一.作用
上架后app出现重大问题,需要及时修复,但是重新上架版本需要时间成本,而且用户体验也不好,可以通过热修复手段修复bug。
二.阿里AndFix介绍
市面上流行的Android热修复工具对比如下,根据实际需要选择了AndFix。
想了解更多细节可参考我转载的另一篇文章http://blog.csdn.net/u010452083/article/details/78729832
优点:
重大bug,需要紧急修复
可以下次迭代修复的bug
影响用户体验的行为
无需重启
缺点:
- 无法添加新类(内部类也不行)和新的字段、新的方法?自己试了方法可以
- 资源文件无法替换 试了下换原有的图片可以,但是新增的不行
- 不能修改xml布局文件 不能
- 加固后的包补丁无法使用,如果要加固,需要加固前的包来生成补丁,不过这样生成的补丁也很容易破解
- 不能对同一个方法修复两次,否则App根本跑不起来
- 对加载过的补丁文件要做名字修改 如果名字重叠 就不会再次加载
三.准备工作
官方项目地址https://github.com/alibaba/AndFix,使用方法可参考官方介绍。
下载补丁生成工具https://github.com/alibaba/AndFix/raw/master/tools/apkpatch-1.0.3.zip
四.实现
为了实现方便,我们采取将补丁放到SD卡(省略了从云端下载补丁过程),然后app从SD卡读取并更新补丁。
1.Android Studio中新建测试工程:AndFixTest,布局文件中我们加入两个Button,第一button用于实现补丁更新,第二个button用于展示补丁更新前后效果(未安装补丁前显示“嘤嘤嘤”,更新补丁后显示“哈哈哈”)
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { mBt = (Button) findViewById(R.id.bt); mBt.setOnClickListener(this); mUpdate = (Button) findViewById(R.id.update); mUpdate.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { default: break; case R.id.bt: Toast.makeText(this, "嘤嘤嘤", Toast.LENGTH_SHORT).show(); break; case R.id.update: update(); break; } }布局文件,并且要在gradle中加入依赖库
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/update" android:text="更新补丁" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <Button android:id="@+id/bt" android:layout_gravity="center" android:text="showText" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>
dependencies { compile 'com.alipay.euler:andfix:0.4.0@aar' }
2.方便测试,我们写死补丁存放目录及存文件名
//补丁存放地址 private static final String APATCH_PATH = "/fix.apatch";
private void update() { String patchFileStr = Environment.getExternalStorageDirectory().getAbsolutePath() + APATCH_PATH; try { AppApplication.getInstance().mPatchManager.addPatch(patchFileStr); } catch (IOException e) { e.printStackTrace(); } }3.AndFix的初始化一般放在application中,这里我们定义了AppApplication,记得要在manifest的application标签中声明android:name=".AppApplication"
public class AppApplication extends Application { public static PatchManager mPatchManager; private static class MHOLDER{ public static AppApplication mInstance = new AppApplication(); } public static AppApplication getInstance(){ return MHOLDER.mInstance; } @Override public void onCreate() { super.onCreate(); // 初始化patch管理类 mPatchManager = new PatchManager(this); // 初始化patch版本 mPatchManager.init("1.0"); mPatchManager.loadPatch(); } }
4.声明权限信息,不声明权限可能导致app不能访问SD卡中文件,从而不能实现补丁修复。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>5.生成apk文件,我们将其重命名app01.apk.
6.修改Toast内容,从“嘤嘤嘤”改为“哈哈哈”,生成apk文件并重命名app02.apk
7.利用我们下载好的apkpatch工具生成补丁文件,我们将下载的工具解压后,将前面文件、app01.apk、app02.apk放到解压后的目录中,DOS下执行以下命令
C:\Users\px02085\Desktop\apkpatch-1.0.3>apkpatch.bat -f app02.apk -t app01.apk -o output -k huaweiKey.keystore -p xxx -a huaweiKey.keystore -e xxx
其中命令解释为:
apkpatch.bat -f 新apk -t 旧apk -o 输出目录 -k app签名文件 -p 签名文件密码 -a 签名文件别名 -e 别名密码
- -f <new.apk> :新apk
- -t <old.apk> : 旧apk
- -o <output> : 输出目录(补丁文件的存放目录)
- -k <keystore>: 打包所用的keystore
- -p <password>: keystore的密码
- -a <alias>: keystore 用户别名
- -e <alias password>: keystore 用户别名密码
我们将后缀名apatch文件重命名为程序中写好的fix.apatch,并放入程序中定义好的目录中(即SD卡的根目录)。可以看到我们的补丁文件非常小,一般都只有几K。
8.模拟器或者手机中先安装并运行app01.apk,点击第二个button显示“嘤嘤嘤”。
9.点击第一个button(我们在程序中已经定义好了补丁更新程序并且在正确位置放置好了补丁文件),执行补丁更新(热修复),再点击第二个button(不用重启应用,非常方便),显示“哈哈哈”,热修复成功。