目前的热修复框架,最强大的当属阿里的Sophix了,虽然是收费,但对于小众的APP来说,很可能不会超过免费的阀值(每月5万台设备免费,每台设备每天20次免费查询补丁),再说也不妨碍我们研究下怎么用,听说用起来很方便,对程序员几乎是傻瓜式的,对我来说这点就是极大的诱惑了。事实证明,Sophix确实非常简单易用,根本不需要关心补丁怎么下载,怎么放置,怎么替换,整个流程只需要一个接口调用,补丁制作也为开发人员准备好了工具。Sophix对比其他框架的优势在哪里,上一张官网给出的图就很直观了:

真逗,还给别人家的打了**,我替它写出来好了,Amigo,Tinker,QQZone,Robust。接下来就看下怎么用吧(可能会有人奇怪为什么都有官网了,还要多此一举,知道的都知道,很多平台的技术文档详细是挺详细,就是经常会让你点击各种链接,跳来跳去的很烦)。

1、准备工作

1、注册、登录、新建产品等

进入阿里云注册和登录等,然后进入移动研发平台新建产品,成功之后获取到appKey和appSecret和RSA等以及一个aliyun-emas-services.json的配置文件,该文件包含了appKey、appSecret以及阿里的emas服务类型、状态和版本号等信息,例如:

"services": {"httpdns_service": {"status": 0,"version":"1.2.1"},"cps_service": {"status": 0,"version":"3.1.4"},"hotfix_service": {"status": 1,"version":"3.2.6"},"man_service": {"status": 0,"version":"1.2.4"},"feedback_service": {"status": 0,"version":"3.1.8"}}

status表示是否开通此服务,0为关闭,1为开通,这里我只开通了hotfix_service,即热修复服务。将该文件放入项目的app模块根目录当中,接下来是对项目进行配置,其中会有插件对该文件进行解析。

2、项目配置

在项目根目录的build.gradle文件当中加入或合并如下内容:

