Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
This repository was archived by the owner on Jun 26, 2025. It is now read-only.
Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Xpler

Xposed Kotlin 开发模板,更适合Kotlin编码风格。

Xpler 在原 Xposed Api 基础上进一步封装,使其支持Kotlin的DSL特性,更简洁的编写Hook逻辑。

注意:使用本模板,你仍需要手动创建和配置 xposed_initapplication meta-data

Xpler Api

作为原 Xposed Api 的封装项目,Xpler 提供了部分基本Api。

HookEntrance.kt

作为 XplerXposed 提供的抽象入口类,你只需要继承 XplerEntrance,然后实现相应接口即可。

  • ApplicationHookStart

    class HookInit : XplerEntrance(), ApplicationHookStart {
        override val modulePackage: String
            get() = "com.example.module"
    
        override val scopes: Set<ApplicationHookStart.Scope>
            get() = setOf(
                "packageName" at "applicationClassName",
                "packageName1" at ("applicationClassName1" to "processName"),
            )
    
        override fun onCreateBefore(lparam: MethodParam, hostApp: Application) {
            // Do not write or call the same Hook logic in onBefore and onAfter, as this is meaningless
        }
    
        override fun onCreateAfter(lparam: MethodParam, hostApp: Application) {
            HActivity()
        }
    }

    实现该接口后,将自动为宿主注入类加载器,你只需要在 onCreateBeforeonCreateAfter 中书写 Hook逻辑即可。

    modulePackage 为模块包名,必须提供,Xpler 会用它去加载 HookState,以便对于模块启用/未启用状态的获取。

    scopes 为宿主列表,需提供 宿主包名宿主启动应用程序(Application)宿主进程名(prossName)可选 ,不在 scopes 列表中的包名,尽管在Xposed中加入生效列表,Xpler也不会对该宿主生效。

    而如果,你只是需要一个简单的Hook,并不需要复杂操作,可以试试 DefaultHookStart 接口。

  • DefaultHookStart

    class HookInit : XplerEntrance(), DefaultHookStart {
        override val modulePackage: String
            get() = "com.example.module"
    
        override fun loadPackage(lparam: LoadParam) {
            // the original calling logic
        }
    }

    该接口提供的 loadPackage 方法就是原始的 handleLoadPackage 操作。

记得修改xposed_init 中的入口类,如上述的入口类名为:com.example.module.HookInit

还有,如果有混淆优化,记得保留 HookInit 入口类。

//proguard-rules.pro
-keep class com.example.module.HookInit

XplerState.kt

该类汇总了框架状态,如果你想要判断模块是否生效、框架类型,可使用该类。

XplerHelper.kt

区别于原 XposedHelpers 该类提供了更符合Kotlin的编码风格:

  • XposedHelpers 写法

    XposedHelpers.findAndHookMethod(
            Activity.class,
            "onCreate",
            Bundle.class,
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    XposedBridge.log(param.method.getName() + " Before!");
                }
    
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    XposedBridge.log(param.method.getName() + " After!");
                }
            }
    );
  • XplerHelper 写法

    XplerHelper
        .hookClass(Activity::class.java)
        .method("onCreate", Bundle::class.java) {
            onBefore {
                XposedBridge.log("${this.method.name} Before!")
            }
    
            onAfter {
                XposedBridge.log("${this.method.name} After!")
            }
        }

    并且 XplerHelper 在原基础上缓存了目标 Class ,使同一个 Class 支持链式 Hook,如:

    XplerHelper
        .hookClass(Activity::class.java)
        .method("onCreate", Bundle::class.java) {
            onBefore {
                XposedBridge.log("${this.method.name} Before!")
            }
    
            onAfter {
                XposedBridge.log("${this.method.name} After!")
            }
        }
        .method("onResume") {
            onBefore {
                XposedBridge.log("${this.method.name} Before!")
            }
    
            onAfter {
                XposedBridge.log("${this.method.name} After!")
            }
            
            // 当 onReplace 出现时, onBefore、onAfter 将失去意义,它们将不会被执行
            onReplace {
                XposedBridge.log("${this.method.name} Replace!")
            }
            
            // 解除hook逻辑
            onUnhook {
                unhook()
            }
        }

    而对于 XC_MethodHook.MethodHookParam 的使用,相信通过以上例子已经很明显了。

    得益于Kotlin的扩展特性,在 onBefoe{..}onAfter{..}onReplace{..}作用域内,都属于 XC_MethodHook.MethodHookParam;故此,你可以使用 this 来表示 param 参数。

    不过,值得注意的是,onBefore{..}onAfter{..} 属于同类方法,它们允许同时出现,并分别响应其对应执行周期;而 onReplace{..} 出现时,则代表了Hook方法会被直接替换,因此 onBefore{..}onAfter{..} 不会被执行。

XplerModule.kt

模块信息汇总:版本号、模块路径、模块资源

XplerLog.kt

在模块开发中更具通俗的Log工具类,与Log类的调用基本一致,支持LogCat面板等级输出日志。

HookEntity.kt

为了更合适通俗的编码方式,对于需要被Hook的目标类及其方法 HookEntity 支持以传统类定义的方式来书写Hook逻辑,下称 Hook逻辑类

对于某个Class目标的Hook,Hook逻辑类需要继承 HookEntity 并实现抽象方法setTargetClass 主动设置目标Class,然后通过系列注解完成Hook逻辑的编写,最后在 主逻辑 中完成实例化,即可注入相关方法的Hook逻辑,以下是简单示例:

// 目标类 Activity
class HActivity : HookEntity() {

    override fun setTargetClass(): Class<*> {
        return findClass("android.app.Activity")
    }

    @OnBefore("onCreate")
    fun onCreateBefore(params: MethodParam, savedInstanceState: Bundle?) {
        hookBlockRunning(params) { // this: MethodParam
            XplerLog.d(
                "savedInstanceState: $savedInstanceState",
                "method: ${this.method}"
            )
        }
    }

    @OnAfter("onResume")
    fun onCreateBefore(params: MethodParam) {
        hookBlockRunning(params) { // this: MethodParam
            XplerLog.d(
                "thisObject: ${this.thisObject}",
                "method: ${this.method}"
            )
        }
    }

    ...
}

//////////////////////////

// HookInit
override fun onCreateAfter(lparam: LoadParam, hostApp: Application) {
    HActivity()
}

没错,参数 params: MethodParam 不能被省略,并且它只能被放在首位。

以下是一个稍复杂的写法,自行体会:

class HMainActivity : HookEntity() {

    override fun setTargetClass(): Class<*> {
        return findClass("android.app.Activity")
    }

    @OnConstructorBefore
    fun constructorBefore(params: MethodParam) {
        hookBlockRunning(params) {
            XplerLog.d("thisObject: $thisObject")
        }.onFailure {
            XplerLog.e(it)
        }
    }

    @OnAfter("getUser")
    @ReturnType(name = "com.example.bean.User")
    fun getUserAfter(
        params: MethodParam,
        name: String,
        @Param("com.example.config.UserConfig") config: Any?,
    ) {
        hookBlockRunning(params) { // this: MethodParam
            XplerLog.d(
                "name: ${name}",
                "config: ${config}",
                "result: ${this.result}"
            )
        }
    }
}

和前文一样 Xpler 提供的时机注解 @..Before@..After@..Replace,中的 @..Replace 仍然会替换对应目标方法的逻辑,而这时对于 @..Before@..After 则不会生效。

Xpler 在 FreedomPlus 中被很好的实践运用,如果你想要更多示例,请点击 这里

Releases

Packages

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.