这篇文章主要写一下我使用 dexposed 的一个简单流程。
一开始就不多废话了,总之dexposed是阿里巴巴新开源的一个非侵入式的AOP框架。
GitHub传送门:https://github.com/alibaba/dexposed
以下翻译自 GitHub:
1、Dexposed是什么:
Dexposed 是 Android 应用开发一个功能强大且非侵入式的运行时 AOP(面向方向编程)框架,他是基于开源的 Xposed 框架实现的。
Dexposed 的 AOP 实现是完全非侵入式的,没有使用任何注解处理器,编织器或字节码重写。集成 Dexposed 框架很简单,只需要使用一行代码,在程序的初始化阶段加载一个小小的 JNI 库即可。
Dexposed 不仅可以 hook 你自己的程序代码,也可以 hook 你的应用程序中调用的 Android 框架中的函数。开发者经常严重的依赖 Fragment 碎片化来开发程序,这个功能对这一情况大有用处。
机遇动态加载的机制,运行中的 app 可以加载一小段经过编译的 Java AOP 代码,在不需要重新启动程序的情况下改变目标 app 的行为。
2、经典实用场景
1、经典 AOP 编程
2、仪表化 (Instrumentation) ,用于测试,性能监控等
3、在线热修复,用于修复,紧急漏洞,安全漏洞、
4、SDK hook ,以提供更好的开发体验。
3、集成
这部分是我个人集成详细过程,和官方给的方法可能有出入。(因为我按它说的做根本没弄好(⊙﹏⊙)b)
首先先把 GitHub 上的东西下载下来解压后打开,目录如下:
在 Android Studio 上新建项目 DexposedDemo。把 dexposed\src\main 目录下的 jniLibs 文件夹拷贝到自己项目的 src/main 目录下。在自己的项目中添加一个包,取名为 com.taobao.android.dexposed ,接着把 dexposed\src\main\java\com\taobao\android\dexposed 下的源码都复制到 com.taobao.android.dexposed 包中。。添加后,在 Project 视图中,目录结构如下:
接下来检测设备是否支持 dexposed 框架,根据官方文档,因在程序中今早进行检测,所以这段代码被放到 MyApplication 类中。
package com.bajie.dexposed;
import android.app.Application;
import android.os.Build;
import android.util.Log;
import com.taobao.android.dexposed.DexposedBridge;
public class MyApplication extends Application {
private static final String TAG = "MyApplication";
private boolean mCanDexposed = false;
@Override
public void onCreate() {
super.onCreate();
mCanDexposed = DexposedBridge.canDexposed(this);
Log.i(TAG, "canDexposed = " + mCanDexposed);
}
public boolean canDexposed() {
return mCanDexposed;
}
}
别忘了在 manifest 文件中配置 application 哦:
<application
android:name=".MyApplication" />
4.基本使用方法
针对一个方法,可以用三种方法对它进行改造,分别是:方法前,方法后,替代方法。
比如有一个显示 Toast 的方法如下:
private void showToast() {
toast = Toast.makeText(this, "this is a toast", Toast.LENGTH_SHORT);
}
我们想在这个方法执行前或执行后在一个 TextView 中显示消息,可以这样实现:
private void hookShowToast() {
DexposedBridge.findAndHookMethod(this.getClass(), "showToast", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
tv.setText("showToast() afterHooked");
}
});
}
Dexposed 框架还可以替换掉整个函数:
private void methodReplacement() {
if(canDexposed) {
DexposedBridge.findAndHookMethod(this.getClass(), "showToast", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
Toast.makeText(MainActivity.this, "this is a replacement toast", Toast.LENGTH_SHORT).show();
return null;
}
});
}
}
Dexposed 还拥有热补丁的方法。就是在项目上线的时候,在不发布新版本的情况下,动态修复线上的 bug 的功能。
首先先建一个 Patch 项目作为补丁,引入 dexposedbridge.jar 和 patchloader.jar,在目标项目中加入 com.taobao.android.dexposed.patch 下面的源码,这里需要注意,需要在目标项目中加入读 SdCard 的权限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
首先在 目标项目中添加此方法
public void runPathApk() {
String fullPath = Environment.getExternalStorageDirectory() + File.separator + "patch.apk";
setText("\n" + fullPath);
PatchResult result = PatchMain.load(this, fullPath, null);
if (result.isSuccess()) {
setText("patch success!");
} else {
setText("\n" + result.getErrorInfo());
}
}
其中 fullPath 为补丁 apk 的路径,可以自定义,当然在路径中你需要放入补丁 apk。
接着在补丁中添加类:
public class ToastPach implements IPatch {
@Override
public void handlePatch(PatchParam patchParam) throws Throwable {
final Class<?> cls = patchParam.context.getClassLoader().loadClass("com.bajie.dexposed.MainActivity");
DexposedBridge.findAndHookMethod(cls, "showToast", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
Toast.makeText((Activity)param.thisObject, "success", Toast.LENGTH_LONG).show();
return null;
}
});
}
}
补丁项目中只需要实现此类就可以,然后把补丁项目打包,放到相应的位置,运行原来的项目,在这里,showToast 方法将被替换掉。
需要注意几点是,我当时用gradle:2.0.2-beta6 进行运行的时候,没办法使用,后来改成 gradle:1.5.0 就可以运行了。