Android應(yīng)用程序插件化研究之AssetManager

文章首發(fā):Android應(yīng)用程序插件化研究之AssetManager|大利貓



最近在研究Android應(yīng)用的插件化開發(fā),看了好幾個相關(guān)的開源項目憋槐。插件化都是在解決以下幾個問題:

  • 如何把插件apk中的代碼和資源加載到當(dāng)前虛擬機(jī)淑趾。
  • 如何把插件apk中的四大組件注冊到進(jìn)程中。
  • 如何防止插件apk中的資源和宿主apk中的資源引用沖突近范。

就這幾個問題评矩,我開始研究插件化開發(fā)實現(xiàn)的相關(guān)技術(shù)阱飘。在上篇文章中我講了如何把插件apk中的class加載到當(dāng)前進(jìn)的問題虱颗,本篇文章主要講第一點的第二點:如何加載另一個apk中的資源到當(dāng)前應(yīng)用中忘渔。

AssetManager介紹

當(dāng)我們在組件中獲取資源時使用getResource獲得Resource對象畦粮,通過這個對象我們可以訪問相關(guān)資源乖阵,比如文本、圖片拉背、顏色等默终。通過跟蹤源碼發(fā)現(xiàn),其實 getResource 方法是Context的一個抽象方法两疚, getResource的實現(xiàn)是在ContextImp中實現(xiàn)的诱渤。獲取的Resource對象是應(yīng)用的全局變量谈况,然后繼續(xù)跟蹤源碼,發(fā)現(xiàn) Resource 中有一個AssetManager的全局變量赡茸,在Resource的構(gòu)造函數(shù)中傳入的祝闻,所以最終獲取資源都是通過 AssetManager 獲取的联喘,于是我們把注意力放到AssetManager上。我們要解決下面兩個問題:

  • 如何獲取 AssetManager 對象叭喜。
  • 如何通過 AssetManager 對象獲取插件中apk的資源堤框。

通過對 AssetManager 的相關(guān)源碼跟蹤纵柿,我們找到答案:

  • AssetManager 的構(gòu)造函數(shù)沒有對 api 公開昂儒,不能使用 new 創(chuàng)建渊跋;context .getAssets() 可用獲取當(dāng)前上下文環(huán)境的 AssetManager着倾;利用反射 AssetManager.class.newInstance() 這樣可用獲取對象。
  • 如何獲取插件 apk 中的資源蒿囤。我們發(fā)現(xiàn) AssetManager 中有個重要的方法崇决。
/** Add an additional set of assets to the asset manager. 
* This     can be either a directory or ZIP file.
* Not for use by applications. Returns the cookie of the added asset, 
* or 0 on failure.
*@{hide}
 */
public native final int addAssetPath(String path);

我們可以把一個包含資源的文件包添加到assets中恒傻。這就是AssetManager查找資源的第一個路徑。這個方法是一個隱藏方法睁枕,我們可以通過反射調(diào)用外遇。

AssetManager assetManager =     AssetManager.class.newInstance() ; // context .getAssets()罐氨?
AssetManager.class.getDeclaredMethod("addAssetPath", String.class).invoke(assetManager, apkPath);

上文提到,我們可以獲取當(dāng)前上下文的 AssetManager,也可以通過反射創(chuàng)建一個 AssetManager玩徊。我們這里本文分析的是后一種。第一種能不能呢泣棋,這個問題留給讀者先去思考潭辈,后續(xù)文章會單獨討論。 詳細(xì)了解可以參考老羅的文章《Android應(yīng)用程序資源管理器(Asset Manager)的創(chuàng)建過程分析》把敢。下面我們來寫一個demo:獲取插件的文本資源和圖片資源。

創(chuàng)建一個插件apk工程module:apkbeloaded

我把插件的包名命名為laodresource.demo.com.loadresourcedemo婶恼。

第一步:

這個工程中我們可以不用寫任何代碼柏副。在drawable目錄下放一張圖片:icon_be_load.png。

在string中定義字符串:<string name="text_beload">I am from apkBeLoaded</string>眷篇。

第二步:

打包生成apk:apkbeloaded-debug.apk荔泳。

拷貝到測試機(jī)文件路徑下:$ adb push <你的路徑>/apkbeloaded-debug.apk sdcard/

創(chuàng)建一個宿主apk工程

在布局文件中定義一個文本控件和一個圖片控件,分別用來顯示插件中獲取的文本和圖片椎椰。

