阿里热修复Sophix的使用指南 
本文转自五问  并作补充
 
一、阿里云热修复Sophix的介绍 1.1、首先看一下市场上热修复方案的比较: 
https://help.aliyun.com/document_detail/434850.html 
 
1.2、收费情况: 
https://help.aliyun.com/document_detail/434858.html 
 
二、接入指南 2.1、准备 
准备好阿里云账号 
进行身份实名认证 
移动研发平台EMAS ,进行项目创建,创建后会生成一个aliyun-emas-services.json 文件,里面包含了热修复sdk接入时所需的密钥,很重要 
 
 
2.2、EMAS平台的添加流程如下: 2.2.1、添加应用 
生成应用的key信息文件,如果建议按需接入所需功能,没必要也不安全,按下图将文件放入到app中
下图的红框中的添加sdk也是,添加emas平台中的所有功能,建议按需接入某个功能(如:热修),另外该插件在Android gradle 7之上会报错
 
2.3、热修复接入 
https://help.aliyun.com/document_detail/434883.html 
注意点如下: 
使用gradle plugin版本高于4.2时,可能会自动开启资源优化。开启资源优化后,资源名称被混淆,会导致补丁工具在生成补丁时一直卡在”开始构建补丁…..”,无法正常解析apk包。解决方案:在gradle.properties 中新增android.enableResourceOptimizations=false,重新生成基线包和修复包,然后再生成补丁。
密钥的使用推荐在SophixStubApplication 中初始化,而不是在AndroidManifest文件中配置
使用android studio打包生成apk时,要关闭instant run。
queryAndLoadNewPatch方法 用来请求控制台发布的补丁包,会涉及设备信息读取,所以必须在用户同意隐私协议之后调用。另外用户可根据业务情况,酌情考虑是否打开此开关。
但不可放在attachBaseContext中,否则无网络权限,建议放在主进程用户同意隐私协议之后的任意时刻。
接入流程步骤如下:
添加工程依赖 
1. Android Studio集成方式 1 2 3 4 5 6 7 8 9 10 11 12 13 gradle远程仓库依赖, 打开项目找到App的build.gradle文件,添加如下配置: 添加Maven仓库地址: **** `` ` repositories {    maven {        url "http://maven.aliyun.com/nexus/content/repositories/releases"    } } ` `` 
 
2.添加gradle坐标版本依赖: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 android {     ......     defaultConfig {         applicationId "com.xxx.xxx"           ......         ndk {                                       abiFilters 'arm64-v8a' , 'armeabi' , 'armeabi-v7a' , 'x86' , 'x86_64'          }         ......     }     ...... } dependencies {     ......         compile 'com.aliyun.ams:alicloud-android-hotfix:3.3.5'      ...... } 
 
3.添加应用权限 Sophix SDK使用到以下权限,使用Maven依赖或者aar依赖可以不用配置。具体配置在AndroidManifest.xml中。
1 2 3 4 <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" /> 
 
4.配置AndroidManifest文件 也可以不用配置(直接在SophixStubApplication,文件中初始化配置即可(推荐在SophixStubApplication中配置)),在 移动研发平台EMAS ,进行项目创建,创建后会生成一个aliyun-emas-services.json 文件,里面包含了热修复sdk接入时所需的密钥
在AndroidManifest.xml中间的application节点下添加如下配置:
1 2 3 4 5 6 7 8 9 <meta-data android:name ="com.taobao.android.hotfix.IDSECRET"  android:value ="App ID"  /> <meta-data android:name ="com.taobao.android.hotfix.APPSECRET"  android:value ="App Secret"  /> <meta-data android:name ="com.taobao.android.hotfix.RSASECRET"  android:value ="RSA密钥"  /> 
 
5. 混淆配置,按需配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ``` #基线包使用,生成mapping.txt -printmapping mapping.txt #生成的mapping.txt在app/build/outputs/mapping/release路径下,移动到/app路径下 #修复后的项目使用,保证混淆结果一致 #-applymapping mapping.txt #hotfix -keep class  com.taobao.sophix .**{*;} -keep class  com.ta.utdid2.device .**{*;} #防止inline -dontoptimize ``` ** **重要** 开启混淆时,生成修复包要使用旧包的mapping文件以保证混淆结果一致。 初始化 
 
