<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ZeusPlugin插件框架項目

          聯(lián)合創(chuàng)作 · 2023-09-28 12:39

          本項目為ZeusPlugin插件框架項目,ZeusPlugin為插件框架代碼,app為測試插件與補(bǔ)丁的項目demo,testplugin為插件demo, testhotfix為補(bǔ)丁demo。絕大部分核心代碼都在PluginManger.java中。PluginManager也是入口類,核心方法是inite初始化、loadLastVersionPlugin加載插件、reloadInstalledPluginResources加載插件與補(bǔ)丁的資源、loadHotfixPluginClassLoader加載補(bǔ)丁的類。插件與補(bǔ)丁更新的最小單位是java類(不局限四大組件)。

          插件的定位

          提高某些功能的升級率,使功能可以不通過安裝新apk版本進(jìn)行更新,可以實現(xiàn)wifi/移動環(huán)境下用戶無感知的更新功能。如果電商類的網(wǎng)頁,可以通過url告知客戶端使用哪個插件并可以指定最低版本,然后客戶端發(fā)現(xiàn)存在符合的插件就加載使用。如:http//www.baidu.com/a.php?p=zeusplugin_test&pversion=2,表示該頁面使用zeusplugin_test插件,插件的最低版本號為2。宿主發(fā)現(xiàn)存在符合的插件則加載并將該url傳給插件,不存在則進(jìn)入下載流程,下載完成后即可加載。插件的下發(fā)可以通過push或者輪訓(xùn)的方式預(yù)下載增量更新包,或者進(jìn)入loading頁面同步下載,下載完成后即可加載使用。這時插件就可以是Fragment、ViewActivity等等。

          補(bǔ)丁使用的定位

          解決某個版本發(fā)布后的bug,或者是更新某個功能。由于代碼會進(jìn)行混淆,一個補(bǔ)丁通常只能對應(yīng)一個版本。

          插件補(bǔ)丁框架的核心思想

          • 替換系統(tǒng)使用的ClassLoader,通過閱讀源碼發(fā)現(xiàn)系統(tǒng)反射四大組件都是用的ContextImpl中的mPackageInfo中的mClassLoader成員變量。所以為了能讓系統(tǒng)生成四大組件,我們通過反射修改了mClassLoader成員變量。補(bǔ)丁原理則是ClassLoader優(yōu)先查找補(bǔ)丁中的類,如果存在則返回,然后再查找原宿主中的類,我們是通過反射的方式設(shè)置宿主ClassLoaderparent成員來完成的。

          • 替換系統(tǒng)獲取資源用到的Resources對象并使該對象可以訪問到所有插件和補(bǔ)丁的資源,Resources是通過AssetManager來訪問資源的。系統(tǒng)的Resources對象是ContextImplmPackageInfo中的mResources成員。因此我們生成了一個PluginResources對象并創(chuàng)建一個可以訪問所有插件的AssetManager,反射調(diào)用addAssetPath將插件/補(bǔ)丁的路徑都添加上。 通過反射修改了mResources成員變量。但是部分手機(jī)是通過獲取調(diào)用Activity/Application中的getResources來訪問,我們重寫該方法,并返回生成的PluginResources。

          以上就是我們的核心,修改生成類和資源的成員變量

          支持運(yùn)行時更新的原理

          • 插件更新后,插件在訪問資源應(yīng)該都是新插件中的資源。因此我們重新創(chuàng)建一個Resources,這個新的Resources只能訪問宿主跟新插件中的資源。這解決了資源更新的問題。

          • 插件更新后,插件在生成類的時候應(yīng)該生成新插件中的類。因此我們重新創(chuàng)建了一個插件ClassLoader來替換原來的ClassLoader,在方案中,一個插件對應(yīng)一個ClassLoader,ZeusClassLoader是個空殼,它內(nèi)部有一個數(shù)組保存了所有的插件ClassLoaderzeusClassLoader首先查找原宿主apkClassLoader,因為宿主apkClassLoaderparent為補(bǔ)丁ClassLoader,所以先在補(bǔ)丁中查找類,然后在宿主apk中查找,最后依次在插件中查找。我們只要替換了插件ClassLoader,那么新的插件ClassLoader自然只能訪問新插件中的類了。

          • 系統(tǒng)在解析xml生成View的時候都是通過反射來生成View的,系統(tǒng)為了加快速度會把所有已經(jīng)反射過的View的構(gòu)造函數(shù)都保存在LayoutInflater的靜態(tài)成員變量sConstructorMap中,所以更新了插件后,我們會清除該map中的所有對象。

          • 在使用舊版本插件時,可以安裝新版本插件,每個插件的安裝地址都是隨機(jī)的,有個pathInfo文件來保存最新插件的隨機(jī)安裝路徑。一旦加載最新插件時,ClassLoaderAssetManager都指向最新版本的插件,當(dāng)然so路徑也是隨機(jī)的。當(dāng)軟件退出或者再次啟動的時候會清理掉老版本插件,因為pathInfo只保留最新插件的安裝地址,這些老版本插件就已經(jīng)不可訪問了,只能加載最新版本的插件。

          使用步驟

          1. 使原應(yīng)用程序的Application繼承BaseApplication。或者將BaseApplication代碼拷貝至自己的Application中。具體參考app中的MyApplication

          2. 使原應(yīng)用程序的Activity都繼承BaseActivity?;蛘邔?code>BaseActivity代碼拷貝至自己的Activity中。具體參考app中的MainActivity

          3. 內(nèi)置的插件應(yīng)放入assets目錄中。插件的命名以PluginConfig.EXP_PLUG_PREFIX為前綴,以PluginConfig.PLUGINWEB_APK_SUFF為結(jié)尾。

          4. 內(nèi)置的插件必須在插件項目的assets中添加PluginConfig.PLUGINWEB_MAINIFEST_FILE(即plugin.meta)文件,該文件為插件的配置文件。配置如插件名稱(name),插件版本(version),插件支持的宿主最低版本(minVersion),插件的入口類名(mainClass,可不寫)。具體參考testplugin例子。

          5. PluginConfig中是一些可以配置的信息,建議除了內(nèi)置插件目錄以外都不要修改。

          6. 請將當(dāng)前aapt目錄下aapt.exe拷貝到sdk目錄下的build-tools中的正在使用的打包工具,替換原有的aapt.exe, 該aapt.exe是基于6.0源碼編譯,包含windows、mac和linux(64位)版本。測試替換23.0.2、23.0.3都沒有問題。該aapt.exe還集成了資源混淆功能。需要在build.gradle中進(jìn)行配置。 如下:aaptOptions.additionalParameters '--PLUG-resoure-proguard', '--PLUG-resoure-id', '0x7d''--PLUG-resoure-proguard'表明開啟資源混淆,可以不寫,不寫表示不開啟資源混淆,'--PLUG-resoure-id'表示設(shè)置資源的packageID,'0x7d'表示資源packageID0x7d開頭。

          7. 插件或補(bǔ)丁的資源packageID不能與其他插件或者是宿主相同。具體如何設(shè)置請參考testplugin中的build.gradle。

          8. app模塊中的buil.gradle中的buildJar方法拷貝到你的build.gradle中,這個方法是用來生成插件的sdk,生成sdk的jar文件在build/libs路徑下, 把生成的jar放到插件項目的sdk-jars,要把什么類放到sdk中,請對該方法進(jìn)行修改。具體參考testplugin。

          9. 請將插件的AndroidManifest.xml中有關(guān)的配置添加到宿主中,包括四大組件、權(quán)限申請、meta-data等,為了插件的擴(kuò)展也可以在宿主中預(yù)定義一些組件。

          以下是補(bǔ)丁相關(guān)的。補(bǔ)丁與插件類似,只不過補(bǔ)丁把實時加載的功能去掉了。如果項目只運(yùn)行在android 4.4及以上(art虛擬機(jī),部分低于4.4的手機(jī)也可以去掉),則1忽略,以上就已經(jīng)支持補(bǔ)丁了,可以直接運(yùn)行app模塊,不需要以下的額外操作。

          1. 如果要支持bug fix的補(bǔ)丁功能,請把gradleplugin拷貝到工程里,并將project的build.gradle中的帶有“//-----補(bǔ)丁相關(guān)-------”的相關(guān)配置移植到你的項目里。如果你的項目只支持android 4.4及以上時(比如內(nèi)置應(yīng)用),不需要按照第當(dāng)前移植即可支持bug fix補(bǔ)丁功能。具體請查看testhotfix模塊。

          2. bug fix的補(bǔ)丁需要以PluginConfig.EXP_PLUG_HOT_FIX_PREFIX為開頭,補(bǔ)丁apk中res文件夾中必須有實際的資源,實在沒有就隨便寫個com.android.internal.util.Predicate要保留,故意讓所有的類中都包含這個類,這個類系統(tǒng)也定義了,所以dalvik虛擬機(jī)生成dex的時候會給當(dāng)前記一個標(biāo)記,這樣補(bǔ)丁才能實現(xiàn)。

          3. 插件與補(bǔ)丁都需要先安裝,插件可以任意時刻進(jìn)行加載,補(bǔ)丁則下次啟動由框架加載,不提供實時加載,實時加載之后你的內(nèi)存中的對象可能就會亂套了。插件與補(bǔ)丁的安裝代碼如下:PluginManager.getPlugin(pluginName).install();

          4. 如果宿主被混淆請打補(bǔ)丁包時使用-applymapping,具體請搜索,在此不做詳細(xì)介紹。

          5. 補(bǔ)丁只在宿主的release包才生效,請在release包中進(jìn)行測試。

          6. 補(bǔ)丁在android studio中開啟instant run時調(diào)試是無效的,如果要生效就得更改代碼,具體如何更改請查看PluginManager.java。

          支持特性

          1. 支持插件的安裝、升級、卸載、版本管理

          2. 支持插件調(diào)用宿主的類與資源。要在插件中使用宿主的資源ID,需要使用public.xml將資源ID固定,public.xml如何使用請自行搜索,并將該ID添加到sdk-jar中,如果只是插件調(diào)用宿主中的某個類,然后這個使用了宿主資源則不需處理。

          3. 支持插件的動態(tài)實時升級。只需要調(diào)用PluginManager.loadLastVersionPlugin(pluginName)即可使用最新版本的插件。

          4. 插件與宿主的關(guān)系和apk與android系統(tǒng)的關(guān)系接近。如果插件中有與宿主重名的類,這個插件中的類只能被插件使用,宿主是不會使用插件中的類的。宿主只能通過顯式loadClass的方式才能訪問插件。

          5. 當(dāng)插件版本過多又怕新插件在早期apk中不支持,應(yīng)編寫一個類CTS測試(google強(qiáng)制廠商執(zhí)行的兼容性測試)的小插件,該插件中會調(diào)用所有之前插件用到的宿主中的所有方法和成員等等。如果該小程序跑過了則說明新版本apk兼容所有插件。

          6. 支持so以及so的動態(tài)實時升級。

          7. 插件與補(bǔ)丁支持加固方案,單dex或者多個dex文件情況,已對android 1.5以上版本(已適配最新的android N)和廠商定制的android系統(tǒng)進(jìn)行了適配,適配了各種機(jī)型和廠商自己的系統(tǒng)(包括yunOS等)。測試無資源加載找不到的問題,存在極個別的第一次 加載后類找不到的情況,嘗試幾次就可以了。(概率極低,<0.0001%)

          8. 對性能無明顯影響。經(jīng)過在android 2.2及以上進(jìn)行高強(qiáng)度測試,對性能無明顯影響。

          9. 支持bug fix的補(bǔ)丁功能,補(bǔ)丁修復(fù)最小單位是java中的class,補(bǔ)丁中可以有資源,也可以使用宿主的資源,它其實跟插件是一樣的,只不過補(bǔ)丁的class 與宿主的class重名了,發(fā)現(xiàn)重名就替換,支持單dex、多dex(方法數(shù)超了的情況)。補(bǔ)丁對性能有微弱影響(個人認(rèn)為可以忽略),android 4.4及以上完全無影響。

          10. 如果你的apk沒有進(jìn)行代碼混淆,補(bǔ)丁也可以產(chǎn)生與插件相同的作用來進(jìn)行功能的更新。

          不支持的特性

          1. 不支持插件中使用activity動畫。如果要使用activity動畫請將activity動畫用到的xml文件放到宿主中,否則卡死。

          2. 不支持插件有自己的Application,插件獲取的是宿主的application。

          3. 不支持動態(tài)升級插件的AndroidManifest.xml文件,所有試圖修改AndroidManifest.xml的功能都需要升級宿主。不過這種情況很少,目前我們還沒遇到過。

          4. 不支持補(bǔ)丁實時加載,下次啟動才能加載,否則內(nèi)存中的對象會亂掉,如之前保存了A類的實例,現(xiàn)在A類已經(jīng)被實時替換為B類了,那么之前的A類實例就不能轉(zhuǎn)為B類了。

          5. 不支持插件在xml使用宿主的自定義屬性。(支持這個性價比太低,請使用其他替代方法)

          6. 其他還不清楚,還請大家進(jìn)行測試。

          瀏覽 20
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  精品视频第一页 | 欧美三级免费看 | AV天堂区 | 操逼达人 | 色婷婷五月天亚洲中文字幕 |