快速開(kāi)始
接入說(shuō)明
instantRun 方式僅支持原生 AAR 接入方式。
InstantRun 新特性
滿足一定條件下,支持不重啟修復(fù);
支持資源修復(fù);
生成補(bǔ)丁的時(shí)候不需要類(lèi)白名單。
技術(shù)原理
Java 修復(fù)
通過(guò)對(duì) JavaMethod 進(jìn)行預(yù)插樁,實(shí)現(xiàn)動(dòng)態(tài)的邏輯替換。
構(gòu)建 Patch 需要修改源碼,因此無(wú)法修改代碼的三方庫(kù)不能實(shí)現(xiàn)修復(fù)。
so 修復(fù)
原始 so 未加載可立即生效。
資源修復(fù)
通過(guò)固定資源 id 而進(jìn)行新增和修改。
前置條件
采用原生 AAR 方式接入,需要先 將mPaaS 添加到您的項(xiàng)目中。
不要混用 dexPatch 熱修復(fù)方式和 instantRun 熱修復(fù)方式。
新舊 APK 包中的 so 文件數(shù)量和名字需要保持一致,否則無(wú)法打出熱修復(fù)補(bǔ)丁且不支持修復(fù)。
必須使用 10.2.3-20 及以上基線版本,如你是 10.1.68 基線版本按照文檔進(jìn)行 mPaaS 10.2.3 升級(jí)指南。
添加 SDK
原生 AAR 方式
參考 管理組件依賴,通過(guò) 組件管理(AAR)在工程中安裝 熱修復(fù)(Hotfix)組件。
初始化熱修復(fù)
原生 AAR 接入
如果需要使用熱修復(fù)功能,您還需要完成以下兩步操作。
需要將
Application
對(duì)象重新繼承為QuinoxlessApplicationLike
,并注意將該類(lèi)防混淆。此處以 MyApplication 為例。@Keep public class MyApplication extends QuinoxlessApplicationLike implements Application.ActivityLifecycleCallbacks { private static final String TAG = "MyApplication"; @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); Log.i(TAG, "attacheBaseContext"); } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate"); registerActivityLifecycleCallbacks(this); } @Override public void onMPaaSFrameworkInitFinished() { MPHotpatch.init(); LoggerFactory.getTraceLogger().info(TAG, getProcessName()); } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { Log.i(TAG, "onActivityCreated"); } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { } }
在 AndroidManifest.xml 文件中將
Application
對(duì)象指向 mPaaS 提供的Application
對(duì)象。將剛剛生成的 MyApplication 類(lèi)添加到 key 為mpaas.quinoxless.extern.application
的meta-data
中。示例如下:<application android:name="com.alipay.mobile.framework.quinoxless.QuinoxlessApplication" > <meta-data android:name="mpaas.quinoxless.extern.application" android:value="com.mpaas.demo.MyApplication" /> </application>
其中
com.mpaas.demo.MyApplication
是您自定義的 Application 代理類(lèi),繼承QuinoxlessApplicationLike
。引入 Apache HTTP 客戶端。
在使用熱修復(fù)功能的時(shí)候,需要調(diào)用到 Apache HTTP 客戶端相關(guān)的功能。只需在
AndroidManifest.xml
加入如下代碼。更多信息,請(qǐng)參見(jiàn)使用 Apache HTTP 客戶端。<uses-library android:name="org.apache.http.legacy" android:required="false"/>
instantRun 插樁配置和依賴
instantRun Maven
maven {
url "https://mvn.cloud.alipay.com/nexus/content/repositories/open/"
}
instantRun 插樁依賴
工程 app 主 module 下 build.gradle 文件中添加如下依賴:
apply plugin: 'com.android.application'
apply plugin: 'com.alipay.instantrun'
工程根目錄下 build.gradle 文件中添加如下插件依賴:
dependencies {
classpath "com.mpaas.android.patch:patch-gradle-plugin:1.0.7"
}
instantRun 插樁配置
創(chuàng)建 instantrun 文件夾
在主工程的 app 目錄下創(chuàng)建 instantrun 文件夾,放入生成 patch.jar 需要使用的 mapping.txt
文件。
instantrun 文件夾中文件的說(shuō)明及來(lái)源按以下方式操作放入:
以下文件必須每次發(fā)布版本前進(jìn)行保留,當(dāng)需要修復(fù)時(shí)需將上個(gè)版本保留好的替換到 instantrun 文件夾中。
在有 Bug 的項(xiàng)目工程中執(zhí)行命令行 ./gradlew clean assembleRelease
生成以下文件:
instantrun/InstantRunMapping.txt.gz(構(gòu)建后生成的 InstantRunMapping_release.txt.gz 或 InstantRunMapping_debug.txt.gz,產(chǎn)物在 ./build/outputs/instantrun/ 如有,則改名后放入)
instantrun/mapping.txt(原工程構(gòu)建打 Release 包時(shí)的 mapping.txt,產(chǎn)物在 ./build/outputs/mapping/[debug|release]/mapping.txt)
instantrun/methodsMap.instantrun(原 Bundle 級(jí)別接入插樁生成的 methodsMap.instantrun,產(chǎn)物在./build/outputs/instantrun/methodsMap.instantrun 如有則放入)
添加 instantrun.xml 配置文件
在主工程的 app 目錄下添加 instantrun.xml
配置文件,注意配置中的相關(guān)內(nèi)容,請(qǐng)仔細(xì)斟酌每個(gè)選項(xiàng):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<switch>
<!--true代表打開(kāi)InstantRun,請(qǐng)注意即使這個(gè)值為true,InstantRun也默認(rèn)只在Release模式下開(kāi)啟-->
<!--false代表關(guān)閉InstantRun,無(wú)論是Debug還是Release模式都不會(huì)運(yùn)行InstantRun-->
<turnOnInstantRun>true</turnOnInstantRun>
<!--是否開(kāi)啟手動(dòng)模式,手動(dòng)模式會(huì)去尋找配置項(xiàng)patchPackageName包名下的所有類(lèi),自動(dòng)的處理混淆,然后把patchPackageName包名下的所有類(lèi)制作成補(bǔ)丁-->
<!--這個(gè)開(kāi)關(guān)只是把配置項(xiàng)patchPackageName包名下的所有類(lèi)制作成補(bǔ)丁,適用于特殊情況,一般不會(huì)遇到-->
<manual>false</manual>
<!--是否強(qiáng)制插入代碼,InstantRun默認(rèn)在debug模式下是關(guān)閉的,開(kāi)啟這個(gè)選項(xiàng)為true會(huì)在debug下插入代碼-->
<!--但是當(dāng)配置項(xiàng)turnOnInstantRun是false時(shí),這個(gè)配置項(xiàng)不會(huì)生效-->
<forceInsert>false</forceInsert>
<!--配置Patch函數(shù)匹配規(guī)則,默認(rèn)為函數(shù)簽名,可修改為函數(shù)序號(hào),存儲(chǔ)在methodsMap.instantrun中-->
<!--其中signature模式切面占用空間較大,而id模式切面占用空間會(huì)更小一些,更適合在乎安裝包大小的App使用-->
<!--<methodMatchMode>signature</methodMatchMode>-->
<methodMatchMode>id</methodMatchMode>
<!--是否捕獲補(bǔ)丁中所有異常,建議上線的時(shí)候這個(gè)開(kāi)關(guān)的值為true,測(cè)試的時(shí)候?yàn)閒alse-->
<catchReflectException>false</catchReflectException>
<!--是否在補(bǔ)丁加上log,建議上線的時(shí)候這個(gè)開(kāi)關(guān)的值為false,測(cè)試的時(shí)候?yàn)閠rue-->
<patchLog>true</patchLog>
<!--項(xiàng)目是否支持progaurd-->
<proguard>true</proguard>
</switch>
<!--需要HotPatch的包名或者類(lèi)名,這些包名下的所有類(lèi)都會(huì)被插入代碼-->
<!--這個(gè)配置項(xiàng)是各個(gè)Bundle需要自行配置,就是你們Bundle里面你們自己代碼的包名,
這些包名下的類(lèi)會(huì)被InstantRun插入代碼,沒(méi)有被InstantRun插入代碼的類(lèi)InstantRun是無(wú)法修復(fù)的-->
<acceptPackageName name="acceptPackage">
<name>com.</name>
<name>android.</name>
<name>org.</name>
</acceptPackageName>
<!--不需要InstantRun插入代碼的包名,InstantRun庫(kù)不需要插入代碼,如下的配置項(xiàng)請(qǐng)保留,還可以根據(jù)各個(gè)APP的情況執(zhí)行添加-->
<exceptPackageName name="exceptPackage">
<name>com.alipay.euler</name>
<name>com.alipay.dexpatch</name>
<name>com.alipay.instantrun</name>
<name>ohos.</name>
<name>com.alipay.mobile.quinox.LauncherApplication</name>
</exceptPackageName>
<!--不需要InstantRun插樁的函數(shù)訪問(wèn)類(lèi)型和對(duì)應(yīng)包名列表,按需插樁,可降低接入包大小-->
<methodExceptConfig name="methodExceptConfig">
<privateMethodPackage>
<name>com.instantrun.demo</name>
</privateMethodPackage>
<packageMethodPackage>
<name>com.instantrun.demo</name>
</packageMethodPackage>
<protectedMethodPackage>
<name>com.instantrun.demo</name>
</protectedMethodPackage>
<publicMethodPackage>
<name>com.instantrun.demo</name>
</publicMethodPackage>
<syntheticMethodPackage>
<name>com.instantrun.demo</name>
</syntheticMethodPackage>
</methodExceptConfig>
<!--補(bǔ)丁的包名,請(qǐng)保證唯一性,填寫(xiě)apk包名即可-->
<patchPackageName name="patchPackage">
<name>com.instantrun.demo</name>
</patchPackageName>
</resources>
修改 Bug 代碼
Java 函數(shù)修復(fù)方式
首先接入上述的構(gòu)建依賴與配置;
需要在改動(dòng)的方法上面添加以下注解:
@com.alipay.instantrun.patch.annotaion.Modify
//修改方法 @com.alipay.instantrun.patch.annotaion.Modify protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } //或者是被修改的方法里面調(diào)用 com.alipay.instantrun.patch.InstantRunModify.modify()方法 protected void onCreate(Bundle savedInstanceState) { com.alipay.instantrun.patch.InstantRunModify.modify() super.onCreate(savedInstanceState); }
對(duì)于 Lambda 表達(dá)式,需要在修改的方法里面調(diào)用:
com.alipay.instantrun.patch.InstantRunModify.modify()
。//修改方法 @com.alipay.instantrun.patch.annotaion.Modify protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } //或者是被修改的方法里面調(diào)用com.alipay.instantrun.patch.InstantRunModify.modify()方法 protected void onCreate(Bundle savedInstanceState) { com.alipay.instantrun.patch.InstantRunModify.modify() super.onCreate(savedInstanceState); }
新增的類(lèi)、方法使用
@com.alipay.instantrun.patch.annotaion.Add
注解。//增加方法 @com.alipay.instantrun.patch.annotaion.Add public String getString() { return "InstantRun"; } //增加類(lèi) @com.alipay.instantrun.patch.annotaion.Add public class NewAddCLass { public static String get() { return "instantRun"; } }
so 修復(fù)方式
修改相關(guān) C/C++ 代碼或 so 即可,然后打包新的 so 替換工程中有問(wèn)題的 so 庫(kù)。
資源修復(fù)方式
支持任何資源文件的修復(fù)和添加,但不支持 so 庫(kù)資源的添加。
資源 ID 固定配置
下載 生成資源文件的工具 Jar 包 獲取需要修復(fù)的 apk 包資源 id,執(zhí)行以下命令行:
java -jar ~/path/stableResourcesId.jar ~/path/old.apk ~/path/values
生成的產(chǎn)物在目標(biāo)目錄下。
將上面命令行生成的
public.xml
、ids.xml
兩個(gè)文件產(chǎn)物放入到新工程(修復(fù)好的工程)的~/res/values
目錄中。將
public.txt
文件放入到新工程(修復(fù)好的工程)的根目錄中。然后在 app moudle 的
build.gradle
文件中的 android 節(jié)點(diǎn)下進(jìn)行如下配置:aaptOptions { File publicTxtFile = project.rootProject.file( 'public.txt') if (publicTxtFile.exists()) { additionalParameters "--stable-ids", "${project.rootProject.file ('public.txt').absolutePath}" } }
進(jìn)行補(bǔ)丁打包配置
在 Android Studio 的 mPaaS 插件中,進(jìn)入 基礎(chǔ)工具 > 熱修復(fù) > 生成補(bǔ)丁(instant run)頁(yè)面。
說(shuō)明
如果是修改或者新增 res/layout
下的 xml
布局文件,則需在 Java 代碼層進(jìn)行 Java patch 加入修改的注解以及獲取對(duì)應(yīng)的資源 id,再進(jìn)行加載。
使用 instantRun
生成 patch.jar 產(chǎn)物
patch.jar 是生成熱修復(fù)補(bǔ)丁包的關(guān)鍵,包含了需要修復(fù)的內(nèi)容,在最新修復(fù)的工程輸出即可,在終端按如下命令行執(zhí)行生成:
./gradlew clean mpGeneratePatch
生成的產(chǎn)物在工程的 ./build/outputs/instantrun/patch.jar
目錄下。
生成熱修復(fù) instantRun 補(bǔ)丁
在 Android Studio 的 mPaaS 插件工程中進(jìn)行補(bǔ)丁生成,如下所示:
單擊 基礎(chǔ)工具 > 熱修復(fù) > 生成補(bǔ)丁(instant run)。
進(jìn)入生成補(bǔ)丁頁(yè)面,填寫(xiě)相關(guān)修復(fù)信息項(xiàng)。
輸入項(xiàng)含義說(shuō)明
New bundle:選擇最新修復(fù)好的 apk 包路徑。
Old bundle:選擇有 bug 的 apk 包路徑(線上版本)。
PatchJarPath dir:工程中接入 instantRun 執(zhí)行命令行
./gradlew clean mpGeneratePatch
打出的patch.jar
路徑。Patch out dir:存放補(bǔ)丁包產(chǎn)物的路徑。
重要New bundle 和 Old bundle 中的 apk 包不能存放到 C 盤(pán)的 User 目錄下和中文目錄下。
單擊 Next 進(jìn)入填寫(xiě)簽名信息頁(yè)面。
確保填寫(xiě)的簽名信息準(zhǔn)確,否則會(huì)導(dǎo)致生成失敗。
填寫(xiě)完成后單擊 Create 即可生成補(bǔ)丁。
使用熱修復(fù)
將補(bǔ)丁包發(fā)布到控制臺(tái),具體參考文檔 使用熱修復(fù)。
查看日志
熱更新請(qǐng)求日志
過(guò)濾 Tag 中包含 DynamicRelease 的日志;
InstantRun 執(zhí)行日志
過(guò)濾 Tag 中包含 IR. 的日志;
Patch 執(zhí)行日志
在打 Patch 前,在構(gòu)建配置 instantrun.xml 中打開(kāi) patchLog 選項(xiàng)。 過(guò)濾 Tag 中包含 IR.PatchCode 的日志。包含 invoke method is 的日志行,表示執(zhí)行了對(duì)應(yīng)函數(shù)的 Patch。