1. 程式人生 > >Android 外掛化技術 載入任意未安裝apk

Android 外掛化技術 載入任意未安裝apk

轉載     http://www.eoeandroid.com/thread-562805-1-1.html 

(一) 綜述    隨著智慧手機硬體效能的逐步提升,移動應用也做的越來越複雜,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

第三個外掛程式碼來自大名鼎鼎的 PullToRefresh :https://github.com/johannilsson/android-pulltorefresh第6第

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


  插圖2(類載入器結構圖):


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 通過前幾篇的探索我們