漫談Android元件化及Web化

IT大咖說發表於2018-07-08

漫談Android元件化及Web化

內容來源:2018 年 04 月 14 日,高階Android工程師陳家偉在“2018網際網路開發者大會”進行《漫談Android元件化及Web化》演講分享。IT 大咖說(微信id:itdakashuo)作為獨家視訊合作方,經主辦方和講者審閱授權釋出。

閱讀字數:3326 | 9分鐘閱讀

嘉賓演講視訊及PPT:t.cn/Rr62oSm

摘要

本次分享主要講述Android元件化和Android web化的原理與實踐。

Android動態化介紹

動態化演進

安卓的動態化主要包含三個部分,分別是元件化、外掛化、模組化。模組化很容易理解,指的是為了解耦將某一個功能拆分成獨立的模組,最常見的模組有網路模組和下載模組。外掛化和元件化的概念就比較模糊,不同的框架所做的定義都不一樣,它們之間的邊界也不太明顯。

漫談Android元件化及Web化

上圖是某App對外掛化和元件化的理解圖示,左面表示的是元件化,右邊表示的是外掛化。元件化的機器人是由多個元件構成,外掛化的機器人是一個整體可以進行分發。

這張示意圖乍看沒什麼問題,但是其實還是存在漏洞,比如當元件化的機器人某一部分變的足夠大的時候,該部分其實可以脫離出來成為新的機器人,而當外掛化機器人功能越來越弱小的時候也可以演變從一個元件。總的來說元件化和外掛化的邊界並不是很明顯,只是根據站的角度和處理問題的方法不同而產生的概念性上的定義。

Android動態化需要解決的問題

Android動態化需要解決4個問題,分別是Dex載入、資源載入、SO載入、四大元件載入。下文將介紹這四個問題所涉及的安卓的具體部分。

Dex是安卓編譯後的產物,Java會被編譯成class,安卓則對這些class檔案進行壓縮處理得到一個Dex。安卓的資源比較多,有圖片、佈局檔案、動畫等。SO是安卓的動態連結庫,一般由C或者C++寫成。安卓的四大元件Activity,Service,Content Provider,BroadcastReceiver必須在AndroidManifest.xml配置檔案中宣告才能夠正常載入。

主流動態化框架

目前主流的動態化框架有Atlas、RePlugin、DroidPlugin、VirtualAPK,除開Atlas將自己定義為元件化框架外,其他三個都將自己定義為外掛化框架。根據個人的觀察發現,他們主要的區別在於對安卓的四大元件的處理上,Atlas是先定義這些元件再通過打包的方式處理。但是去年Atlas也做了一些外掛化的處理,這使得目前的這四個框架都涉及到了外掛化。

元件化和外掛化

相信大家都經常遇到產品的某些需求要緊急上線的情況,但是App不同於H5開發那樣可以隨時發版,需要經過眾多的渠道進行釋出,而如果能夠做到動態發版,對整個產品的演進和動態開發都會有比較好的推進作用。

另外減少包體積同樣也很重要,一般同個App,iOS的包體積會比Android的更大,這是由於iOS無法進行原生程式碼的動態下發,而國內的安卓渠道稽核相對比較鬆一些。還有一個需要關注的是熱修復,它可以讓我們即時的修復線上的BUG。

上文提到的這三點其實就是元件化和外掛化共同目的,只不過他們在實現手段上有所不同。一般元件是和主工程一起打包,外掛則可以獨立打包、另外元件需要藉助打包完成更多工作

動態載入原理

動態載入App思路之類載入

漫談Android元件化及Web化

前面提到過外掛化要解決的其中一個問題就是Dex載入。在Java中可以通過ClassLoader載入class檔案,安卓方面則提供了BaseDexClassLoader。BaseDexClassLoader內部有很多DexFile,它是Dex的檔案描述,要想實現類載入,可以直接將外掛的DexFile前插到BaseDexClassLoader。這種方式就是單類載入器。

漫談Android元件化及Web化

安卓中系統類由BootClassLoader載入,PathClassLoader繼承自BootClassLoader,載入的是App類。Altlas為了實現類載入,將PathClassLoader替換為了自己的ClassLoader——DelegateClassLoader,這時所有類的載入都會經過DelegateClassLoader,且每個外掛都由獨立的PluginClassLoader載入,這些類的查詢則由DelegateClassLoader完成。這種方式是多類載入器。

動態載入App思路之資源載入

漫談Android元件化及Web化

安卓在打包的時候會為每個資源分配一個32位Int型的ID,採用16進製表示。0x後面是類似PPTTEEEE的形式,TT代表類別,EEEE代表條目,安卓中所有打包資源ID的PP都是7F。

安卓中的資源載入有兩種方式,第一種是資源隔離。指的是每個外掛由不同的Resources物件載入資源(安卓中通過Resources物件獲取資源),這是為了避免由於資源ID相同造成的資源衝突問題。

第二個資源載入方式是資源分割槽,它通過修改安卓的打包工具,使得可以變更資源ID的PP,已達到避免ID重複的目的。

對比這兩種方式可以發現,資源隔離的好處在於不需要修改打包工具, 畢竟打包工具是使用C++寫的,維護起來也比較麻煩(aapt2已經支援資源分割槽)。資源分割槽的優勢在於能夠資源共用,因為它可以共用一個Resources物件,同時還可以避免資源衝突。

動態載入App之四大元件載入

四大元件的載入同樣有兩種方式。一種是通過合併manifest資訊方式,比如手動拷貝或者打包,將外掛Menifest資訊合併入主APP。另一種是事先宣告空的四大元件,再通過Hock掉系統的入口來啟動四大元件。

Google玩轉動態化

雖然動態框架在國內很流行,但國外對此卻不是很熱衷,他們更多的還是使用React Native。

國內的動態框架主要是研究如何通過反射呼叫或者Hock掉系統API來達到目的,不過系統API的呼叫其實存在著風險,因為每個版本的私有API的變動都是挺大的。為此Google也提供了一種動態框架——Instant,它通過Google Play Service載入,即有外掛化也有元件化的特點,通過aapt2來完成資源分割槽,對於四大元件的載入採用預埋、代理的方式啟動Activity service。

Web化介紹

一般App的活動頁都是使用H5開發,因為H5可以進行動態更新。但是H5體驗上還是不如Native,在動畫以及一些高階功能方面也不夠強。

而元件化也存在著問題,在最新發布的Android P版本中限制了對私有API的訪問,一旦訪問私有API 應用就會崩潰。雖然可以通過某些技術手段攻克這一限制,但是其實還有另一種方式——SPA(單頁面應用)。 對於Web端的SPA,它只有一個HTML檔案,然後通過JS渲染,以達到在一個HTML的進行頁面跳轉的目的。

下面來看下Android中的web化。

首先是React Native。React Native中每個頁面都是一個View,且都在Activity中,它通過控制View的切換來進行頁面跳轉。

Android提供了一種佈局容器——Fragment,Activity可以承載很多Fragment,通過切換Fragment也可以達到頁面切換的效果。這就是Android Native的web化。

Android web核心原理

Android Native web實現的核心是多類載入器、資源隔離以及context替換。

因為要保證命名和混淆規則不能出現同一個類名,所以無法使用單類載入器。多類載入器由於採用不同ClassLoader載入外掛,因此不用顧慮命名是否重複。

漫談Android元件化及Web化

Context替換指的是將Fragment中的Context替換成我們自定義的Context。Fragment中所有的類和資源都是通過Context訪問,而通過自定義Context就能達到動態載入Activity外部外掛的目的。


相關文章