最近研究阿里的开源热修复框架AndFix,本文参考AndFix官方教程,给出我所使用详细小白demo教程,包括在构建测试demo过程中所遇到对问题也列出来。阿里github链接:https://github.com/alibaba/AndFix
限制:
1、支持的Android版本为2.3-7.0(即:Android API 9 ~ Android API 24),本文在7.1版本的真机中测试失败。
2、无法添加删除类和字段,只能修改。
3、如构造函数等静态函数可能会有问题。
踩坑说明:
在使用AS创建项目时候,不管你选择的是那个Target版本,在gradle中默认的SDK都是最高版本。而我一开始用最高版本时,项目/build/outputs文件夹下没有apk文件夹,使用如下步骤生成apk文件:
此时output目录下生成apk文件夹,但最后生成补丁包时报错如下:
因此最后我选择手动修改gradle配置文件,降低SDK版本,同时由于本文为demo测试,删除了一些不需要的依赖项。
本文使用Gradle将sdk编译版本设置为23,并且将最低目标版本为21(这个大家可以根据官网支持的版本修改),同时删除了所有dependencies依赖项,只添加AndFix依赖,具体对应位置修改如下:
compileSdkVersion 23
minSdkVersion 21
dependencies {
compile 'com.alipay.euler:andfix:0.5.0@aar'
}
此时,当我们修改完成后,gradle sync发现会报许多资源错误。这是因为创建的项目资源文件中使用了高版本SDK和一些依赖包中的东西,因此需要将不必要的资源文件或里面引用的标签删除,大致包括AndroidManifest.xml中的标签,res文件夹下的资源文件。如果是生成的BasicActivity,那么在这个Activity中,也可以将其他东西删除。
本文最终的使用的MainActivity.java关键代码如下:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
Log.d("euler", "test");
TextView tv = (TextView) findViewById(R.id.text);
tv.setText(change());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
public String change(){
return "old";
}
布局文件activity_main.xml代码如下:
补丁框架所需要的类MainApplication.java,直接放在与启动类MainActivity同一目录下,具体代码如下:
import java.io.IOException;
import android.app.Application;
import android.os.Environment;
import android.util.Log;
import com.alipay.euler.andfix.patch.PatchManager;
/**
* sample application
*
* @author [email protected]
*
*/
public class MainApplication extends Application {
private static final String TAG = "euler";
private static final String APATCH_PATH = "/out.apatch";
/**
* patch manager
*/
private PatchManager mPatchManager;
@Override
public void onCreate() {
super.onCreate();
// initialize
mPatchManager = new PatchManager(this);
mPatchManager.init("1.0");
Log.d(TAG, "inited.");
// load patch
mPatchManager.loadPatch();
Log.d(TAG, "apatch loaded.");
// add patch at runtime
try {
// .apatch file path
String patchFileString = Environment.getExternalStorageDirectory()
.getAbsolutePath() + APATCH_PATH;
mPatchManager.addPatch(patchFileString);
Log.d(TAG, "apatch:" + patchFileString + " added.");
} catch (IOException e) {
Log.e(TAG, "", e);
}
}
}
由于本文代码需要对sdcard进行读写,且实现MainApplication类,因此需要修改AndroidManifest.xml文件,本文具体代码如下:
此时项目生成基本完成,gradle能够build成功。如果还有什么错误,只需要根据提示安装即可。
AndFix在使用补丁工具生成补丁包时,需要keystore文件和密钥等,如果你已经有自己的keystore文件,则可跳过这步。具体步骤如下:
finish后软件会自动在指定目录下生成jks文件,并提示生成成功。
建立好keystore后,需要配置用该文件作为apk的签名文件,具体步骤如下:
配置完成后,选择本次编译版本,因为签名配置使用签名文件的版本为release版,因此编译选项选择release版。具体步骤如下:
然后运行安装app即可,在项目路径/app/build/outputs/apk/release/app-release.apk即为带Bug的apk。
本文保存该apk并更名为old.apk,解压源码AndFix-master/tools/apkpatch-1.0.3.zip,将old.apk放在解压后的apkpatch-1.0.3文件夹下。
需要注意的是,本文demo使用了存储设备读取权限,因此安装后需要手动在应用管理中开启存储权限。
本文更新的apk文件,只是将MainActivity中change函数的返回字符串更改为new,重新编译得到更新后的apk文件,并重命名为new.apk,同样复制到apkpatch-1.0.3文件夹下,此时手机里运行的仍然是带bug的old.apk。
进入apkpatch-1.0.3文件夹文件夹,使用如下命令生成补丁.apatch文件。
./apkpatch.sh -o /Users/xxx/Desktop/ -k /Users/xxx/xxx.jks -p ******** -a xxx -e ******** -t ./old.apk -f ./new.apk
命令参数说明:
此时,Desktop目录下将生成了两个文件,关注.patch文件,重命名为MainApplication中用到的常量名称out.patch。
将补丁文件放入指定位置,本文所用测试机对应位置为/sdcard,因此使用命令如下:
adb push /Users/xxx/Desktop/out.apatch /sdcard/out.apatch
对于其他机型,本文代码对应可能使用的命令如下:
adb push /Users/xxx/Desktop/out.apatch /storage/emulated/0/out.apatch
重新启动应用,发现bug已经被修复。