Skip to main content

Shiply 热修复 Android SDK 接入指引

一、隐私安全说明

Shiply 热修复 SDK

版本:2.0.1

更新时间:2025年2月21日

SDK介绍:为移动开发者提供在线热修复的能力,及时解决 App 线上严重问题。

服务提供方:深圳市腾讯计算机系统有限公司

接入指引:Shiply 热修复 SDK 接入指引

隐私保护规则:Shiply 热修复 SDK 隐私保护规则

二、接入 SDK

2.1 支持范围

版本 / 工具 / 开关支持范围
Android 系统版本5.0 ~ 15
minSdkVersion21 ~ 28
Android Gradle Plugin3.5 ~ 8.x
R8 Support支持

2.2 引入编译插件和运行时 SDK

1. 在项目根目录的 build.gradle 中引入热修复的 gradle 编译插件

buildscript {
repositories {
maven { url "https://tencent-tds-maven.pkg.coding.net/repository/shiply/repo/" }
}
dependencies {
classpath "com.tencent.rfix:RFix-gradle-plugin:2.0.1"
}
}

2. 在项目 app 的 build.gradle 中引入热修复的运行时 SDK 和注解处理器

repositories {
maven { url "https://tencent-tds-maven.pkg.coding.net/repository/shiply/repo/" }
}
dependencies {
compileOnly "com.tencent.rfix:RFix-android-anno:2.0.1"
implementation "com.tencent.rfix:RFix-android-lib:2.0.1"
annotationProcessor "com.tencent.rfix:RFix-android-anno:2.0.1"
}

PS: 如果编译时注解没能正常生效,注解目标类又是 kotlin 写的,可以尝试将 annotationProcessor 改为 kapt

3. 在项目 app 的 build.gradle 中应用 gradle 编译插件,并进行相关配置

apply plugin: 'com.tencent.rfix'

RFixPatch {
// 补丁类型:Disable/Tinker
patchType = 'Tinker'

// 修复目标Apk,通常为对外发布的Release版本
oldApks = ["${projectDir.absolutePath}/RFix/old.apk"]
// 修复后的Apk,在目标版本基础上修改代码后的版本
newApks = ["${projectDir.absolutePath}/RFix/new.apk"]
// 补丁输出目录
outputFolder = "${projectDir.absolutePath}/RFix/"

// 忽略补丁编译中的告警信息(该功能谨慎开启,忽略某些告警后生成的补丁可能异常)
ignoreWarning = false

buildConfig {
// Apk的唯一补丁标识,用于识别补丁和Apk是否匹配
patchId = new Date().format("MMddHHmmss")
// 使用splits实现多架构编译时需要开启该功能,以确保每个Apk的PatchId不同
appendOutputNameToPatchId = true

// 修复目标Apk的代码混淆文件和资源ID映射文件
applyMapping = "${projectDir.absolutePath}/RFix/old_mapping.txt"
applyResourceMapping = "${projectDir.absolutePath}/RFix/old_R.txt"

// 开启多架构补丁独立打包功能
enablePackageSeparate = false
// 开启加固包的补丁构建模式
isProtectedApp = false
}
}

2.3 改造 Application 并初始化 SDK

由于热修复引擎需要在应用启动前进行补丁加载,因此需要接管 App 的 Application,这就需要开发者对 App 的 Application 进行改造。

这里我们提供了两种改造方案,开发者可以根据自身需求选择一种即可。

方案一:自动代理业务 Application(推荐)

该方案是接入最简单,改造成本最小的方案,并且兼容 Hilt 这类依赖注入框架,以及无法修改业务现有 Application 继承关系的场景。

  • 第一步:对业务现有的 Application 使用 @ApplicationProxy 注解,并填写自动生成 Application 的类名
  • 第二步:将注解生成的 Application 添加到 AndroidManifest.xml
  • 第三步:在合适的时机初始化 SDK,初始化支持在子线程异步执行
