快速开始

接入说明

instantRun 方式仅支持原生 AAR 接入方式。

  1. 添加 SDK

  2. 初始化热修复

  3. 生成热修复补丁

  4. 发布热修复补丁

InstantRun 新特性

  • 满足一定条件下,支持不重启修复;

  • 支持 so 修复

  • 支持资源修复;

  • 生成补丁的时候不需要类白名单。

技术原理

Java 修复

  • 通过对 JavaMethod 进行预插桩,实现动态的逻辑替换。

  • 构建 Patch 需要修改源码,因此无法修改代码的三方库不能实现修复。

so 修复

  • 原始 so 未加载可立即生效。

资源修复

  • 通过固定资源 id 而进行新增和修改。

前置条件

  • 采用原生 AAR 方式接入,需要先 将mPaaS 添加到您的项目中

  • 不要混用 dexPatch 热修复方式和 instantRun 热修复方式。

  • 新旧 APK 包中的 so 文件数量和名字需要保持一致,否则无法打出热修复补丁且不支持修复。

  • 必须使用 10.2.3-20 及以上基线版本,如你是 10.1.68 基线版本按照文档进行 mPaaS 10.2.3 升级指南

添加 SDK

原生 AAR 方式

参考 管理组件依赖,通过 组件管理(AAR)在工程中安装 热修复(Hotfix)组件。

初始化热修复

原生 AAR 接入

如果需要使用热修复功能,您还需要完成以下两步操作。

  1. 需要将 Application对象重新继承为 QuinoxlessApplicationLike,并注意将该类防混淆。此处以 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) {
      }
     }
  2. 在 AndroidManifest.xml 文件中将 Application对象指向 mPaaS 提供的 Application对象。将刚刚生成的 MyApplication 类添加到 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 代理类,继承 QuinoxlessApplicationLike

  3. 引入 Apache HTTP 客户端。

    在使用热修复功能的时候,需要调用到 Apache HTTP 客户端相关的功能。只需在AndroidManifest.xml加入如下代码。更多信息,请参见使用 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 插桩配置

创建 instantrun 文件夹

在主工程的 app 目录下创建 instantrun 文件夹,放入生成 patch.jar 需要使用的 mapping.txt 文件。

instantrun 文件夹中文件的说明及来源按以下方式操作放入:

重要

以下文件必须每次发布版本前进行保留,当需要修复时需将上个版本保留好的替换到 instantrun 文件夹中。

在有 Bug 的项目工程中执行命令行 ./gradlew clean assembleRelease生成以下文件:

instantrun/InstantRunMapping.txt.gz(构建后生成的 InstantRunMapping_release.txt.gz 或 InstantRunMapping_debug.txt.gz,产物在 ./build/outputs/instantrun/ 如有,则改名后放入)

instantrun/mapping.txt(原工程构建打 Release 包时的 mapping.txt,产物在 ./build/outputs/mapping/[debug|release]/mapping.txt)

instantrun/methodsMap.instantrun(原 Bundle 级别接入插桩生成的 methodsMap.instantrun,产物在./build/outputs/instantrun/methodsMap.instantrun 如有则放入)

添加 instantrun.xml 配置文件

在主工程的 app 目录下添加 instantrun.xml配置文件,注意配置中的相关内容,请仔细斟酌每个选项:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <switch>
        <!--true代表打开InstantRun,请注意即使这个值为true,InstantRun也默认只在Release模式下开启-->
        <!--false代表关闭InstantRun,无论是Debug还是Release模式都不会运行InstantRun-->
        <turnOnInstantRun>true</turnOnInstantRun>

        <!--是否开启手动模式,手动模式会去寻找配置项patchPackageName包名下的所有类,自动的处理混淆,然后把patchPackageName包名下的所有类制作成补丁-->
        <!--这个开关只是把配置项patchPackageName包名下的所有类制作成补丁,适用于特殊情况,一般不会遇到-->
        <manual>false</manual>

        <!--是否强制插入代码,InstantRun默认在debug模式下是关闭的,开启这个选项为true会在debug下插入代码-->
        <!--但是当配置项turnOnInstantRun是false时,这个配置项不会生效-->
        <forceInsert>false</forceInsert>

        <!--配置Patch函数匹配规则,默认为函数签名,可修改为函数序号,存储在methodsMap.instantrun中-->
        <!--其中signature模式切面占用空间较大,而id模式切面占用空间会更小一些,更适合在乎安装包大小的App使用-->
        <!--<methodMatchMode>signature</methodMatchMode>-->
        <methodMatchMode>id</methodMatchMode>

        <!--是否捕获补丁中所有异常,建议上线的时候这个开关的值为true,测试的时候为false-->
        <catchReflectException>false</catchReflectException>

        <!--是否在补丁加上log,建议上线的时候这个开关的值为false,测试的时候为true-->
        <patchLog>true</patchLog>

        <!--项目是否支持progaurd-->
        <proguard>true</proguard>

    </switch>

    <!--需要HotPatch的包名或者类名,这些包名下的所有类都会被插入代码-->
    <!--这个配置项是各个Bundle需要自行配置,就是你们Bundle里面你们自己代码的包名,
    这些包名下的类会被InstantRun插入代码,没有被InstantRun插入代码的类InstantRun是无法修复的-->
    <acceptPackageName name="acceptPackage">
        <name>com.</name>
        <name>android.</name>
        <name>org.</name>
    </acceptPackageName>

    <!--不需要InstantRun插入代码的包名,InstantRun库不需要插入代码,如下的配置项请保留,还可以根据各个APP的情况执行添加-->
    <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插桩的函数访问类型和对应包名列表,按需插桩,可降低接入包大小-->
    <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>

    <!--补丁的包名,请保证唯一性,填写apk包名即可-->
    <patchPackageName name="patchPackage">
        <name>com.instantrun.demo</name>
    </patchPackageName>