6. 初始化 初始化的调用应该尽可能的早,必须在Application.attachBaseContext()的最开始(在super.attachBaseContext之后,如果有Multidex,也需要在Multidex.install之后)进行SDK初始化操作,初始化之前不能用到其他自定义类,否则极有可能导致崩溃。而查询服务器是否有可用补丁的操作可以在后面的任意地方。不建议在Application.onCreate()中初始化,因为如果带有ContentProvider,就会使得Sophix初始化时机太迟从而引发问题。
Sophix最新版本引入了新的初始化方式。
原来的初始化方式仍然可以使用。只是新方式可以提供更全面的功能修复支持,将会带来以下优点:
初始化与应用原先业务代码完全隔离,使得原先真正的Application可以修复,并且减少了补丁预加载时间等等。 
新方式能够更完美地兼容Android 8.0以后版本。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public  class  SophixStubApplication  extends  SophixApplication  {    private  final  String  TAG  =  "SophixStubApplication" ;     String  appVersion  =  "0.0.0" ;          @SophixEntry(MyApplication.class)      static  class  RealApplicationStub  {     }     @Override      protected  void  attachBaseContext (Context base)  {         super .attachBaseContext(base);         initSophix();     }     private  void  initSophix ()  {         try  {             appVersion = this .getPackageManager()                     .getPackageInfo(this .getPackageName(), 0 )                     .versionName;         } catch  (Exception e) {         }         final  SophixManager  instance  =  SophixManager.getInstance();         List<String> tags = new  ArrayList <>();                           tags.add("test" );          for  (String tag : tags) {             Log.e(TAG, "sophix tag:"  + tag);         }         instance.setContext(this )                 .setAppVersion(appVersion)                 .setEnableDebug(false )                 .setEnableFullLog()                 .setTags(tags)                 .setSecretMetaData("你自己的hotfix.idSecret" ,                         "你自己的emas.appSecret" ,                         "你自己的hotfix.rsaSecret" )                 .setPatchLoadStatusStub(new  PatchLoadStatusListener () {                     @Override                      public  void  onLoad (final  int  mode, final  int  code, final  String info, final  int  handlePatchVersion)  {                         Log.e(TAG, "sophix handlePatchVersion:"  + handlePatchVersion + " /code:"  + code + " /info:"  + info);                         if  (code == PatchStatus.CODE_LOAD_SUCCESS) {                                                          Log.e(TAG, "sophix load patch "  + handlePatchVersion + " success!"  + info);                         } else  if  (code == PatchStatus.CODE_LOAD_RELAUNCH) {                                                                                       Log.e(TAG, "sophix preload patch success. restart app to make effect. handlePatchVersion:"  + handlePatchVersion);                                                        Intent  intent  =  new  Intent ();                             intent.putExtra("message" , "恭喜你,成功接收到发送的广播"  + PatchStatus.CODE_LOAD_RELAUNCH);                             intent.setAction("可使用重启广播重启" );                             sendBroadcast(intent);                         }                     }                 }).initialize();     } } 
 
7.最后,需要把AndroidManifest里面的application改为这个新增的SophixStubApplication类: 1 2 3 4 <application         android:name="com.my.pkg.SophixStubApplication"         ... ...>         ... ... 
 
这样便完成了新方式的初始化接入改造。
 
三、热修复打差量包流程 热修控制台地址 
https://emas.console.aliyun.com/service/devTool/hotfix/patch 
 
3.1、找到热修界面添加应用 
如下图:注意 应用版本必须与你的versionName一致,否则会导致后续下发查找不到差量包
 
3.2、打差量包 
https://help.aliyun.com/document_detail/434864.html 
准备好SophixPatchTool_windows打包工具各版本打包工具如下: 
 
打一个release的包 
再第2步的release包的基础上修改一些内容,在打一个release包 
利用工具开始打包,如下图 
 
注意:  每次热修差量包的生成的基础包就是你上次发版后的包,并不是说你在进行第三次热修时,用第二次的热修包,作为基准包
问题包:1.0-querelease-2022-12-07.apk,修复包:1.0-release-2022-12-07.apk
打开工具:
选择两个包填充
选择设置填好keystore
选择高级,默认如下图,强制冷启动就是补丁包下发后必须重启,建议勾选强制冷启动,为何:看下面解释
Sophix何时走即时生效热修复,何时走冷启动修复?https://help.aliyun.com/document_detail/53227.htm?spm=5176.2020520104.0.0.385a3f1bbai0Ta#topic-1993907 
配置完成后点击Go开始打差量包
成功
sophix-patch.jar 就是打出的差量包
 
四、上传补丁-发布 4.1、添加你的应用版本,然后上传补丁 
 
4.2、发布补丁 
上传后点击发布如下图
下载[hotfixdebug]工具验证你的补丁包是否成功,调试流程原文如下链接:
https://help.aliyun.com/document_detail/434866.html 
调试没问题后点击上图的新建发布
发布的话:有全量,灰度两种,灰度的话 ,需要设置指定标签tag,就是你的应用app中Sophix所配置的,如下图:(推荐是全量)
 
4.3、发布成功后在app中调用查询补丁方法 
SophixManager.getInstance().queryAndLoadNewPatch()后续将回调PatchLoadStatusListener如下图
依次出现热修状态码如下,状态码含义:
https://help.aliyun.com/document_detail/434886.html?spm=a2c4g.11186623.0.0.6cdf4b0cnRYOiA 
上图加载成功后提示需要重启后热修生效 
 
五、测试用例 
1.  修改一个toast文案,然后修复成功。
2.  修改一张图片,增加一张新的图片进行展示,增加点击效果,增加一个新的类生成提示文案(mipmap-hdpi、drawable-xhdpi、drawable、都添加图片)
drawable-xhdpi 中新增热修图片添加可能会存在问题:如下,然后按要求在drawable 中添加后,热修成功。
https://help.aliyun.com/document_detail/338384.html 
3.  添加assets文件,热修成功。 
4.  四大组件不行,因为需要在AndroidManifest.xml文件中配置,热修的时候使用的话会报找不到的,需要注册异常,如下图
5.  删除测试4中的组件跳转流程,热修测试成功,
6.  删除测试2中添加的xml中的代码与相关资源,热修测试成功
注意:
 1.热修包存在的话,每杀死app,初始化进来都会走
1 2 3 onLoad方法的回调 code  == PatchStatus.CODE_LOAD_SUCCESS
 
2.同一个热修包,设置不同的tag,然后点击下发的话都会下发一次
3.清除热修包后,之前发布的版本都无效了,再次查询加载,都查不到了,只能之后在这个版本重新发布
1 SophixManager.getInstance ().cleanPatches () 
 
热修复书籍:https://developer.aliyun.com/article/115122