在正式開始分析源代碼之前,我們首先需要有一些動态加載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如需轉載請自行聯系原作者
kissazi2