// 注解会自动在目标类所在包下生成代理 Applicaiton
// 该代理 Applicaiton 需要手动配置到 AndroidManifest.xml
@ApplicationProxy(application = ".SampleProxyApplication")
public class SampleApplication extends Application {

@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);

// 初始化RFix组件
initRFix();
}

private void initRFix() {
// 1. 初始化日志接口,用于接出SDK内部输出的日志
RFixLog.setLogImpl(new CustomRFixLog());

// 2. 构造RFix业务参数
RFixParams params = new RFixParams("your_app_id", "your_app_key")
.setDeviceManufacturer(Build.MANUFACTURER) // 设置设备厂商,用于下发规则控制
.setDeviceModel(Build.MODEL) // 设置设备型号,用于下发规则控制
.setUserId("123456") // 设置用户ID,用于下发规则控制
.setCustomProperty("property1", "xxx"); // 设置自定义属性,用于扩展下发规则

// 3. 初始化RFix组件
RFixApplicationLike applicationLike = DefaultRFixApplicationLike.createApplicationLike(this);
RFixInitializer.initialize(applicationLike, params);
}
}

方案二:改造业务 ApplicationApplicationLike(Tinker标准接入方式)

该方案需要开发者改造现有的 Application,侵入性和改造成本都相对较高。

改造后原代码中获取 Application 的方式会发生变化,必须通过 ApplicationLike 对象的 getApplication() 方法获取。

  • 第一步:将业务现有的 Application 直接改为继承自 DefaultRFixApplicationLike
  • 第二步:对该类使用 @ApplicationLike 注解,并填写自动生成 Application 的类名
  • 第三步:将注解生成的 Application 添加到 AndroidManifest.xml
  • 第四部:解决因 Application 切换导致的各处编译和访问异常
// 注解会自动在目标类所在包下生成 Applicaiton
// 该 Applicaiton 需要手动配置到 AndroidManifest.xml
@ApplicationLike(application = ".SampleApplication")
public class SampleApplicationLike extends DefaultRFixApplicationLike {

public SampleApplicationLike(Application application, RFixLoadResult loadResult) {
super(application, loadResult);
}

@Override
public void onBaseContextAttached(Context base) {
super.onBaseContextAttached(base);

// 初始化RFix组件
initRFix();
}

private void initRFix() {
// 1. 初始化日志接口,用于接出SDK内部输出的日志
RFixLog.setLogImpl(new CustomRFixLog());

// 2. 构造RFix业务参数
RFixParams params = new RFixParams("your_app_id", "your_app_key")
.setDeviceManufacturer(Build.MANUFACTURER) // 设置设备厂商,用于下发规则控制
.setDeviceModel(Build.MODEL) // 设置设备型号,用于下发规则控制
.setUserId("123456") // 设置用户ID,用于下发规则控制
.setCustomProperty("property1", "xxx"); // 设置自定义属性,用于扩展下发规则

// 3. 初始化RFix组件
RFixInitializer.initialize(this, params);
}
}

2.4 集成热修复调试页面

为了方便开发者在开发阶段对补丁的功能进行调试,SDK 中内置了一个简单的调试页面 AbsRFixDevActivity

开发者可以在接入时继承该类,实现一个简单的补丁调试页。

public class RFixDevActivity extends AbsRFixDevActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}

在开发调试中,我们可以通过调试页面主动触发配置拉取,并观察补丁的安装结果和加载情况。

热修复调试页面

2.5 SDK 其他功能说明

1. 主动触发拉取补丁

在 SDK 初始化时会自动触发一次远端补丁配置的检查,如果补丁状态有变化,则会自动触发后续的下载、安装、卸载等行为。

如果开发者有特殊的需求,也可以在合适的时机,通过 requestConfig 接口主动触发远端补丁配置检查。

RFix manager = RFix.getInstance();
manager.requestConfig()

2. 监听补丁安装过程

如果开发者有监听补丁安装过程的需求,可以通过注册监听器来实现,目前监听器提供:配置拉取、补丁下载、补丁安装的回调接口。

PS: 开发者可以利用监听器,在补丁首次安装成功时,主动重启进程,以加速补丁的生效速度。

