Xposed开发之检查模块是否启用

Author Avatar
发表:10月 12, 2018 更新:4月 29, 2019
字数统计:511 字 阅读时长:2 分

个人开发的 Xposed 模块中,确实有检查自己模块是否已启用的需求,那么该如何实现呢?

思路分析

最直接思路就是直接去 Xposed Installer 的模块列表里面,自己的模块是否已被勾选。那么, Xposed Installer 有提供相关 api 调用来返回某模块是否被勾选吗?答案是,没有。

那么,能不能 Hook Xposed Installer 的模块列表界面,从而获取是否被勾选呢? 想到这里的时候其实是把此问题复杂化了:只要能 Hook 成功了,就说明自己模块已经启用了,那么何不 Hook 自己的模块应用本身呢? 这样也避免了还需要去逆向 Xposed Installer 的麻烦。

想到这里,其实整个问题都已经迎刃而解了。

编程实现

当前模块相关的工具类 ModuleUtils


public class ModuleUtils {

    private ModuleUtils() {}

    /**
     * 返回模块版本
     * 注意:该方法被本模块Hook住,返回的值是 BuildConfig.MODULE_VERSION,如果没被Hook则返回-1
     */
    private static int getModuleVersion() {
        return -1;
    }

    /**
     * 当前模块是否在XposedInstaller中被启用
     */
    public static boolean isModuleEnabled() {
        return getModuleVersion() > 0;
    }
}

ModuleUtils.isModuleEnabled() 正常条件下一定是返回 false 的,而我们接下来要做的就是去 Hook getModuleVersion() 方法,让其在已启用的情况下返回正值,这样就能通过 isModuleEnabled() 判断模块是否已经启用了。

ModuleUtilsHook 用来 Hook ModuleUtils

public class ModuleUtilsHook implements IXposedHookLoadPackage {

    private static final String SMSCODE_PACKAGE = BuildConfig.APPLICATION_ID;
    private static final int MODULE_VERSION = BuildConfig.MODULE_VERSION;

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {

        if (SMSCODE_PACKAGE.equals(lpparam.packageName)) {
            try {
                XLog.i("Hooking current Xposed module status...");
                hookModuleUtils(lpparam);
            } catch (Throwable e) {
                XLog.e("Failed to hook current Xposed module status.");
            }
        }

    }

    private void hookModuleUtils(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        String className = ModuleUtils.class.getName();

        XposedHelpers.findAndHookMethod(className, lpparam.classLoader,
                "getModuleVersion",
                XC_MethodReplacement.returnConstant(MODULE_VERSION));
    }
}

其中上面的 MODULE_VERSION 是在项目 modulebuild.gradle 自定义的:

android {
    // ...
    defaultConfig {
        // ...
        buildConfigField("int", "MODULE_VERSION", "18")
    }
}

最后,因为 ModuleUtilsHook 在 Hook 过程中用到了反射,所以不应该混淆 ModuleUtilsgetModuleVersion 方法:

-keep class com.github.tianma8023.xposed.smscode.utils.ModuleUtils {
    int getModuleVersion();
}

源码请戳 ModuleUtilsHook