<ImageView android:layout_width="wrap_content"
       android:src="@mipmap/ic_launcher"
       android:id="@+id/icon"
       android:layout_height="wrap_content"/>
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/text"
    android:text="Hello World!"
    android:layout_below="@+id/icon"
    android:layout_centerInParent="true"
    />

MainActivity.java
onCrease:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ImageView imageView = (ImageView) findViewById(R.id.icon);
    TextView textView = (TextView) findViewById(R.id.text);

    /**
     *  插件apk路徑
     */
    String apkPath =     Environment.getExternalStorageDirectory()+"/apkbeloaded-debug.apk";
    /**
     *  插件資源對象
     */
    Resources resources = getBundleResource(this,apkPath);
    /**
     *獲取圖片資源
     */
    Drawable drawable = resources.getDrawable(resources.getIdentifier("icon_be_load", "drawable",
        "laodresource.demo.com.apkbeloaded"));
    /**
     *  獲取文本資源
     */
    String text = resources.getString(resources.getIdentifier("text_beload","string",
        "laodresource.demo.com.apkbeloaded"));

    imageView.setImageDrawable(drawable);
    textView.setText(text);

}

創(chuàng)建Resource對象:

public Resources getBundleResource(Context context, String apkPath){
    AssetManager assetManager = createAssetManager(apkPath);
    return new Resources(assetManager,  
    context.getResources().getDisplayMetrics(), 
    context.getResources().getConfiguration());
}

創(chuàng)建AssetManager對象:

private AssetManager createAssetManager(String apkPath) {
    try {
        AssetManager assetManager = AssetManager.class.newInstance();
        AssetManager.class.getDeclaredMethod("addAssetPath", String.class).invoke(
            assetManager, apkPath);
        return assetManager;
    } catch (Throwable th) {
        th.printStackTrace();
    }
    return null;
}

到這里慨飘,我們完成了插件研究的第一個問題:加載插件apk的class和資源瓤的。下一篇文章開始研究插件中的組件注冊問題圈膏。
Demo源碼:https://github.com/liuguangli/LoadResourceDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末篙骡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子尿褪,更是在濱河造成了極大的恐慌杖玲,老刑警劉巖淘正,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件臼闻,死亡現(xiàn)場離奇詭異述呐,居然都是意外死亡斑唬,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門缤谎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坷澡,“玉大人含蓉,你說我怎么就攤上這事≌遄” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵拗军,是天一觀的道長发侵。 經(jīng)常有香客問我刃鳄,道長钱骂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任掌腰,我火速辦了婚禮张吉,結(jié)果婚禮上肮蛹,老公的妹妹穿的比我還像新娘勺择。我一直安慰自己省核,他們只是感情好昆码,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布赋咽。 她就那樣靜靜地躺著,像睡著了一般脓匿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上米母,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天毡琉,我揣著相機(jī)與錄音桅滋,去河邊找鬼。 笑死蜂绎,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的师枣。 我是一名探鬼主播践美,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼陨倡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了兴革?” 一聲冷哼從身側(cè)響起杂曲,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤擎勘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棚饵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體噪漾,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡怪与,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年分别,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沼填。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡括授,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出薛夜,到底是詐尸還是另有隱情梯澜,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布晚伙,位于F島的核電站俭茧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏母债。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一牵署、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧青责,春花似錦、人聲如沸扁耐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至俗壹,卻和暖如春藻烤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背怖亭。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工期吓, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留峭跳,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像拯刁,于是被迫代替她去往敵國和親脊岳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 是時候來一波Android插件化了 是時候來一波Android插件化了前言Android開發(fā)演進(jìn)模塊化介紹插件化介...
    流水不腐小夏閱讀 4,774評論 3 51
  • 上一篇文章我們講解了如何使用 DexClassLoader 來加載插件文件中的類。 Android插件化進(jìn)階——插...
    小之丶閱讀 1,273評論 0 9
  • 插件化-資源處理 寫的比較長割捅,可以選擇跳過前面2節(jié)奶躯,直接從0x03實例分析開始。如有錯誤亿驾,請不吝指正嘹黔。 0x00 ...
    唐一川閱讀 5,317評論 2 22
  • [TOC] 插件化介紹 插件化: 在主程序能獨立運行的前提下,插件程序給主程序提供一些輔助的功能莫瞬,目前主要以apk...
    doubimonkey閱讀 1,822評論 0 49
  • 今日儡蔓,頭好暈啊~ 果然還是不要熬夜比較好啊,養(yǎng)成的好習(xí)慣就這樣被輕易打亂了疼邀。 關(guān)于未來喂江,我不迷茫,其實生活嘛旁振,也沒...
    搗搗閱讀 91評論 0 0