AndFix的github地址
AndFix是一种在线修复错误而不是重新分发Android App的解决方案。它作为Android库分发。
Andfix是一个缩写“ android 热修复”。
AndFix支持Android版本从2.3到7.0,ARM和X86架构,以及Dalvik和ART运行时(32位和64位)。
AndFix补丁的压缩文件格式是.apatch。它从您自己的服务器分发到客户端,以修复您的应用程序错误。
andfix使用
在使用中,可以将整个使用过程分成两部分
- 原始apk和修复之后的apk的编写
- patch文件的生成
3.在代码中调用生成的patch
生成patch文件
在下载的源码目录中,有一个Tool的目录,将你项目的apk 要修复的apk 以及签名文件放到该目录中,输入命令如下
usage: apkpatch -f <new> -t <old> -o <output> -k <keystore> -p <> -a <alias> -e <>
-a,--alias <alias> keystore entry alias// 用户别名
-e,--epassword <> keystore entry password.//用户别名密码
-f,--from <loc> new Apk file path.//新apk
-k,--keystore <loc> keystore path.//打包所用的keystore目录
-n,--name <name> patch name.
-o,--out <dir> output dir.//输出文件的目录
-p,--kpassword <> keystore password.//密码
-t,--to <loc> old Apk file path.//旧apk
C:\Users\freed>E:
E:\>cd E:\StudioProjects\AndFix-master\AndFix-master\tools\apkpatch-1.0.3
E:\StudioProjects\AndFix-master\AndFix-master\tools\apkpatch-1.0.3>apkpatch -f new.apk -t old.apk -o . -k iccardKey.jks -p yunmeng -a iccard -e yunmeng
add modified Method:V setContentView() in Class:Lcom/yunmeng/liuy/iccard/ui/activity/WelcomeActivity;
在目录中会生成diff.dex 与一个apatch的文件
将apatch文件放到需要加载的目录中
添加依赖
dependencies {
implementation 'com.alipay.euler:andfix:0.5.0@aar'
}
在代码上的使用
public class AndFixApplication 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();
try {
init();
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
private void init() throws PackageManager.NameNotFoundException {
// 初始化patch管理类
mPatchManager=new PatchManager(this);
// 初始化patch版本,如果patch包中的版本信息与应用中的不一致,则不更新
mPatchManager.init(this.getPackageManager().getPackageInfo(getPackageName(),0).versionName);
// 加载已经添加到PatchManager中的patch
mPatchManager.loadPatch();
}
private void update() {
String patchFileStr = Environment.getExternalStorageDirectory().getAbsolutePath() + APATCH_PATH;
try {
mPatchManager.addPatch(patchFileStr);
} catch (IOException e) {
e.printStackTrace();
}
}
}
在更新完成后无需再次启动
AndFix原理
阿里系修复方案使用的是底层替换方案
与腾讯系的类加载方案不同的是,底层替换方案不会再次加载新类,而是直接在Native层修改原有类,由于是在原有类进行修改限制会比较多,不能够增减原有类的方法和字段,如果我们增加了方法数,那么方法索引数也会增加,这样访问方法时会无法通过索引找到正确的方法,同样的字段也是类似的情况。
底层替换方案和反射的原理有些关联,就拿方法替换来说,方法反射我们可以调用java.lang.Class.getDeclaredMethod,假设我们要反射Key的show方法,会调用如下所示。
Key.class.getDeclaredMethod("show").invoke(Key.class.newInstance());
Android 8.0的invoke方法,如下所示。
libcore/ojluni/src/main/java/java/lang/reflect/Method.java
@FastNative
public native Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
invoke方法是个native方法,对应Jni层的代码为:
art/runtime/native/java_lang_reflect_Method.cc
static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver,
jobject javaArgs) {
ScopedFastNativeObjectAccess soa(env);
return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
Method_invoke函数中又调用了InvokeMethod函数:
art/runtime/reflection.cc
jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod,
jobject javaReceiver, jobject javaArgs, size_t num_frames) {
...
ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable>(javaMethod);
const bool accessible = executable->IsAccessible();
ArtMethod* m = executable->GetArtMethod();//1
...
}
注释1处获取传入的javaMethod(Key的show方法)在ART虚拟机中对应的一个ArtMethod指针,ArtMethod结构体中包含了Java方法的所有信息,包括执行入口、访问权限、所属类和代码执行地址等等,ArtMethod结构如下所示。
art/runtime/art_method.h
class ArtMethod FINAL {
...
protected:
GcRoot<mirror::Class> declaring_class_;
std::atomic<std::uint32_t> access_flags_;
uint32_t dex_code_item_offset_;
uint32_t dex_method_index_;
uint16_t method_index_;
uint16_t hotness_count_;
struct PtrSizedFields {
ArtMethod** dex_cache_resolved_methods_;//1
void* data_;
void* entry_point_from_quick_compiled_code_;//2
} ptr_sized_fields_;
}
ArtMethod结构中比较重要的字段是注释1处的dex_cache_resolvedmethods和注释2处的entry_point_from_quick_compiledcode,它们是方法的执行入口,当我们调用某一个方法时(比如Key的show方法),就会取得show方法的执行入口,通过执行入口就可以跳过去执行show方法。
替换ArtMethod结构体中的字段或者替换整个ArtMethod结构体,这就是底层替换方案。
AndFix采用的是替换ArtMethod结构体中的字段,这样会有兼容问题,因为厂商可能会修改ArtMethod结构体,导致方法替换失败。Sophix采用的是替换整个ArtMethod结构体,这样不会存在兼容问题。
底层替换方案直接替换了方法,可以立即生效不需要重启。采用底层替换方案主要是阿里系为主,包括AndFix、Dexposed、阿里百川、Sophix。
demo地址
网友评论