在正式開始分析源代碼之前,我們首先需要有一些動态加載apk的基礎知識。
<a href="http://blog.csdn.net/singwhatiwanna/article/details/22597587">《android apk動态加載機制的研究》</a>
總的說來,為了調用另一個apk中的類,我們就需要用android中提供的classloader,将不屬于宿主apk中的類加載進來。由于android中不允許沒有在androidmanifest中聲明的activity被運作,是以我們需要在androidmanifest中聲明一個代理activity(proxyactivity).這篇文章中的思路是,在插件的activity中将這個proxyactivity傳進去,這樣代碼執行的邏輯是插件activity的,同時插件activity也因為proxyactivity擁有了部分系統資源的通路能力。這裡不是指resource的通路而是context所擁有的通路其他元件、與服務互動的能力。當然,插件activity也存在生命周期函數沒法被系統調用、無法通路resource的問題。
這篇文章解決資源通路的思路是,通過構造resource對象及其依賴的assetmanager,将資源重定向到插件apk,然後override插件中getresource方法。解決生命周期函數無法調用的方法是在proxyactivity的每一個生命周期函數調用的時候同時調用插件activity的對應函數。
這個架構隻需要在如下面截圖中的指定檔案夾(一般是sdcard中的download檔案夾)中放入需要動态加載的apk檔案,選擇對應的圖示就可以實作動态加載了.

1、加載插件資訊
從上面我們看到插件的資訊通過檔案位址dirtext傳入,然後由 plugmgr.loadplugin(new file(dirtext))進行apk資訊的加載,最終将資訊儲存在pluginfo的集合。plugmgr是一個pluginmanager類型的對象,它定義在android_plugmgr類庫中。pluglistviewadapter(繼承自baseadapter)就是一個帶有pluginfo的adatpter而已。
2、點選每一項,加載對應的插件
activityclassgenerator: 動态生成 插件activity子類的工具類
activityoverider :提供公共方法供自動生成的activity調用
frameworkclassloader 架構類加載器(application 的 classloder被替換成此類的執行個體),它主要是對插件、宿主的apk進行分别的處理。
layoutinflaterwrapper :layoutinflater 包裝器,用來替換某些系統布局
pluginactivitylifecyclecallback :插件activity的生命周期方法回調
pluginactivitywrapper :插件activity的包裝類
pluginclassloader :插件類加載器,實作dex檔案生成、加載
plugincontextwrapper :插件context包裝類
pluginfo :插件資訊實體類
pluginmanager :插件管理類,提供給外部初始化插件apk、啟動activity的公共借口。
pluginmanifestutil :插件manifest資訊提取類,除提取manifest資訊外,也包括提取插件apk中lib的類庫)
pluginpackagemanager :這個類庫自定義的packagemanager,對packagemanager做了些包裝
reflectionutils :反射工具類,提供一些常用的反射操作。
xmlmanifestreader : androidmanifest.xml讀取類
從前面的分析中,我們知道要加載插件apk中的資訊,我們需要加載插件apk中的元件(activity、service、brocastreceiver)、用dexclassloader加載dex檔案中資訊、修改resource類的資源指向。要完成以上操作,我們需要讀取插件apk包中的androidmanifest資訊,取出一些必要的内容(不單單是從androidmanifest.xml,還有插件apk本身)。
之前我們忽略了pluginmanager的初始化。它的初始化是在宿主apk的mainactivity中進行的。初始化通過pluginmanager.getinstance()→pluginmanager.init()進行調用。getinstance()所做的就是擷取applicationcontext然後傳給init().
我們來模拟計算機一步步地執行看看。從"先用起來"那一節,我們知道加載類庫會調用androidx.pluginmgr.pluginmanager.loadplugin(...)方法.在這一步裡面主要對後面用的到的資訊進行加載.從代碼裡面不管單個還是多個插件都進入pluginmanager.buildpluginfo(...)。
這段函數的思路還是很清晰的,其中我們最為感興趣的是,加載插件apk究竟需要androidmanifest什麼資訊?可以預想到android四大元件肯定是必須的,權限不是必須的。插件apk的所擁有的權限隻能宿主apk中androidmanifest中的,這是android的安全機制所保證的。進入pluginmanifestutil.setmanifestinfo(...)。
從這個函數中,我們就完成了對插件apk所需要的資訊的加載,需要注意的是,android-plugmgr這版的源代碼暫時隻支援activity,service、receiver都還是不支援的。
從點選主界面點選每一個插件開始,
上面代碼就是插件加載activity的整個過程,然而我們漏掉了插件activity的加載流程,以及特定的activity怎麼被proxyactivity繼承的過程。接下來分析這個類庫中自定義的frameworkclassloader加載特定類的過程。在上面代碼context.startactivity(...)中會對将要start的activity進行加載,也就是調用classloader進行加載,由于我們已經将宿主apk中application的預設classloader替換成了frameworkclassloader,是以在context.startactivity(...)的過程中會調用frameworkclassloader.loadclass(...)。上一個流程中調用了frameworkclassloader.newactivityclassname(...),主要為現在插件apk中activity的加載埋下伏筆。
看來frameworkclassloader也就是對類的加載進行預處理,真正的處理還在pluginclassloader.loadactivityclass(...)。
superclassname = "com.handmark.pulltorefresh.samples.launcheractivity"
targetclassname = "androidx.pluginmgr.pluginactivity"
pluginid = "sample-3.0.0.apk"
pkgname = "com.handmark.pulltorefresh.samples"
讓一個proxyactivity繼承插件apk中特定的activity
聲明字段
對重要的生命周期方法進行聲明,并添加添加activityoverride對應的靜态方法
override通路資源的函數getresource(...)等activity自身要提供的公共接口
我們以declaremethod_oncreate(dexmaker, generatedtype, supertype)進行分析
這段函數所做的事情可以用下面的java代碼表示
我們的分析就到這裡。這個類庫目前也就支援activity、receiver(最新的實驗分支支援)而已,對于service還是不支援的。
<a href="http://blog.csdn.net/luoshengyang/article/details/6703247">android應用程式内部啟動activity過程(startactivity)的源代碼分析</a>
<a href="http://blog.csdn.net/luoshengyang/article/details/6689748">android應用程式啟動過程源代碼分析</a>
<a href="http://my.oschina.net/u/2289564/blog/393252">direct-load-apk啟動插件的原理</a>
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。
轉載:http://www.cnblogs.com/kissazi2/p/4526055.html