1. 程式人生 > >Android技術之家

Android技術之家

引言

先簡單介紹一下Android外掛化。很早之前已經有公司在研究這項技術,淘寶做得比較早,但淘寶的這項技術一直是保密的。直到2015年才陸續出現很多框架,Android外掛化分成很多技術流派,實現的方式都不太一樣。

發展歷史

首先,要記住2012年這個時間點。2012年的時候,就有人做外掛化技術,是大眾點評的屠毅敏,他推出了AndroidDynamicLoader框架,用Fragment來實現。大眾點評是國內做App比較早的公司,他們積累了很多的經驗,尤其是外掛化技術 。通過動態載入不同的Fragement,把想換的頁面都換掉。我們也是在這個專案中第一次看到了如何通過addAssetPath來讀取外掛中的資源。

2013年,出現了23Code。23Code提供了一個殼,在這個殼裡可以動態下載外掛,然後動態執行。可以在殼外編寫各種各樣的控制元件,放在這個框架下去執行。這就是Android外掛化技術。這個專案的作者和開源地址,目前不是很清楚。

2014年初,大家也許看過一個視訊,阿里一位員工做了一次技術分享,專門講淘寶的Altas技術,以及這項技術的大方向。但是很多技術細節沒有分享。

然後是任玉剛的里程碑式的專案。2014年底,玉剛釋出了一個Android外掛化專案,起名為dynamic-load-apk,這跟後續介紹的很多外掛化專案都不太一樣。它沒有Hook太多的系統底層方法,而是從上層,即App應用層解決問題,建立一個繼承自Activity的ProxyActivity類,然後讓外掛中的所有Activity都繼承自ProxyActivity,並重寫Activity所有的方法。之所以說這個專案是里程碑式的,是因為在2015年之前業界沒有太多資料可以參考。

2015年4月,一個新框架推出來,叫OpenAltas,後來改名為ACDD。這個框架參考了淘寶App的很多經驗,主要就是Hook的思想,同時,還首次提出來通過擴充套件AAPT來解決外掛與宿主的資源id衝突的問題。

2015年8月,張勇釋出DroidPlugin。這是Android外掛化中第二個里程碑式的專案,這個專案太牛了,能把任意的App都載入到宿主裡。可以基於這個框架寫一個宿主App,然後就可以把別人寫的App都當作外掛來載入。這個框架的功能的確很強大,但強大的代價就是要改寫很多Android系統的底層程式碼,更別提這哥們還比較懶,沒有制訂任何說明文件,導致技術人員掌握這個框架不太容易。

再之後就是百花齊放的時代了,GitHub上有很多外掛化框架,但這些框架影響都不大,我們這裡就略過了。

接下來登場的是熱修復技術。2015年5月,iOS推出了JSPatch,JSPatch通過Runtime的機制,能迅速修復線上App任何一個類的任何一個方法。而當時的Android系統沒有能迅速替換的方式。於是,在2015年9月,有人找到了實現迅速替換的途徑,就是Andfix,後面會講它的原理。

2015年10月,大眾點評的賈吉鑫做了一個專案,起名為Nuwa(女媧),主要思路跟Andfix差不多,都是解決Android的修復問題,能修復線上的任何一個方法。可惜後來沒有繼續維護。

2015年底,仍然是Android外掛化框架,福建的林廣亮提出了一個新機制——Small框架,這個機制不太一樣的地方就是,通過指令碼的方式來解決資源衝突的問題。

2015 年 8 月,DroidPlugin 是 360 手機助手實現的一種外掛化框架,它可以直接執行第三方的獨立 APK 檔案,完全不需要對 APK 進行修改或安裝。一種新的外掛機制,一種免安裝的執行機制,是一個沙箱(但是不完全的沙箱。就是對於使用者來說,並不知道他會把 apk 怎麼樣), 是模組化的基礎。

2017年 6 月 ,VirtualAPK 是滴滴開源的一套外掛化框架,支援幾乎所有的 Android 特性,四大元件方面。