</resources>

修改 Bug 代码

Java 函数修复方式

  • 首先接入上述的构建依赖与配置;

  • 需要在改动的方法上面添加以下注解:

    @com.alipay.instantrun.patch.annotaion.Modify

    //修改方法
    @com.alipay.instantrun.patch.annotaion.Modify
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    }
    //或者是被修改的方法里面调用 com.alipay.instantrun.patch.InstantRunModify.modify()方法
    protected void onCreate(Bundle savedInstanceState) {
        com.alipay.instantrun.patch.InstantRunModify.modify()
            super.onCreate(savedInstanceState);
    }
  • 对于 Lambda 表达式,需要在修改的方法里面调用:com.alipay.instantrun.patch.InstantRunModify.modify()

    //修改方法
    @com.alipay.instantrun.patch.annotaion.Modify
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    }
    //或者是被修改的方法里面调用com.alipay.instantrun.patch.InstantRunModify.modify()方法
    protected void onCreate(Bundle savedInstanceState) {
        com.alipay.instantrun.patch.InstantRunModify.modify()
            super.onCreate(savedInstanceState);
    }
  • 新增的类、方法使用 @com.alipay.instantrun.patch.annotaion.Add注解。

    //增加方法
    @com.alipay.instantrun.patch.annotaion.Add
    public String getString() {
        return "InstantRun";
    }
    //增加类
    @com.alipay.instantrun.patch.annotaion.Add
    public class NewAddCLass {
        public static String get() {
            return "instantRun";
            }
    }

so 修复方式

修改相关 C/C++ 代码或 so 即可,然后打包新的 so 替换工程中有问题的 so 库。

资源修复方式

支持任何资源文件的修复和添加,但不支持 so 库资源的添加。

资源 ID 固定配置

  1. 下载 生成资源文件的工具 Jar 包 获取需要修复的 apk 包资源 id,执行以下命令行:

    java -jar ~/path/stableResourcesId.jar ~/path/old.apk ~/path/values

    生成的产物在目标目录下。

  2. 将上面命令行生成的 public.xmlids.xml 两个文件产物放入到新工程(修复好的工程)的 ~/res/values 目录中。

  3. public.txt 文件放入到新工程(修复好的工程)的根目录中。

    然后在 app moudle 的 build.gradle 文件中的 android 节点下进行如下配置:

    aaptOptions {
        File publicTxtFile = project.rootProject.file( 'public.txt')
        if (publicTxtFile.exists()) {
            additionalParameters "--stable-ids", "${project.rootProject.file
            ('public.txt').absolutePath}"
        }
    }

进行补丁打包配置

在 Android Studio 的 mPaaS 插件中,进入 基础工具 > 热修复 > 生成补丁(instant run)页面。

说明

如果是修改或者新增 res/layout 下的 xml 布局文件,则需在 Java 代码层进行 Java patch 加入修改的注解以及获取对应的资源 id,再进行加载。

使用 instantRun

生成 patch.jar 产物

patch.jar 是生成热修复补丁包的关键,包含了需要修复的内容,在最新修复的工程输出即可,在终端按如下命令行执行生成:

./gradlew clean mpGeneratePatch

生成的产物在工程的 ./build/outputs/instantrun/patch.jar目录下。

生成热修复 instantRun 补丁

在 Android Studio 的 mPaaS 插件工程中进行补丁生成,如下所示:

  1. 单击 基础工具 > 热修复 > 生成补丁(instant run)

  2. 进入生成补丁页面,填写相关修复信息项。

    输入项含义说明

    • New bundle:选择最新修复好的 apk 包路径。

    • Old bundle:选择有 bug 的 apk 包路径(线上版本)。

    • PatchJarPath dir:工程中接入 instantRun 执行命令行 ./gradlew clean mpGeneratePatch 打出的 patch.jar 路径。

    • Patch out dir:存放补丁包产物的路径。

    重要

    New bundle 和 Old bundle 中的 apk 包不能存放到 C 盘的 User 目录下和中文目录下。

  3. 单击 Next 进入填写签名信息页面。

    确保填写的签名信息准确,否则会导致生成失败。

  4. 填写完成后单击 Create 即可生成补丁。

使用热修复

将补丁包发布到控制台,具体参考文档 使用热修复

查看日志

  • 热更新请求日志

    过滤 Tag 中包含 DynamicRelease 的日志;

  • InstantRun 执行日志

    过滤 Tag 中包含 IR. 的日志;

  • Patch 执行日志

    在打 Patch 前,在构建配置 instantrun.xml 中打开 patchLog 选项。 过滤 Tag 中包含 IR.PatchCode 的日志。包含 invoke method is 的日志行,表示执行了对应函数的 Patch。