视频说明 (如不能全屏或播放,请点击,查看视频

HotFix集成视频Android

1.1 Android SDK及工具下载

请前往文档SDK下载&版本更新记录里下载“Android SDK”、“Android Demo工程”、“Android打包工具”和“Android调试工具”。如有任何疑问请加入钉钉群咨询。

Demo工程目录说明

  • 根目录下README.md整个demo工程的说明, 包含高级调试技巧, 务必请仔细阅读
  • patchtool_demo目录下示例了打补丁工具使用方法
  • BaseBug.md文件包含hotfix修复的详细说明, 务必请仔细阅读

1.2 集成准备

1.2.1 android studio集成方式

gradle远程仓库依赖, 打开项目找到app的build.gradle文件,添加如下配置:

添加maven仓库地址:

repositories {
   maven {
       url "http://repo.baichuan-android.taobao.com/content/groups/BaichuanRepositories"
   }
}

注意: 1.4.0版本的仓库地址已经发生了变更, 请更新到上述百川最新的仓库地址

添加gradle坐标版本依赖:

dependencies {
    compile 'com.taobao.android:alisdk-hotfix:1.4.0'
}

跟其它版本不一样的地方, 1.4.0版本会传递性依赖utdid这个sdk, 所以不需要重复依赖.但是另一方面其它阿里系SDK也可能依赖了utdid这个SDK, 如果编译期间报utdid重复, 所以此时进行如下处理即可, 关闭传递性依赖:

compile ('com.taobao.android:alisdk-hotfix:1.4.0') {
        transitive = false
    }

utdid实际上是为设备生成唯一deviceid的一个基础类库

如若仓库访问失败, 那么用本地依赖的方式进行依赖, SDK下载见“1.1 Android SDK及工具下载”节, 首先复制下载SDK文件夹下的.aar和.jar到libs目录下, 然后更新模块下的build.gradle文件

repositories {
    ...
    flatDir {
        dirs 'libs'
    }
}
dependencies {
    compile files('libs/utdid4all-1.1.5.3_proguard.jar')
    compile(name:'alisdk-hotfix-1.4.0', ext:'aar')  
}

编译期间报utdid重复, 去掉compile files('libs/utdid4all-1.1.5.3_proguard.jar')依赖即可

¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

1.2.2 eclipse集成方式

  • 下载SDK文件夹下的alisdk-hotfix-1.4.0.aar文件后解压
  • 复制jni/armeabi目录下的libandfix.so到自己的jni/armeabi目录下, eclipse jni目录一般指的就是项目libs目录
  • 复制utdid4all-1.1.5.3_proguard.jar文件到项目libs目录下
  • 重命名classes.jar为alisdk-hotfix-1.4.0.jar并复制到项目libs目录下
  • 合并AndroidManifest.xml文件中的内容到本项目AndroidManifest.xml文件

编译期间报utdid类重复异常, 那么步骤2中添加的utdid4all-1.1.5.3_proguard.jar从项目libs目录移除即可

¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

1.2.3 权限说明

HotFix SDK使用到以下权限

<! -- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<! -- 外部存储读权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

READ_EXTERNAL_STORAGE/ACCESS_WIFI_STATE权限属于Dangerous Permissions,自行做好android6.0以上的运行时权限获取

¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

1.2.4 配置AndroidManifest文件

AndroidManifest.xml中间的application节点下添加如下配置:

<meta-data
android:name="com.taobao.android.hotfix.APPSECRET"
android:value="your-app-secret" />
<meta-data
android:name="com.taobao.android.hotfix.RSASECRET"
android:value="your-rsa-secret" />

将上述value中的值分别改为通过百川平台HotFix服务申请得到的App Secret和RSA密钥。
如何得到应用的AppSecretRSASecret? 请查询获取SDK配置信息

¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

1.2.5 混淆配置

-keep class * extends java.lang.annotation.Annotation
-keepclasseswithmembernames class * {
    native <methods>;
}
-keep class com.alipay.euler.andfix.**{
    *;
}
-keep class com.taobao.hotfix.aidl.**{*;}
-keep class com.ta.utdid2.device.**{*;}
-keep class com.taobao.hotfix.HotFixManager{
    public *;
}

¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

1.2.6 特别申明

不管是android studio/eclipse集成方式都务必做如下检查! 否则将抛UnsatisfiedLinkError异常导致补丁加载失败

检查当前项目结构jniLibs中是否有armeabi-v7a, arm64-v8a目录, 如果有: 请复制下载SDK(SDK下载&版本更新记录里“SDK”项下载下来, 然后解压)文件夹中armeabi-v7a/arm64-v8a目录下对应的so文件到对应的文件夹下面. 如果没有armeabi-v7a/arm64-v8a目录, 则不需要做这个处理。

PS:hotfix这样处理的目的: 减少jar包大小进而减少apk大小. 所以alisdk-hotfix-**.aar中只有armeabi下的libandfix.so文件, 所以如果当前项目目录下有armeabi-v7a/arm64-v8a目录, 但是没有复制对应的libandfix.so文件进去, 那么在相应cpu架构的机型下加载libandfix.so就会报找不到so文件的异常(UnsatisfiedLinkError)

如果做了上述处理仍然发现UnsatisfiedLinkError异常, 那么请确保是否是打包引起的问题, 解压apk, 看libs下armeabi-v7a/arm64-v8a目录是否有对应的libandfix.so文件

1.3 SDK接口使用说明

1.3.1 接入范例

initialize的调用应该尽可能的早. 强烈推荐在Application.onCreate()中进行SDk初始化以及查询服务器是否有可用补丁的操作.

HotFixManager.getInstance().setContext(this)
                .setAppVersion(appVersion)
                .setAppId(appId)
                .setAesKey(null)
                .setSupportHotpatch(true)
                .setEnableDebug(true)
                .setPatchLoadStatusStub(new PatchLoadStatusListener() {
                    @Override
                    public void onload(final int mode, final int code, final String info, final int handlePatchVersion) {
                        // 补丁加载回调通知
                        if (code == PatchStatusCode.CODE_SUCCESS_LOAD) {
                            // TODO: 10/24/16 表明补丁加载成功
                        } else if (code == PatchStatusCode.CODE_ERROR_NEEDRESTART) {
                            // TODO: 10/24/16 表明新补丁生效需要重启. 业务方可自行实现逻辑, 提示用户或者强制重启, 建议: 用户可以监听进入后台事件, 然后应用自杀
                        } else if (code == PatchStatusCode.CODE_ERROR_INNERENGINEFAIL) {
                            // 内部引擎加载异常, 推荐此时清空本地补丁, 但是不清空本地版本号, 防止失败补丁重复加载
                            //HotFixManager.getInstance().cleanPatches(false);
                        } else {
                            // TODO: 10/25/16 其它错误信息, 查看PatchStatusCode类说明
                        }
                    }
                }).initialize();

initialize()方法内部会强制调用queryNewHotPatch()方法, 所以此处不需要额外再调用queryNewHotPatch()方法

¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

1.3.2 接口说明

1.3.2.1 initialize方法

该方法主要做些必要的初始化工作以及如果本地有补丁的话会加载补丁, 所以需要尽可能的早, 推荐在Application的onCreate方法中调用, 由于initialize方法参数越来越多变的原来越臃肿, 所以1.4.0版本修改了调用方式, initialize()方法调用之前你需要先调用如下几个方法, 方法调用说明如下:

  • setContext(this): Application上下文context 必选
  • setAppVersion(appVersion): 应用的版本号 必选
  • setAppId(appId): 百川上应用的唯一标识, 如何获取请查询获取SDK配置信息 必选
  • setAesKey(必须16位): 用户自定义aes秘钥, 此时平台无感知这个秘钥, 所以不用担心百川平台会利用你们的补丁做一些非法的事情. 这个参数值必须配合补丁工具的-y参数一起使用, 具体使用参见«Part2 生成patch补丁»的说明, 两者的值需要保持一致, 补丁才能正确被解密进而加载. 可选
  • setSupportHotpatch(true/false): 目前的版本热修复方案采用类似andfix本地hook方法方法所以热部署有一定的风险(方法正在被运行然后被patch了可能会导致native层的crash). 用户如果有实时生效的需求以及被patch的方法没有被高频调用那么这个参数可以设置为true. 第一个补丁将会即时生效 可选
  • setEnableDebug(true/false): 是否调试模式, 调试模式下会输出日志以及不进行补丁签名校验. 线下调试此参数可以设置为true, 查看日志过滤TAG:BCHotfix, 同时强制不对补丁进行签名校验, 所有就算补丁未签名或者签名失败也发现可以加载成功. 但是正式发布该参数必须设置为false, 需要对补丁签名校验, 否则就可能存在安全漏洞风险 可选
  • setPatchLoadStatusStub(new PatchLoadStatusListener()): 设置patch加载状态监听器, 该方法参数需要实现PatchLoadStatusListener接口, 接口说明见1.3.2.2说明 可选
  • initialize(): sdk初始化方法 必选

1.3.2.2 PatchLoadStatusListener接口

该接口需要自行实现并传入initialize方法中, 补丁加载状态会回调给该接口, 参数说明如下:

  • mode: 补丁模式, 0:正常请求模式 1:扫码模式 2:本地补丁模式
  • code: 补丁加载状态码, 详情查看PatchStatusCode类说明
  • info: 补丁加载详细说明, 详情查看PatchStatusCode类说明
  • handlePatchVersion: 当前处理的补丁版本号, 0:无 -1:本地补丁 其它:后台补丁

这里列举几个常见的code码说明, 详情查看SDK中PatchStatusCode类说明

  • code: 1 补丁加载成功
  • code: 6 服务端没有最新可用的补丁
  • code: 11 RSASECRET错误,官网中的密钥是否正确请检查
  • code: 12 当前应用已经存在一个旧补丁, 应用重启尝试加载新补丁
  • code: 13 补丁加载失败, 导致的原因很多种, 比如UnsatisfiedLinkError等异常, 此时应该严格检查logcat异常日志
  • code: 16 APPSECRET错误,官网中的密钥是否正确请检查
  • code: 18 一键清除补丁
  • code: 403 签名不匹配,可能是APPID APPSECRET填错,请检测

1.3.2.3 queryNewHotPatch方法

该方法主要用于查询服务器是否有新的可用补丁. 首先initialize()方法内部会强制调用queryNewHotPatch()方法, 所以initialize()方法调用之后不需要再调用这个方法, 但是你可以在其它你需要的地方调用. 同时SDK内部限制连续两次queryNewHotPatch()方法调用不能短于3s, 否则的话就会报code:19的错误码. 如果查询到可用的话, 首先下载补丁到本地, 然后

  • 应用原本没有补丁, 那么第一个补丁会立刻加载
  • 应用已经存在一个补丁, 首先会把之前的补丁文件删除, 然后不立刻加载, 而是等待下次应用重启再加载该补丁
    补丁在后台发布之后, 并不会主动下行推送到客户端, 需要手动调用queryNewHotPatch方法查询后台补丁是否可用.
  • 只会下载补丁版本号比当前应用存在的补丁版本号高的补丁, 比如当前应用已经下载了版本号为5的补丁, 那么只有后台发布的补丁版本号>5才会重新下载.

同时1.4.0版本服务后台上线了“一键清除”补丁的功能, 所以如果后台点击了“一键清除”那么这个方法将会返回code:18的状态码. 此时本地补丁将会被强制清除, 同时不清除本地补丁版本号

1.3.2.4 cleanPatches(boolean force)方法

参数force表示是否强制清空本地补丁版本号, 比如当前本地补丁版本号是10, 那么下次再次调用queryNewHotPatch方法时, 如果该参数为false: 不清除本地补丁版本号那么后台最新的补丁1就不会重新下载, 当然如果存在比10大的补丁版本仍然是可以下载下来的. 如果该参数为true: 清除本地补丁版本号, 本地补丁版本号将会被设置为0, 所以后台只要有任何发布的补丁都能够下载下来.

1.4 版本管理说明

说明一:patch是针对客户端具体某个版本的,patch和具体版本绑定

  • eg. 应用当前版本号是1.1.0, 那么只能在后台查询到1.1.0版本对应发布的补丁, 而查询不到之前1.0.0旧版本发布的补丁.

说明二:针对某个具体版本发布的新补丁, 必须包含所有的bugfix, 而不能依赖补丁递增修复的方式, 因为应用仅可能加载一个补丁

  • eg. 针对1.0.0版本在后台发布了一个补丁版本号为1的补丁修复了bug1, 然后发现此时针对这个版本补丁1修复的不完全, 代码还有bug2, 在后台重新发布一个补丁版本号为2的补丁, 那么此时补丁2就必须同时包含bug1和bug2的修复才行, 而不是只包含bug2的修复(bug1就没被修复了)

FAQ

关于此文档暂时还没有FAQ
返回
顶部