buildscript {repositories {maven {url 'http://maven.aliyun.com/nexus/content/repositories/releases/'}}dependencies {// 添加emas-services插件classpath 'com.aliyun.ams:emas-services:1.0.1'}
}allprojects {repositories {maven {url 'http://maven.aliyun.com/nexus/content/repositories/releases/'}}
}

在app模块的build.gradle文件当中加入或合并如下内容:

apply plugin: 'com.aliyun.ams.emas-services'
dependencies {implementation 'com.aliyun.ams:alicloud-android-hotfix:3.2.6'
}
repositories {maven {url "http://maven.aliyun.com/nexus/content/repositories/releases"}
}

在AndroidManifest.xml文件当中加入配置:

        <meta-dataandroid:name="com.taobao.android.hotfix.IDSECRET"android:value="your appkey" /><meta-dataandroid:name="com.taobao.android.hotfix.APPSECRET"android:value="your appsecret" /><meta-dataandroid:name="com.taobao.android.hotfix.RSASECRET"android:value="your rsa" />

记住替换下相应的value。

2、接口接入

1、入口及回调接口

package com.qugengting.hotfixdemo;import android.content.Context;
import android.support.annotation.Keep;
import android.util.Log;import com.taobao.sophix.PatchStatus;
import com.taobao.sophix.SophixApplication;
import com.taobao.sophix.SophixEntry;
import com.taobao.sophix.SophixManager;
import com.taobao.sophix.listener.PatchLoadStatusListener;/*** Sophix入口类,专门用于初始化Sophix,不应包含任何业务逻辑。* 此类必须继承自SophixApplication,onCreate方法不需要实现。* 此类不应与项目中的其他类有任何互相调用的逻辑,必须完全做到隔离。* AndroidManifest中设置application为此类,而SophixEntry中设为原先Application类。* 注意原先Application里不需要再重复初始化Sophix,并且需要避免混淆原先Application类。* 如有其它自定义改造,请咨询官方后妥善处理。*/
public class SophixStubApplication extends SophixApplication {private final String TAG = "SophixStubApplication";public interface MsgDisplayListener {void handle(String msg);}public static MsgDisplayListener msgDisplayListener = null;public static StringBuilder cacheMsg = new StringBuilder();// 此处SophixEntry应指定真正的Application,并且保证RealApplicationStub类名不被混淆。@Keep@SophixEntry(MyApp.class)static class RealApplicationStub {}@Overrideprotected void attachBaseContext(Context base) {super.attachBaseContext(base);
//         如果需要使用MultiDex,需要在此处调用。
//         MultiDex.install(this);initSophix();}private void initSophix() {String appVersion = "0.0.0";try {appVersion = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName;} catch (Exception e) {}final SophixManager instance = SophixManager.getInstance();instance.setContext(this).setAppVersion(appVersion).setSecretMetaData(null, null, null).setEnableDebug(true).setEnableFullLog().setPatchLoadStatusStub(new PatchLoadStatusListener() {@Overridepublic void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {if (code == PatchStatus.CODE_LOAD_SUCCESS) {Log.i(TAG, "sophix load patch success!");} else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {// 如果需要在后台重启,建议此处用SharePreference保存状态。Log.i(TAG, "sophix preload patch success. restart app to make effect.");}String msg = new StringBuilder("").append("Mode:").append(mode).append(" Code:").append(code).append(" Info:").append(info).append(" HandlePatchVersion:").append(handlePatchVersion).toString();if (msgDisplayListener != null) {msgDisplayListener.handle(msg);} else {cacheMsg.append("\n").append(msg);}}}).initialize();}
}

注释写的很详细了,再稍微描述一下,AndroidManifest.xml里面的application:name要指定该类即SophixStubApplication,原来的application类配置在这个类的@SophixEntry注解里面即可,PatchLoadStatusListener是回调接口,如果有补丁加载什么的,就会回调onLoad方法了,当然,补丁不会自动下发,需要主动去拉取。我这里参考了官方的DEMO,自定义一个接口MsgDisplayListener便于DEMO演示,当然这个接口不是必须的。

2、拉取补丁

拉取补丁是非常简单的,只有一行代码:

SophixManager.getInstance().queryAndLoadNewPatch();

如果拉取成功(PatchLoadStatusListener接口回调,code参数值符合预期),那么恭喜,补丁已经补好了!只要重启APP就可以看到补丁的效果了。

顺便放上我的MainActivity代码好了:

package com.qugengting.hotfixdemo;import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;import com.taobao.sophix.SophixManager;public class MainActivity extends AppCompatActivity {private static final int REQUEST_EXTERNAL_STORAGE_PERMISSION = 0;private TextView mStatusTv;private String mStatusStr = "";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mStatusTv = findViewById(R.id.tv_status);updateConsole(SophixStubApplication.cacheMsg.toString());if (Build.VERSION.SDK_INT >= 23) {requestExternalStoragePermission();}SophixStubApplication.msgDisplayListener = new SophixStubApplication.MsgDisplayListener() {@Overridepublic void handle(final String msg) {runOnUiThread(new Runnable() {@Overridepublic void run() {updateConsole(msg);}});}};}/*** 如果本地补丁放在了外部存储卡中, 6.0以上需要申请读外部存储卡权限才能够使用. 应用内部存储则不受影响*/private void requestExternalStoragePermission() {if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},REQUEST_EXTERNAL_STORAGE_PERMISSION);}}@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {switch (requestCode) {case REQUEST_EXTERNAL_STORAGE_PERMISSION:if (grantResults.length <= 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {updateConsole("local external storage patch is invalid as not read external storage permission");}break;default:}}/*** 更新监控台的输出信息** @param content 更新内容*/private void updateConsole(String content) {mStatusStr += content + "\n";if (mStatusTv != null) {mStatusTv.setText(mStatusStr);}}public void onClick(View view) {SophixManager.getInstance().queryAndLoadNewPatch();}}

这里也是参考了官方的DEMO写的,不想看的可直接看第三部分,如何制作、上传和发布补丁。

3、制作、上传和发布补丁

1、制作补丁

首先,准备好数字证书,编译release版本,安装到手机上,随便修改下代码表示修复的内容(我这里是替换了下资源文件)再编译一个新的release版本,从官网下载补丁工具:

Mac版本打包工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_macos.zip

Windows版本打包工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_windows.zip

Linux版本打包工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_linux.zip

解压运行,弹出框:

设置界面需要设置下,然后就可以GO了!然而,我这里遇到了问题,本地JDK版本有旧版本残留,虽然在DOS执行java -version是正常的显示1.8版本,但是该工具执行就是会报错,先是报了“has value '1.8', but '1.6' is required”,后来改了改又报了could not open jvm.cfg的错误,找了半天解决办法才找到,如果有同样遇到的可以参考该文章。补丁终于生成了:

接下来就是上传到后台了。

2、上传补丁

移步控制台,选择对应产品,选择移动热修复-补丁管理-添加版本(记住,补丁的版本设置跟你当前手机安装的APP版本一致,我手机安装的版本是1.0.0,刚开始我以为补丁版本号要加1,即1.0.1,结果发布后拉取补丁并没有拉取到,所以这里的版本只需设置1.0.0即可),然后上传补丁:

3、发布补丁

点击上图的详情进入下一界面,点击新建发布即可。这样,补丁就成功发布了!手机端拉取下就可以下载补丁了!

4、其他

少不了说下混淆了:

#基线包使用,生成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

另外记得application类,避免混淆。

最后,再看看运行效果:

加载补丁前后(图一是初始状态,图二是加载补丁成功,图三是重启后效果):

