Xposed插件每次代码改动,都需要重启手机才能生效,有时候重启一次还不生效(我的手机有一次重启 3 次,才看到生效,还好是公司测试机,不心疼),所以代码最好写上相关 Log 信息,来看代码生效没。
XposedBridge.log("启动了xxx软件");
不过这里分享一个免重启调试的方法,方法来自网上,感谢 DX :
/**
* @author DX
* 这种方案建议只在开发调试的时候使用,因为这将损耗一些性能(需要额外加载apk文件),调试没问题后,直接修改xposed_init文件为正确的类即可
* 可以实现免重启,由于存在缓存,需要杀死宿主程序以后才能生效
* 这种免重启的方式针对某些特殊情况的hook无效
* 例如我们需要implements IXposedHookZygoteInit,并将自己的一个服务注册为系统服务,这种就必须重启了
* Created by DX on 2017/10/4.
*/
public class HookLoader2 implements IXposedHookLoadPackage {
//按照实际使用情况修改下面几项的值
/**
* 当前Xposed模块的包名,方便寻找apk文件
*/
private final String modulePackage = "com.xxx.plugin";
/**
* 宿主程序的包名(允许多个),过滤无意义的包名,防止无意义的apk文件加载
*/
private static List<String> hostAppPackages = new ArrayList<>();
static {
// TODO: Add the package name of application your want to hook!
hostAppPackages.add("com.eg.android.AlipayGphone");
hostAppPackages.add("com.xxx.plugin");
}
/**
* 实际hook逻辑处理类
*/
private final String handleHookClass = TargetHook.class.getName();
/**
* 实际hook逻辑处理类的入口方法
*/
private final String handleHookMethod = "handleLoadPackage";
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (hostAppPackages.contains(loadPackageParam.packageName)) {
//将loadPackageParam的classloader替换为宿主程序Application的classloader,解决宿主程序存在多个.dex文件时,有时候ClassNotFound的问题
XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Context context=(Context) param.args[0];
loadPackageParam.classLoader = context.getClassLoader();
invokeHandleHookMethod(context,modulePackage, handleHookClass, handleHookMethod, loadPackageParam);
}
});
}
}
/**
* 安装app以后,系统会在/data/app/下备份了一份.apk文件,通过动态加载这个apk文件,调用相应的方法
* 这样就可以实现,只需要第一次重启,以后修改hook代码就不用重启了
* @param context context参数
* @param modulePackageName 当前模块的packageName
* @param handleHookClass 指定由哪一个类处理相关的hook逻辑
* @param loadPackageParam 传入XC_LoadPackage.LoadPackageParam参数
* @throws Throwable 抛出各种异常,包括具体hook逻辑的异常,寻找apk文件异常,反射加载Class异常等
*/
private void invokeHandleHookMethod(Context context, String modulePackageName, String handleHookClass, String handleHookMethod, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
File apkFile=findApkFile(context,modulePackageName);
if (apkFile==null){
throw new RuntimeException("寻找模块apk失败");
}
//加载指定的hook逻辑处理类,并调用它的handleHook方法
PathClassLoader pathClassLoader = new PathClassLoader(apkFile.getAbsolutePath(), ClassLoader.getSystemClassLoader());
Class<?> cls = Class.forName(handleHookClass, true, pathClassLoader);
Object instance = cls.newInstance();
Method method = cls.getDeclaredMethod(handleHookMethod, XC_LoadPackage.LoadPackageParam.class);
method.invoke(instance, loadPackageParam);
}
/**
* 根据包名构建目标Context,并调用getPackageCodePath()来定位apk
* @param context context参数
* @param modulePackageName 当前模块包名
* @return return apk file
*/
private File findApkFile(Context context, String modulePackageName){
if (context==null){
return null;
}
try {
Context moudleContext = context.createPackageContext(modulePackageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
String apkPath=moudleContext.getPackageCodePath();
return new File(apkPath);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
}