Android 外掛化技術 載入任意未安裝apk
(一) 綜述 隨著智慧手機硬體效能的逐步提升,移動應用也做的越來越複雜,android平臺上應用的apk包體積也越來越大,然後同類產品開始比拼誰的體積小,實現方案呢,然後很容易想到"外掛化",也就是說可以釋出核心很小的產品,隨著新增功能的需求而動態下載功能模組,促使外掛化的另一個動機是App應用固有的問題,那就是很多元件需要註冊,更新功能的話不能像Web應用那樣可在使用者無察覺的情況下通過升級伺服器而方便升級,只能彈出個框讓使用者重新下載整個程式包,然後調取系統安裝流程。
被載入的apk稱之為外掛,因為機制類似於生物學的"寄生",載入了外掛的應用也被稱為宿主。
往往不是所有的apk都可作為外掛被載入,往往需要遵循一定的"開發規範",還需要外掛專案引入某種api類庫,業界通常都是這麼做的。
這裡介紹一種無須規範限制的動態載入解決方案,外掛不需要依賴任何API,這也是本人突發異想,靈感所致。
(二)功能介紹 特點:
- 外掛為普通apk,無須依賴任何jar
- Activity生命週期由系統自己管理
- 使用簡單,只需要瞭解一個類PluginManager的兩個方法
- 啟動Activity的效率高
- 不修改外掛,被載入的外掛仍然可以獨立安裝。
功能點:
- 可載入任意apk中的 Activity (包括子類 ActionBarActivity 、FragmentActivity)的派生類(不包括違反限制條件的Activity)
- 支援外掛自定義Application
- 支援外掛Apk中的Activity跳轉到別的Activity(外掛內部的或系統的,外部已安裝apk的,甚至是別的外掛中的),也沒有任何限制
- 支援Activity設定主題(與系統的主題應用規則一樣,如果Activity沒指定Theme,但所在Application指定了Theme,則使用Application的Theme)
- 初步支援.so
- 支援外掛使用 SharedPreference 或 SQLite資料庫(尚未完善)
(ps:第一個外掛程式碼來自
https://github.com/viacheslavtitov/NDKBegining作者是個老外,不過也比較粗心,要正常執行你需要在sd卡下建立目錄:FFMPEG第二個外掛程式碼來自這篇博文:http://blog.csdn.net/caihanyuan/article/details/7367351
7個外掛程式碼是自測專案,分別測試ActionBarActivity和Activity基本載入和跳轉
其他apk還沒能正常載入,框架還在不斷完善中,不過騰訊的開心消消樂可以幫助記錄crashlog,這點真不錯~
將要支援的特性:
PackageManager service 等等,詳情都列在開源專案android-pluginmgr
https://github.com/houkx/android ... t/android-pluginmgr下的TODO檔案中
(ps:修正專案主頁README描述的限制條件1,目前已經沒有這個限制了,在外掛中呼叫context.getPackageName()返回外掛的清單檔案中宣告的包名)
限制條件(永不支援的):
- 外掛apk中不能假定自己已經安裝,以及由此造成的影響,比如認為applicationInfo.dataDir==/data/data/packageName
- 不能依賴清單檔案中的程序宣告,被載入的apk以及裡面的任何元件目前都在同一個程序管理。
- 外掛中的許可權,無法動態註冊,外掛中的許可權都得在宿主中註冊(暫無解決方案)
(三) 實現 動態載入需要處理很多問題,雖然有很多問題,但是核心問題就是載入Activity,因為Activity是可見的,人們對可以看到的東西總是那麼重視,視覺資訊占人所處理資訊的90%以上。
Activity如何調起來?資源的載入等等已經有大牛的文章介紹汗牛充棟了,我本菜鳥,不再贅述。
目前Activity的載入或許有很多處理方式,但是可以分為兩種:一是自己new 二是系統new 。很多動態載入框架基於第一種方式。我這個方案基於第二種
,既然要系統new,就要系統自己可以找到相應的Activity. 由於Activity需要在清單檔案註冊了才能使用,所以要註冊Activity,但是如何註冊呢?
我在網上看到有人用極端的方式:外掛裡的所有Activiy都在宿主裡註冊,既然宿主總要修改升級,何必要外掛呢,這已經違背了動態載入的初衷:不修改框架而動態擴充套件功能更多的是這麼做,註冊一個Activity基類,供外掛中的Activity繼承,在這個基類裡做動態載入的核心邏輯,這就要求外掛必須依賴某種API類庫。
我的方案通俗的說是這樣,依賴倒轉,不讓外掛依賴框架API,而是反過來,自動生成一個Activity類依賴(繼承)外掛中的Activity,這個自動生成的類就叫PluginActivity
並且宣告在框架的清單檔案中,如下:
< activity name="androidx.pluginmgr.PluginActivity" />
聰明的讀者會想,等一下,外掛裡面Activity可不止一個,你就註冊一個?
是的,就一個,自動生成的Activity類名都是androidx.pluginmgr.PluginActivity,不過放在不同的檔案中,最簡單的對映,原始Activity類名.dex檔案中儲存對應的子類:PluginActivity
其實也是偷樑換柱了,如果你想啟動外掛裡的Activity,如com.test.MyPlugActivity, 我就把啟動目標修改為androidx.pluginmgr.PluginActivity類,
然後從com.test.MyPlugActivity.dex檔案中找到 public class androidx.pluginmgr.PluginActivity extends com.test.MyPlugActivity{....}
以啟動SthActivity為例:
好了,核心思想已經表達清楚了,下面介紹如何讓系統按你說的路徑去找類檔案,這涉及到類載入器。自定義類載入器比較簡單,繼承java.lang.ClassLoader即可.
在我的開源專案原始碼中對應的類是 FrameworkClassLoader, PluginManager初始化時就去修改Application的類載入器,替換為 FrameworkClassLoader.
FrameworkClassLoader 其實不幹什麼實際載入工作,只是分發任務:
public Class loadClass(String className){
if(當前上下文外掛不為空) {
if( className 是 PluginActivity){
找到當前實際要載入的原始 Activity
return 使用外掛對應的 ActivityClassLoader 從 (自動生成的)原始Activity類名.dex 檔案 載入PluginActivity
}else{
return 使用對應的 PluginClassLoader 載入普通類
}
}else{
return super.loadClass()//即委派給宿主Application的原始類載入器載入
}
}
其中, PluginClassLoader 是一個DexClassLoader, parent 指向 FrameworkClassLoader,
ActivityClassLoader 也是一個DexClassLoader, parent 指向 PluginClassLoader
package androidx.pluginmgr;import android.util.Log;/** * 框架類載入器(Application 的 classLoder被替換成此類的例項) * * */class FrameworkClassLoader extends ClassLoader { private String[] plugIdAndActname;//代表外掛上下文 public FrameworkClassLoader(ClassLoader parent)
{ super(parent); } //在外部或外掛內部的 startActivity 時呼叫這個方法設定外掛上下文 String newActivityClassName(String plugId, String actName) { plugIdAndActname = new String[] { plugId, actName }; return ActivityOverider.targetClassName;//targetClassName即宿主manifest配置的androidx.pluginmgr.PluginActivity
} protected Class<?> loadClass(String className, boolean resolv) throws ClassNotFoundException { Log.i("cl", "loadClass: " + className); String[] plugIdAndActname = this.plugIdAndActname;
Log.i("cl", "plugIdAndActname = " + java.util.Arrays.toString(plugIdAndActname)); if (plugIdAndActname != null) { String pluginId = plugIdAndActname[0]; PlugInfo
plugin = PluginManager.getInstance().getPluginById( pluginId); Log.i("cl", "plugin = " + plugin); if (plugin != null) { try {
if (className.equals(ActivityOverider.targetClassName)) { String actClassName = plugIdAndActname[1];//被(繼承)代理的Activity類名 return plugin.getClassLoader().loadActivityClass(
actClassName);// 載入動態生成的Activity類 }else{ return plugin.getClassLoader().loadClass(className);//載入普通類
} } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
return super.loadClass(className, resolv); }}
到此為止,一個動態載入框架的核心雛形已經有了,但是還有許多細節待完善。詳情請見原始碼
相關推薦
Android 外掛化技術 載入任意未安裝apk
轉載 http://www.eoeandroid.com/thread-562805-1-1.html (一) 綜述 隨著智慧手機硬體效能的逐步提升,移動應用也做的越來越複雜,android平臺上應用的apk包體積也越來越大,然後同類產品開始比拼誰的
Android外掛化技術簡介
https://blog.csdn.net/io_field/article/details/79084630 可以通過反射 事先定義統一介面的方式,訪問外掛中的類和方法 還可以在AndroidManifest.xml中動態註冊元件Activity、Service、BroadcastReceiver、
Android外掛化技術之旅 1 開篇 - 實現啟動外掛與呼叫外掛中的Activity和Service
前言 Android技術如今已很成熟了,元件化、外掛化、熱修復等等框架層出不窮,如果只停留在單純的會用框架上,技術永遠得不到成長,只有懂得其原理,能夠婉婉道來,能夠自己手動寫出,技術才會得到成長,與其焦慮未來,不如把握現在。本篇將手寫教大家寫出外掛化框架,外掛化技術是Android高階工程師必備的技術之一,
《Android外掛化技術——原理篇》
| 導語 外掛化技術最早從2012年誕生至今,已經走過了5個年頭。從最初只支援Activity的動態載入發展到可以完全模擬app執行時的沙箱系統,各種開源專案層出不窮,在此挑選了幾個代表性的框架,總結其中的技術原理。由於本人水平有限,外掛化框架又相當複雜,文中若有錯誤或者不準
Android外掛技術——(三)載入未安裝apk
上一篇我們介紹了載入已安裝apk,本篇將介紹載入未安裝apk。 未安裝apk由於系統毫不知情,因此無法通過系統api獲取其上下文,自然也就無法獲取其資源。接下來,我們將另闢蹊徑來解決這個問題。 步驟如下: 一、採用上一篇中的Android Host工程,仍
外掛化載入未安裝APK
主程式專門開一個PluginActivity,在該Activity裡通過dexClassLoader動態載入apk,通過反射的方式向被載入apk的mainActivity裡傳遞PluginAvtivity這個引數,相當於在主程式的PluginActivity裡畫Apk中A
Android外掛化基礎之載入已安裝的apk資源
郵箱:[email protected] 我也是在進行學習和研究,有問題可以直接說 應該明確的問題 外掛化是什麼意思? 為什麼要使用外掛化的這種方式? 外掛化的優劣? 根據上述問題我們就可以進行初步的瞭解了 外掛顧名思義就是
Android外掛化框架和熱修復技術的資料收集和彙總
外掛化框架 一個APP功能的堆疊和業務的蓬勃發展,導致APP越來越龐大和臃腫,每一個APP都有一顆超級APP的理想和成為系統第二的願望,如何減少APP的釋出成本和更新成本,外掛化的方式是一條不錯的捷徑。 外掛化的介紹與原理 開源的外掛化框架
Android外掛化架構設計之載入資原始檔
開篇介紹 現在專案比較大 資源比較多,但是若希望動態來載入資原始檔,可以有以下幾種方式: 1. 通過下載資原始檔zip包然後解壓來載入 2. 通過外掛開發 本文通過外掛開發來實現載入外掛中的資原始檔. 程式演示 也可以開啟連結 效果演示 開
Android外掛化完美實現程式碼資源載入及原理講解 附可執行demo
*本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出 。 我們通過前4篇的分解,分別將外掛化設計到的知識點全部梳理了一遍,如果沒有看過的,建議先看前面4篇 6. 外掛化資源的使用及動態載入 附demo 好了上面介紹了之
Android外掛化原理和實踐 (三) 之 載入外掛中的元件程式碼
我們在上一篇文章《Android外掛化原理和實踐 (二) 之 載入外掛中的類程式碼》中埋下了一個懸念,那就是通過構造一個DexClassLoader物件後使用反射只能反射出普通的類,而不能正常使用四大元件,因為會報出異常。今天我們就來解開這個懸念和提出解決方法。 1 揭開懸念 還記得《A
Android外掛化原理和實踐 (二) 之 載入外掛中的類程式碼
我們在上一篇文章《Android外掛化原理和實踐 (一)之 外掛化簡介和基本原理簡述》中介紹了外掛化一些基本知識和歷史,最後還列出了三個根本問題。接下來我們打算圍繞著這三個根本問題展開對外掛化的學習。首先本章將介紹第一個根本問題:宿主和外掛中如何相互呼叫程式碼。要實現它們相互呼叫,就得要宿主先將
Android外掛化探索(二)資源載入
前情提要 PathClassLoader和DexClassLoader的區別 DexClassLoader的原始碼如下: public class DexClassLoader extends BaseDexClassLoader {
Android Plugin 外掛化技術-Small外掛框架
本篇文章只是整理了一些流行的開源外掛化技術,其中言論純屬開源作者,不代表本人觀點。 完美內建 所有外掛支援內置於宿主包中高度透明 外掛編碼、佈局編寫方式與獨立應用開發無異外掛程式碼除錯與整包開發無
Android外掛化資源的使用及動態載入 附demo
上一篇我們已經完成了一個真正可執行的外掛化demo,而且demo中也解決了外掛中不可以使用資源的問題,但是由於篇幅的問題我們並沒有對原理講解,所以這一篇是對上一篇的一個收尾,如果沒有看過上一篇建議先看Android外掛化完美實現程式碼資源載入及原理講解 附可執行
Android外掛化開發 第三篇 [載入外掛資源]
引言 本文講解宿主如何從外掛apk中獲取到資源,為啥要從外掛中獲取資源呢?這種需求可能來自於顯示外掛的名字啊,圖示之類的。比如宿主的一個按鍵上顯示“掃一掃”或者"搖一搖"之類的,這個字串是外掛提供的。 Demo建立 引入外掛的AssetManager private sta
Android外掛化原理解析--外掛化載入機制
上文 Activity生命週期管理 中我們地完成了『啟動沒有在AndroidManifest.xml中顯式宣告的Activity』的任務;通過Hook AMS和攔截ActivityThread中H類對於元件排程我們成功地繞過了AndroidMAnifest.xml的限制。但是
Android 外掛化原理解析——外掛載入機制
上文 Activity生命週期管理 中我們地完成了『啟動沒有在AndroidManifest.xml中顯式宣告的Activity』的任務;通過Hook AMS和攔截ActivityThread中H類對於元件排程我們成功地繞過了AndroidMAnifest.xml的限
Android外掛化學習之路(一)之動態載入綜述
前段時間,公司專案完成了外掛化的開發,自己也因此學習了很多Android外掛化的知識,於是想把這些內容記錄下來,本次帶來Android外掛化的第一篇:動態載入綜述 背景知識 1.什麼是動態載入? 動態載入技術應由以下幾個部分組成: 1) 應用在執行
Android外掛化探索(四)免安裝執行Activity(下)
在上一篇中,我們介紹了兩種免安裝啟動Activity的方法。但是那兩種方法都有缺陷,必須在AndroidManifest.xml中註冊。那麼今天,我們來探索其它幾種不需要在清單檔案中註冊的啟動方式。 靜態代理啟動activity 通過前幾篇的探索我們