我上传了代码到github,内容有所改动不过没关系,需要的可以去copy。

最后的最后,补上回调的code官方说明吧:

//兼容老版本的code说明
    int CODE_LOAD_SUCCESS = 1;//加载阶段, 成功
    int CODE_ERR_INBLACKLIST = 4;//加载阶段, 失败设备不支持
    int CODE_REQ_NOUPDATE = 6;//查询阶段, 没有发布新补丁
    int CODE_REQ_NOTNEWEST = 7;//查询阶段, 补丁不是最新的 
    int CODE_DOWNLOAD_SUCCESS = 9;//查询阶段, 补丁下载成功
    int CODE_DOWNLOAD_BROKEN = 10;//查询阶段, 补丁文件损坏下载失败
    int CODE_UNZIP_FAIL = 11;//查询阶段, 补丁解密失败
    int CODE_LOAD_RELAUNCH = 12;//预加载阶段, 需要重启
    int CODE_REQ_APPIDERR = 15;//查询阶段, appid异常
    int CODE_REQ_SIGNERR = 16;//查询阶段, 签名异常
    int CODE_REQ_UNAVAIABLE = 17;//查询阶段, 系统无效
    int CODE_REQ_SYSTEMERR = 22;//查询阶段, 系统异常
    int CODE_REQ_CLEARPATCH = 18;//查询阶段, 一键清除补丁
    int CODE_PATCH_INVAILD = 20;//加载阶段, 补丁格式非法
    //查询阶段的code说明
    int CODE_QUERY_UNDEFINED = 31;//未定义异常
    int CODE_QUERY_CONNECT = 32;//连接异常
    int CODE_QUERY_STREAM = 33;//流异常
    int CODE_QUERY_EMPTY = 34;//请求空异常
    int CODE_QUERY_BROKEN = 35;//请求完整性校验失败异常
    int CODE_QUERY_PARSE = 36;//请求解析异常
    int CODE_QUERY_LACK = 37;//请求缺少必要参数异常
    //预加载阶段的code说明
    int CODE_PRELOAD_SUCCESS = 100;//预加载成功
    int CODE_PRELOAD_UNDEFINED = 101;//未定义异常
    int CODE_PRELOAD_HANDLE_DEX = 102;//dex加载异常
    int CODE_PRELOAD_NOT_ZIP_FORMAT = 103;//基线dex非zip格式异常
    int CODE_PRELOAD_REMOVE_BASEDEX = 105;//基线dex处理异常
    //加载阶段的code说明 分三部分dex加载, resource加载, lib加载
    //dex加载
    int CODE_LOAD_UNDEFINED = 71;//未定义异常
    int CODE_LOAD_AES_DECRYPT = 72;//aes对称解密异常
    int CODE_LOAD_MFITEM = 73;//补丁SOPHIX.MF文件解析异常
    int CODE_LOAD_COPY_FILE = 74;//补丁拷贝异常
    int CODE_LOAD_SIGNATURE = 75;//补丁签名校验异常
    int CODE_LOAD_SOPHIX_VERSION = 76;//补丁和补丁工具版本不一致异常
    int CODE_LOAD_NOT_ZIP_FORMAT = 77;//补丁zip解析异常
    int CODE_LOAD_DELETE_OPT = 80;//删除无效odex文件异常
    int CODE_LOAD_HANDLE_DEX = 81;//加载dex异常
    // 反射调用异常
    int CODE_LOAD_FIND_CLASS = 82;
    int CODE_LOAD_FIND_CONSTRUCTOR = 83;
    int CODE_LOAD_FIND_METHOD = 84;
    int CODE_LOAD_FIND_FIELD = 85;
    int CODE_LOAD_ILLEGAL_ACCESS = 86;
    //resource加载
    public static final int CODE_LOAD_RES_ADDASSERTPATH = 123;//新增资源补丁包异常
    //lib加载
    int CODE_LOAD_LIB_UNDEFINED = 131;//未定义异常
    int CODE_LOAD_LIB_CPUABIS = 132;//获取primaryCpuAbis异常
    int CODE_LOAD_LIB_JSON = 133;//json格式异常
    int CODE_LOAD_LIB_LOST = 134;//lib库不完整异常
    int CODE_LOAD_LIB_UNZIP = 135;//解压异常
    int CODE_LOAD_LIB_INJECT = 136;//注入异常

最后的最后的最后,经过我反复测试,发现官网所说的支持热启动并不是事实,覆盖补丁之后,不仅需要重启,而且是需要杀掉进程的那种重启,补丁才能生效。(后来遇到一次不需要重启的了,我凌乱了,还没抓住规律)

