前言:
对于AndFix的深层次思想和原理,我一直半懂不懂,介绍一个讲述原理的博文 Android App 线上热修复方案,其中所说的Xposed的原理操作看得萌萌哒,等慢慢消化吧,本文只是详细记录下,我在使用AndFix的一些步骤和坑,耐心!耐心!耐心!(重要的事情说3遍)
第一步:下载
虽然可有可无,不过也是第一步,github:https://github.com/alibaba/AndFix
第二部:解压缩
恩,真正使用的时候,我们所需要的一切在解压后的tools目录下的压缩包里面,解压 apkpatch-1.0.3.zip 后的目录如下:
到这里,准备工作都已经做完了。
第三部:代码编写
其实在github上已经说得很清楚了,不过想想还是把代码具体的写出来吧。
对于Patch的初始化,当然越早越好,这个没什么异议,那么就放在Application里面
public class MyApplication extends Application {
public static MyApplication instance;
public static final String TAG = "MyApplication";
public static PatchManager patchManager;
@Override
public void onCreate() {
super.onCreate();
instance = this;
DirUtils.initDir();
initPatch();
}
private void initPatch() {
try {
patchManager = new PatchManager(this);
String versionName = this.getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
Log.d(TAG, versionName);
patchManager.init(versionName);
patchManager.loadPatch();
} catch (Exception e) {
}
}
}
然后在MainActivity里面,我加入了以下代码,并且先提供下本地目录的路径工具 类
public class DirUtils {
public static final String ROOT =
Environment.getExternalStorageDirectory() + File.separator +
MyApplication.instance.getString(R.string.app_name) + File.separator;
public static void initDir() {
File dir = new File(ROOT);
if (!dir.exists()) {
if (dir.mkdirs()) {
}
}
}
}
public class MainActivity extends AppCompatActivity {
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
try {
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
String versionName = packageInfo.versionName;
int versionCode = packageInfo.versionCode;
tv.setText("versionCode=" + versionCode + " : versionName=" + versionName + " : i am a 大八个");
// tv.setText("versionCode=" + versionCode + " : versionName=" + versionName + " : I am not a 大八个" + " 哈哈哈哈");
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
tv.postDelayed(new Runnable() {
@Override
public void run() {
File file = new File(DirUtils.ROOT, "fix.apatch");
if (file.exists()) {
Log.d(MyApplication.TAG, "fix.apatch exists");
try {
MyApplication.patchManager.addPatch(file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}, 3000);
}
public void jump(View view) {
startActivity(new Intent(this, SecondActivity.class));
}
}
这是bug的版本,修复的代码就是把注释的那行代码放开就行了,这里我已经约定好patch的名字就是 fix.patch,然后模拟加载这个补丁。
这儿我没有用到服务器,具体的测试步骤是这样的:
1.把bug版本的apk打包完成,装在手机上,就是模拟用户已经存在在手机上的apk
2.将fix版本的apk打包,然后制作.apatch补丁文件,存储到我约定的路径下,这里就是模拟下载
3.当你重新打开apk,其实就完成了补丁的修复,如果再一次打开apk就可以看到bug被修复了
具体如何生成 .apatch:
在相同的 versionCode 和 versionName 下,才能成功的打出 .apatch的包,如果你的版本标识不一样会报错,这样就无法成功把补丁打出来:
当你把bug版本的apk和fix版本的apk,都打出来之后,使用AndFix提供的tool,也就是前面所说的压缩包,另外,我用的是Mac,所以使用的时候用的就是 .sh后缀的文件,成功的命令如下:
切换到解压后的apkpatch-1.0.3目录下
./apkpatch.sh -f /Users/chenjiahuan/Desktop/app-release-fix.apk -t /Users/chenjiahuan/Desktop/app-release-bug.apk -o /Users/chenjiahuan/Desktop/apkpatch-output -k /Users/chenjiahuan/Desktop/123456.keystore -p 123456 -a 123456 -e 123456
./apkpatch.sh 具体的命令脚本
-f new_fixed_apk 修复完成的apk
-t old_bug_apke 线上待修复的apk
-o patch_output 补丁patch的输出目录
-k keystore 签名文件
-p pwd 签名密码
-a alias 别名
-e alias_pwd 别名密码
一切OK的话就打出了
fix.apatch 就是我需要的补丁,然后按照我之前的测试流程就可以了。
补充:
真正上线的时候肯定不会这么简单的,补丁版本的控制下载流程,包括混淆、加密这些都可能存在着坑,不过程序员不就是专业填坑的么…
另外需要知道的是,AndFix并不是说patch好了之后就能看到,你需要重新打开app,这也是我MainActivity中为什么会有跳转的代码,事实证明,bug修复后,需要用户重新打开app。
这样,我使用的具体流程就是这样了,之后我还会讲一下另外一种热修复方案,基于ClassLoader的,那是我比较熟悉的一种方案,不过过程麻烦了点,代码就不需要贴了吧,都在上面了。