2017 年 7 月,RePlugin是一套完整的、穩定的、適合全面使用的,佔坑類外掛化方案,由360手機衛士的RePlugin Team研發,也是業內首個提出”全面外掛化“(全面特性、全面相容、全面使用)的方案。

基礎

640?wx_fmt=png

介紹完Android外掛化的歷史,接下來講一講Android外掛化需要的Android系統底層知識。在座的基本都是做Android開發出身,或許有一半到三分之一是資深的,還有的只做了一兩年,希望對外掛化有更深的認識。要想完全明白外掛化技術,首先需要了解Android系統的底層實現。

首先,做Android系統原始碼的人應該非常熟悉Binder,如果沒有它真的寸步難行。Binder涉及兩層技術。你可以認為它是一箇中介者模式,在客戶端和伺服器端之間,Binder就起到中介的作用,這是我這段時間對Binder的思考。要實現四大元件的外掛化,就需要在Binder上做修改。Binder服務端的內容沒辦法修改,只能改客戶端的程式碼。四大元件每個元件的客戶端都不太一樣,這個需要大家自己去發現,時間關係,這裡就不多說了。

學習Binder的最好方式就是AIDL。你可以讀到很多關於AIDL的資料,通過制訂一個aidl檔案自動生成一個Java類,研究一下這個Java類的每個方法和變數,然後再反過來看四大元件,其實都是跟AIDL差不多的方式。

其次,是App打包的流程。程式碼寫完了,執行一次打包操作,中途經歷了資源打包、dex生成、簽名等過程。其中最重要的就是資源的打包,即AAPT這一步,如果宿主和外掛的資源id衝突,一種解決辦法就是在這裡做修改。

第三,App在手機上的安裝流程也很重要。熟悉安裝流程不僅對外掛化有幫助,在遇到安裝bug的時候也非常重要。手機安裝App的時候,經常會有下載異常,提示資源包不能解析,這時需要知道安裝App的這段程式碼在什麼地方,這只是第一步。第二步需要知道,App下載到本地後,具體要做哪些事情。手機有些目錄不能訪問,App下載到本地之後,放到哪個目錄下,然後會生成哪些檔案。外掛化有個增量更新的概念,如何下載一個增量包,從本地具體哪個位置取出一個包,這個包的具體命名規則是什麼,等等。這些細節都必須要清楚明白。

第四,是App的啟動流程。Activity啟動有幾種方式?一種是寫一個startActivity,第二種是點選手機App,通過手機系統裡的Launcher機制,啟動App裡預設的Activity。通常,App開發人員喜聞樂見的方式是第二種。那麼第一種方式的啟動原理是什麼呢?另外,啟動的時候,main函式在哪裡?這個main函式的位置很重要,我們可以對它所在的類做修改,從而實現外掛化。

第五點更重要,做Android外掛化需要控制兩個地方。首先是外掛Dex的載入,如何把外掛Dex中的類載入到記憶體?另外是資源載入的問題。外掛可能是apk也可能是so格式,不管哪一種,都不會生成R.id,從而沒辦法使用。這個問題有好幾種解決方案。一種是是重寫Context的getAsset、getResource之類的方法,偷換概念,讓外掛讀取外掛裡的資源,但缺點就是宿主和外掛的資源id會衝突,需要重寫AAPT。另一種是重寫AMS中儲存的外掛列表,從而讓宿主和外掛分別去載入各自的資源而不會衝突。第三種方法,就是打包後,執行一個指令碼,修改生成包中資源id。

第六點,在實施外掛化後,如何解決不同外掛的開發人員的工作區問題。比如,外掛1和外掛2,需要分別下載哪些程式碼,如何獨立執行?就像機票和火車票,如何只執行自己的外掛,而不執行別人的外掛?這是協同工作的問題。火車票和機票,這兩個Android團隊的各自工作區是不一樣的,這時候就要用到Gradle指令碼了,每個專案分別有各自的倉庫,有各自不同的打包指令碼,只需要把自己的外掛跟宿主專案一起打包執行起來,而不用引入其他外掛,還有更厲害的是,也可以把自己的外掛當作一個App來打包並執行。