阿里Sophix热修复框架使用入门相关推荐

  1. 阿里SopHix热修复框架

    2015年以来,Android开发领域里对热修复技术的讨论和分享越来越多,同时也出现了一些不同的解决方案,如QQ空间补丁方案.阿里AndFix以及微信Tinker(Bugly sdk也集成Tikner ...

  2. 阿里Sophix热修复体验

    前言: 之前看了关于热修复的相关文章,想找个代码试试,奈何感觉使用起来有些麻烦,之后就不了了之.看到了阿里的Sophix,嗯,感觉不那么复杂,步骤简单,就着手自己敲了敲.主要记录下自己找了很久,费时步 ...

  3. 阿里移动热修复Sophix使用体验

    2019独角兽企业重金招聘Python工程师标准>>> Android 热修复是个热门技术,各大公司都推出了自己的热修复框架,阿里也推出了全新的Sophix,我决定写个Demo 测试 ...

  4. 阿里云热修复sophix详解

    现在网上有几种常用的app热修复技术,个人感觉阿里云热修复操作比较简单,主要几个步骤,创建app---下载sdk---集成(AS和eclipse)---生成补丁---发布补丁(可以本地调试).下面详细 ...

  5. 深入解析阿里Android热修复技术原理

    前言:本文框架 什么是热修复? 热修复框架分类 技术原理及特点 Tinker框架解析 各框架对比图 总结 通过阅读本文,你会对热修复技术有更深的认知,本文会列出各类框架的优缺点以及技术原理,文章末尾简 ...

  6. Android—常用热修复框架

    前言 热修复即<打补丁>,当一个app上线后,如果发现重大的bug,需要紧急修复.常规的做法是修复bug,然后重新打包,再上线到各个渠道.这种方式的成本高,效率低. 于是热修复技术应运而生 ...

  7. Android之热修复框架Nuwa

    转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/70284239 本文出自:[顾林海的博客] ##前言 当热修复框架还没出 ...

  8. 热修复框架Tinker的从0到集成之路(转)

    转自:http://blog.csdn.net/lisdye2/article/details/54411727 热修复框架Tinker的从0到集成之路 转载请标明出处:  http://blog.c ...

  9. 【Android 热修复】热修复原理 ( 热修复框架简介 | 将 Java 字节码文件打包到 Dex 文件 )

    文章目录 一. 热修复框架简介 1.类替换 2.so 替换 3.资源替换 4.全平台支持 5.生效时间 6.性能损耗 7.总结 二. 将 Java 字节码文件打包到 Dex 文件 一. 热修复框架简介 ...

  10. 热修复框架AndFix【源码阅读】

    前言 AndFix是阿里巴巴开源的Android热修复框架.其基本原理是利用JNI来实现方法的替换,以实现Android APP的热修复,即无需发版即可临时修复在线BUG. 热修复技术有很多种,And ...

最新文章

  1. 从严把控_精准把控 推动从严治党走深走实
  2. mysql查询语句判断日期_mysql语句查询时间检测
  3. Egret note
  4. 从“学徒”(Apprentice III)看领导力(9-17集)
  5. 攻防比赛_2020年度泉州市大学生网络安全攻防比赛在黎明职业大学圆满落幕
  6. Android系统(2)---init.rc知识
  7. 计算机通信与专业英语翻译,电子信息与通信工程专业英语王立琦版课文翻译
  8. 定时任务_定时任务Quartz入门
  9. linux project 软件下载,项目计划管理画甘特图工具Ganttproject安装(for linux)
  10. java映射的概念_Java之路:映射(Map)
  11. 00001__伊丽莎白福尔摩斯
  12. 多目标人工秃鹫优化算法(MATLAB源码分享,智能优化算法) 提出了一种多目标版本的人工秃鹫优化算法(AVOA)
  13. 如何快速学习flex
  14. MUI 调用原生方法跳转QQ添加群
  15. 聊聊短信接口攻击的防范方案
  16. php artisan migrate,PHP artisan迁移不创建新表
  17. WinInet编程中如何使用异步
  18. 帮助计算机网络犯罪活动罪司法解释,帮助信息网络犯罪活动罪司法适用研究
  19. 了解vue中的v-model,通俗易懂!
  20. 恶搞!关闭程序进程!!嘿嘿嘿~

热门文章

  1. OpenCV 安装配置 Jupyter Notebook
  2. DBSCAN聚类算法原理总结
  3. python 读取excel表内容:以获取高铁站点经纬度为例子
  4. 深度学习入门-基于python的理论与实现-深度学习
  5. 移动端h5原生分享到朋友圈、微博等
  6. 计算机找不到海信电视,海信电视到底怎么投屏,看这一篇就够了!
  7. 程序员课外拓展004:Photoshop CC 2018详细图文安装教程
  8. fgo国服登陆显示服务器错误,命运冠位指定安装失败怎么办 FGO国服安装失败解决办法...
  9. 基于Java内置的HttpServer实现轻量级Restful
  10. pdf批量添加图章_还没找到适合自己的PDF阅读器吗,它来了