Android實(shí)現(xiàn)動(dòng)態(tài)加載dex, res, so

什么是動(dòng)態(tài)加載垃沦?

- 簡(jiǎn)單來(lái)說(shuō)動(dòng)態(tài)加載可以加載原本apk不存在的代碼掸犬。

什么場(chǎng)景適用菜秦?

  • 很多場(chǎng)景都適用异袄,比如可以實(shí)現(xiàn)app無(wú)感更新滚朵,不過(guò)有些應(yīng)用市場(chǎng)對(duì)含有動(dòng)態(tài)更新功能的app抓得比較嚴(yán)冤灾,因?yàn)閾?dān)心你偷偷更新了做些壞事。

動(dòng)態(tài)加載的難點(diǎn)是哪里辕近?

如何動(dòng)態(tài)加載res文件

  • 如果只是做動(dòng)態(tài)加載java代碼韵吨,則只需要加載dex就行了,簡(jiǎn)單方便
  • 如果要?jiǎng)討B(tài)加載的內(nèi)容包括res資源移宅,比如布局归粉,資源圖片椿疗。有兩種方案可選:
    • 布局采用java代碼編寫(xiě),資源圖片放到assets中糠悼,這樣assets可以打包到j(luò)ar包中届榄,這樣就可以只加載dex,無(wú)需加載res倔喂,但是采用java代碼開(kāi)發(fā)res較為耗時(shí)不方便铝条,若是只有少量簡(jiǎn)單布局及資源圖片可能采用此方法
    • 布局及資源文件等采用res的xml編寫(xiě),需要避免資源的id與宿主apk的id沖突以及如何將動(dòng)態(tài)加載的Resources注入到宿主Activity的Resources中滴劲,這樣就能夠通過(guò)宿主的context.getResources().getIdentifier接口獲取到資源id了

動(dòng)態(tài)更新需要怎么做攻晒?


加載dex

如何生成dex?
  • 將java代碼打成jar包班挖,再用dex2jar工具將jar打成dex
  • 需要注意鲁捏,要將R.class文件也打包進(jìn)入dex中,需要通過(guò)此文件關(guān)聯(lián)res資源萧芙,若無(wú)res資源可忽略
如何加載dex给梅?
  • 通過(guò)DexClassLoader加載dex文件實(shí)例出ClassLoader
  • 通過(guò)ClassLoader.loadClass("xx.xx.Xxx")
  • 再通過(guò)反射的方式調(diào)用具體的方法

加載res

res打包成什么格式?
  • apk格式双揪,可以在在需要?jiǎng)討B(tài)加載的項(xiàng)目中动羽,生成成apk后用壓縮工具打開(kāi),將里面的dex刪除即可
打包res需要注意什么渔期?
  • 需要注意其中的資源id运吓,修改其id段,避免與資源id沖突疯趟,需要在gradle中配置
    修改為package-id為0x70段的id, 默認(rèn)為0x7f拘哨,修改的id段不能大于0x7f段,否則會(huì)出問(wèn)題信峻,此方法只有在compileSdkVersion為28及以上才生效倦青,低于28的可以在網(wǎng)上尋找修改aapt源碼并編譯出新的功能用于修改package-id
android {
    aaptOptions {
        additionalParameters '--allow-reserved-package-id','--package-id','0x70'
    }
}
如何加載res?
  • 在成功加載dex代碼后盹舞,在加載dex運(yùn)行的第一時(shí)間進(jìn)行res的加載产镐,或者說(shuō)是將res注入到宿主中
try {
            AssetManager assetManager = AssetManager.class.newInstance();
            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
            String resFilePath = resFile(context).getAbsolutePath();
            String baseApkPath = baseApkPath(context);
            if (!TextUtils.isEmpty(baseApkPath)) {
                LOG.i("重設(shè)原生資源--->" + baseApkPath);
                addAssetPath.invoke(assetManager, baseApkPath);
            }
            LOG.i("設(shè)置外置資源resFilePath--->" + resFilePath);
            addAssetPath.invoke(assetManager, resFilePath);
            mResources =
                    new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources()
                            .getConfiguration());
            mAssetManager = mResources.getAssets();
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }
    public String baseApkPath(Context context) {
        try {
            String s = context.getApplicationContext().getPackageResourcePath();
            if (s == null){
                Process process = Runtime.getRuntime().exec("pm path " + context.getPackageName());
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                s = reader.readLine();
                LOG.i("getRuntime baseApkPath",s);
            }
            LOG.i("getApplication baseApkPath",s);
            return s.substring(s.indexOf("/"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

加載so

如何加載so?
  • 實(shí)例化DexClassLoader將so所在的路徑傳入即可自動(dòng)搜索加載
    DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent)``librarySearchPath即為so所以的路徑踢步,此路徑需要為當(dāng)前包所在的路徑data/data/package/下癣亚,要注意的是,so會(huì)根據(jù)cpu的架構(gòu)不同而有不同的文件获印,所以我們?cè)谶x擇so時(shí)要先根據(jù)Build.CPU_ABI判斷cpu的架構(gòu)選擇哪個(gè)so文件逃糟。

奈何表達(dá)能力太差,下次寫(xiě)個(gè)詳細(xì)的蓬豁,下次一定绰咽!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市地粪,隨后出現(xiàn)的幾起案子取募,更是在濱河造成了極大的恐慌,老刑警劉巖蟆技,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玩敏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡质礼,警方通過(guò)查閱死者的電腦和手機(jī)旺聚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)眶蕉,“玉大人砰粹,你說(shuō)我怎么就攤上這事≡焱欤” “怎么了碱璃?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)饭入。 經(jīng)常有香客問(wèn)我嵌器,道長(zhǎng),這世上最難降的妖魔是什么谐丢? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任爽航,我火速辦了婚禮,結(jié)果婚禮上乾忱,老公的妹妹穿的比我還像新娘讥珍。我一直安慰自己,他們只是感情好饭耳,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布串述。 她就那樣靜靜地躺著,像睡著了一般寞肖。 火紅的嫁衣襯著肌膚如雪纲酗。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天新蟆,我揣著相機(jī)與錄音觅赊,去河邊找鬼。 笑死琼稻,一個(gè)胖子當(dāng)著我的面吹牛吮螺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鸠补,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼萝风!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起紫岩,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤规惰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后泉蝌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體歇万,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年勋陪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贪磺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诅愚,死狀恐怖寒锚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情呻粹,我是刑警寧澤壕曼,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站等浊,受9級(jí)特大地震影響腮郊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜筹燕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一轧飞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧过咬,春花似錦、人聲如沸制妄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)振愿。三九已至捷犹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冕末,已是汗流浹背萍歉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留栓霜,地道東北人翠桦。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像胳蛮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丛晌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348