// 在初始化时可以注册回调,以便在各阶段处理业务逻辑
RFixInitializer.initialize(applicationLike, params, new RFixListener() {
@Override
public void onConfig(boolean success, int resultCode, PatchConfig patchConfig) {
// 处理配置
// ...
}
@Override
public void onDownload(boolean success, int resultCode, PatchConfig patchConfig, String patchFilePath) {
// 处理下载文件
// ...
}
@Override
public void onInstall(boolean success, int resultCode, RFixPatchResult patchResult) {
if (success && patchResult.isPatchSuccessFirstTime()) {
// 补丁安装成功,可以记录一个标记,并在合适的时机重启应用,以加快补丁生效速度
// ...
}
}
});

三、制作补丁包

热修复的使用相比其他 SDK 要复杂一些,补丁制作期间可能会遇到较多编译问题,这就需要开发者对 Android 的编译系统有一定的理解。

整个补丁制作过程分为三个环节:

3.1 构建修复目标 old.apk (发布给用户的版本)

在接入 SDK 后,只需要使用项目原来的构建命令进行 Apk 打包即可, 这个阶段我们除了会得到 old.apk 以外,还需要保存本次构建得到的几个中间文件。

  • mapping.txt:代码混淆的映射文件,只有 Release 版本会生成
  • R.txt:资源 ID 的映射文件,Debug/Release 版本都会生成

以上文件我们可以在下列这些位置找到。在获得文件后,我们需要按照 build.gralde 中的配置,将其放到指定的路径上。

// 备份 mapping.txt
from "${buildDir}/outputs/mapping/release/mapping.txt"
into "${projectDir.absolutePath}/RFix/old_mapping.txt"

// 备份 R.txt
// 不同AGP版本下的R.txt位置有差异
from "${buildDir}/intermediates/symbols/release/R.txt"
from "${buildDir}/intermediates/symbol_list/release/R.txt"
from "${buildDir}/intermediates/runtime_symbol_list/release/R.txt"
from "${buildDir}/intermediates/runtime_symbol_list/release/processReleaseResources/R.txt"
into "${projectDir.absolutePath}/RFix/old_R.txt"

3.2 构建修复后的 new.apk (修改代码后的版本)

在配置好 old.apk 及其相关的中间文件后,我们就可以开始修改代码,构建修复后的 new.apk 了,同样只需要使用项目原来的构建命令打包即可。

在获得 new.apk 后,我们同样需要按照 build.gralde 中的配置,将其放到指定的路径上。

PS: 对于开启了 R8 或者 AGP 版本较高项目,在构建 new.apk 时可能遇到 R8 相关的报错,或者构建生成的 new.apk 运行 Crash。这个时候可以尝试去掉 build.gralde 中配置的 applyMapping 参数并重新打包。

3.3 构建修复补丁包 patch.apk

在配置好 old.apknew.apk 及其相关的中间文件后,我们可以执行 ./gradlew RFixBuildRelease 触发补丁包的构建。构建成功后,补丁包可以在 outputFolder 下找到,请使用已签名的版本,因为补丁安装时会检查 patch.apkold.apk 签名是否一致。

如果补丁构建中遇到一些告警,导致补丁构建失败,也可以尝试通过忽略这些告警来生成补丁,但是忽略告警有一定的风险,需要开发者充分评估。

RFixPatch {
// 忽略补丁编译中的告警信息(该功能谨慎开启,忽略某些告警后生成的补丁可能异常)
ignoreWarning = false
}

在成功制作出补丁以后,整个 SDK 接入就基本结束了。接下来开发者可以将 old.apk 安装到设备上,并通过发布平台将补丁包下发到设备上进行验证。

通过发布平台,对补丁包进行发布和验证,请参考:如何使用 Android 热修复

四、热修复示例应用

开发者在接入中如果有遇到一些不理解的地方,也可以参考热修复示例应用。

示例中也有一些简化的接入脚本,可以在接入时进行参考。

Shiply热修复示例应用