上面介紹了外掛化的入門知識,一共六點,每一點都需要花大量時間去理解。否則,在面對外掛化專案的時候,很多地方你會一頭霧水。而只要理解了這六點核心,一切可迎刃而解。

類庫

1.DroidPlugin

是360手機助手在Android系統上實現了一種新的外掛機制

2.Android-Plugin-Framework

此專案是Android外掛開發框架完整原始碼及示例。用來通過動態載入的方式在宿主程式中執行外掛APK。

3.Small

世界那麼大,元件那麼小。Small,做最輕巧的跨平臺外掛化框架。裡面有很詳細的文件

4.dynamic-load-apk

Android 使用動態載入框架DL進行外掛化開發

5.AndroidDynamicLoader

Android 動態載入框架,他不是用代理 Activity 的方式實現而是用 Fragment 以及 Schema 的方式實現

6.DynamicAPK

實現Android App多apk外掛化和動態載入,支援資源分包和熱修復.攜程App的外掛化和動態載入框架.

7.ACDD

非代理Android動態部署框架

8.android-pluginmgr

不需要外掛規範的apk動態載入框架。

9. VirtualAPK

VirtualAPK是滴滴出行自研的一款優秀的外掛化框架。

10.android-pluginmgr

不需要外掛規範的apk動態載入框架。

11.RePlugin

RePlugin是一套完整的、穩定的、適合全面使用的,佔坑類外掛化方案,由360手機衛士的RePlugin Team研發,也是業內首個提出”全面外掛化“(全面特性、全面相容、全面使用)的方案。

640?wx_fmt=png

主流框架

在 Android 中實現外掛化框架,需要解決的問題主要如下:

資源和程式碼的載入

Android 生命週期的管理和元件的註冊

宿主 APK 和外掛 APK 資源引用的衝突解決

下面分析幾個目前主流的開源框架,看看每個框架具體實現思路和優缺點。

DL 動態載入框架 ( 2014 年底)

GItHub:https://github.com/singwhatiwanna/dynamic-load-apk

DL支援的功能

1、plugin無需安裝即可由宿主調起。

2、支援用R訪問plugin資源

3、plugin支援Activity和FragmentActivity(未來還將支援其他元件)

4、基本無反射呼叫

5、外掛安裝後仍可獨立執行從而便於除錯

6、支援3種plugin對host的呼叫模式:

(1)無呼叫(但仍然可以用反射呼叫)。

(2)部分呼叫,host可公開部分介面供plugin呼叫。 這前兩種模式適用於plugin開發者無法獲得host程式碼的情況。

(3)完全呼叫,plugin可以完全呼叫host內容。這種模式適用於plugin開發者能獲得host程式碼的情況。

7、只需引入DL的一個jar包即可高效開發外掛,DL的工作過程對開發者完全透明

8、支援android2.x版本

DL框架原理

動態載入主要有兩個需要解決的複雜問題:資源的訪問和activity生命週期的管理,除此之外,還有很多坑爹的小問題,而DL框架很好地解決了這些問題。需要說明的一點是,我們不可能調起任何一個未安裝的apk,這在技術上是很難實現的,我們調起的apk必須受某種規範的約束,只有在這種約束下開發的apk,我們才能將其調起。

DroidPlugin ( 2015 年 8 月)

Github:https://github.com/DroidPluginTeam/DroidPlugin

DroidPlugin 是 360 手機助手實現的一種外掛化框架,它可以直接執行第三方的獨立 APK 檔案,完全不需要對 APK 進行修改或安裝。一種新的外掛機制,一種免安裝的執行機制,是一個沙箱(但是不完全的沙箱。就是對於使用者來說,並不知道他會把 apk 怎麼樣), 是模組化的基礎。

DroidPlugin 外掛機制 :它可以在無需安裝、修改的情況下執行APK檔案,此機制對改進大型APP的架構,實現多團隊協作開發具有一定的好處。

專案新地址:DroidPlugin

定義:

HOST程式:外掛的宿主。

外掛:免安裝執行的APK

限制和缺陷:

無法在外掛中傳送具有自定義資源的Notification,例如:

a. 帶自定義RemoteLayout的Notification

b. 圖示通過R.drawable.XXX指定的通知(外掛系統會自動將其轉化為Bitmap)

無法在外掛中註冊一些具有特殊Intent Filter的Service、Activity、BroadcastReceiver、ContentProvider等元件以供Android系統、已經安裝的其他APP呼叫。

缺乏對Native層的Hook,對某些帶native程式碼的apk支援不好,可能無法執行。比如一部分遊戲無法當作外掛執行。

特點:

支援Androd 2.3以上系統

外掛APK完全不需做任何修改,可以獨立安裝執行、也可以做外掛執行。要以外掛模式執行某個APK,你無需重新編譯、無需知道其原始碼。

外掛的四大元件完全不需要在Host程式中註冊,支援Service、Activity、BroadcastReceiver、ContentProvider四大元件

外掛之間、Host程式與外掛之間會互相認為對方已經”安裝”在系統上了。

API低侵入性:極少的API。HOST程式只是需要一行程式碼即可整合Droid Plugin

超強隔離:外掛之間、外掛與Host之間完全的程式碼級別的隔離:不能互相呼叫對方的程式碼。通訊只能使用Android系統級別的通訊方法。

支援所有系統API

資源完全隔離:外掛之間、與Host之間實現了資源完全隔離,不會出現資源竄用的情況。

實現了程序管理,外掛的空程序會被及時回收,佔用記憶體低。

外掛的靜態廣播會被當作動態處理,如果外掛沒有執行(即沒有外掛程序執行),其靜態廣播也永遠不會被觸發。

Small ( 2015 年底)

Github:https://github.com/wequick/Small

官網:http://code.wequick.net/Small

Small 是一種實現輕巧的跨平臺外掛化框架,基於“輕量、透明、極小化、跨平臺”的理念

640?wx_fmt=png

優點如下:

1.所有外掛支援內建宿主包中。

2.外掛的編碼和資原始檔的使用與普通開發應用沒有差別。

3.通過設定 URI ,宿主以及 Native 應用外掛,Web 外掛,線上網頁等能夠方便進行通訊。

4.支援 Android 、 iOS 、和 Html5 ,三者可以通過同一套 Javascript 介面實現通訊。

缺點如下:

暫不支援 Service 的動態註冊,不過這個可以通過將 Service 預先註冊在宿主的 AndroidManifest.xml 檔案中進行規避,因為 Service 的更新頻率通常非常低。

VirtualAPK(2017年 6 月 )

VirtualAPK 是滴滴開源的一套外掛化框架,支援幾乎所有的 Android 特性,四大元件方面。

原理:

VirtualAPK 對外掛沒有額外的約束,原生的 apk 即可作為外掛。外掛工程編譯生成 apk後,即可通過宿主 App 載入,每個外掛 apk 被載入後,都會在宿主中建立一個單獨的 LoadedPlugin 物件。如下圖所示,通過這些 LoadedPlugin 物件,VirtualAPK 就可以管理外掛並賦予外掛新的意義,使其可以像手機中安裝過的 App 一樣執行。

合併宿主和外掛的ClassLoader 需要注意的是,外掛中的類不可以和宿主重複

合併外掛和宿主的資源 重設外掛資源的 packageId,將外掛資源和宿主資源合併

去除外掛包對宿主的引用 構建時通過 Gradle 外掛去除外掛對宿主的程式碼以及資源的引用

特性如下:

四大元件均不需要在宿主manifest中預註冊,每個元件都有完整的生命週期。

1.Activity:支援顯示和隱式呼叫,支援Activity的theme和LaunchMode,支援透明主題;

2.Service:支援顯示和隱式呼叫,支援Service的start、stop、bind和unbind,並支援跨程序bind外掛中的Service;

3.Receiver:支援靜態註冊和動態註冊的Receiver;

4.ContentProvider:支援provider的所有操作,包括CRUD和call方法等,支援跨程序訪問外掛中的Provider。

5.自定義View:支援自定義 View,支援自定義屬性和style,支援動畫;

6.PendingIntent:支援PendingIntent以及和其相關的Alarm、Notification和AppWidget;

7.支援外掛Application以及外掛manifest中的meta-data;

8.支援外掛中的so。

優秀的相容性

相容市面上幾乎所有的Android手機,這一點已經在滴滴出行客戶端中得到驗證。

資源方面適配小米、Vivo、Nubia 等,對未知機型採用自適應適配方案。

極少的 Binder Hook,目前僅僅 hook了兩個Binder:AMS和IContentProvider,hook 過程做了充分的相容性適配。

外掛執行邏輯和宿主隔離,確保框架的任何問題都不會影響宿主的正常執行。

RePlugin(2017 年 7 月)

GitHub:https://github.com/Qihoo360/RePlugin

RePlugin是一套完整的、穩定的、適合全面使用的,佔坑類外掛化方案,由360手機衛士的RePlugin Team研發,也是業內首個提出”全面外掛化“(全面特性、全面相容、全面使用)的方案。

其主要優勢有:

極其靈活:主程式無需升級(無需在Manifest中預埋元件),即可支援新增的四大元件,甚至全新的外掛

非常穩定:Hook點僅有一處(ClassLoader),無任何Binder Hook!如此可做到其崩潰率僅為“萬分之一”,並完美相容市面上近乎所有的Android ROM

特性豐富:支援近乎所有在“單品”開發時的特性。包括靜態Receiver、Task-Affinity坑位、自定義Theme、程序坑位、AppCompat、DataBinding等

易於整合:無論外掛還是主程式,只需“數行”就能完成接入

管理成熟:擁有成熟穩定的“外掛管理方案”,支援外掛安裝、升級、解除安裝、版本管理,甚至包括程序通訊、協議版本、安全校驗等

數億支撐:有360手機衛士龐大的數億使用者做支撐,三年多的殘酷驗證,確保App用到的方案是最穩定、最適合使用的

截止2017年6月底,RePlugin的:

特性描述

外掛數103(核心57個)

外掛佔應用比高達83%

年發版次數高達596次(工作日均2次)

崩潰率萬分之一(0.01%),極低

時間2014年應用,3年驗證

目前360公司幾乎所有的億級使用者量的APP,以及多款主流第三方APP,都採用了RePlugin方案。

有關RePlugin的詳細介紹,請點選這裡閱讀《RePlugin 官方 WiKi》。

特性

特性描述

元件四大元件(含靜態Receiver)

升級無需改主程式Manifest完美支援

Android特性支援近乎所有(包括SO庫等)

TaskAffinity & 多程序支援(坑位方案)**

外掛型別支援自帶外掛(自識別)、外接外掛**

外掛間耦合支援Binder、Class Loader、資源等

程序間通訊支援同步、非同步、Binder、廣播等

自定義Theme & AppComat支援

DataBinding支援

安全校驗支援

資源方案獨立資源 + Context傳遞(相對穩定)

Android 版本API Level 9+ (2.3及以上)

參考文章

APK動態載入框架(DL)解析

Android外掛化從入門到放棄-最強合集

包建強的無線技術空間,寫給Android App 開發人員看的 Android 底層知識 置頂8篇

有關Android外掛化思考

Android外掛化原理解析

Android外掛化:從入門到放棄

Android部落格週刊專題之-外掛化開發

                        喜歡 就關注吧,歡迎投稿!

640?wx_fmt=jpeg