# EzXHelper: reflection and hook helpers for Xposed module authors

> EzXHelper is a Kotlin library for Android Xposed module development that wraps the reflection boilerplate and offers hook DSLs for both the 82 and 101 Xposed APIs, published on Maven Central as separate core, API and android-utils artifacts.

**KyuubiRan/EzXHelper** — A library to make Xposed modules development easily.

- Repository: https://github.com/KyuubiRan/EzXHelper
- Website: https://KyuubiRan.github.io/EzXHelper/
- Stars: 611 · Forks: 61
- Language: Kotlin
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/kyuubiran-ezxhelper

## The problem is boilerplate, not the hooking itself

Writing an Xposed module in Kotlin means writing a lot of code that is not about your hook. Every reflective call needs a class, a method lookup, parameter types, and often a way to unwrap a hidden implementation class. Every hook needs a before and an after block with the right argument types, and the argument array has to be handed to the next link in the chain. The hooking itself is one line; the scaffolding around it is thirty.

EzXHelper is a tool library to make Xposed module development easier, written in Kotlin, with the topics listing android, java, kotlin, library, reflection and xposed. Its homepage is at https://KyuubiRan.github.io/EzXHelper/ and it is published on Maven Central, with a version badge pointing at the io.github.kyuubiran.ezxhelper/core artifact.

The scope changed in 3.x, and the change is the most consequential fact about the project. The 3.x version has split the reflection part into a separate library so that it can run on the JVM. That matters for two different audiences: module authors who also want to unit test their reflection logic off-device, and anyone who wants the reflection helpers without pulling in the Xposed-specific parts at all.

The default branch is 3.x, the licence is MIT, and the recent releases are 301, tagged 3.0.1-rel, and 300, tagged 3.0.0-rel, both in July 2025.

## Three artifacts, and you pick the API level you need

The dependency declaration tells you the whole packaging story. There is a core artifact, an artifact per Xposed API level, and an optional android-utils artifact.

```kotlin
dependencies {
    val ezxhelperVersion = "<version>"
    implementation("io.github.kyuubiran.ezxhelper:core:$ezxhelperVersion")
    implementation("io.github.kyuubiran.ezxhelper:xposed-api-82:$ezxhelperVersion")
    implementation("io.github.kyuubiran.ezxhelper:android-utils:$ezxhelperVersion")
}
```

The two Xposed artifacts correspond to the two generations of the Xposed API. The 82 artifact targets the older API surface, the 101 artifact the newer one, and the README shows the 101 line present but commented out in the example, so you pick one and leave the other out. The android-utils artifact is for Android related utility extensions and is likewise the one to add only if you need it.

The core artifact is the one that always goes in. That split is what makes the JVM support claim work, since the reflection helpers live in core and do not depend on the Xposed runtime.

The same dependency block exists in Groovy form for projects that still use build.gradle rather than build.gradle.kts, so both DSL styles are supported and documented side by side. The repository root confirms the module layout: core/, xposed-api-82/, xposed-api-101/, libxposed/, android-utils/ and two sample apps, sample-app/ and sample-app-api-101/.

## The 101 API needs three init calls, the 82 API needs two

The entry points differ between the API levels, and this is where most of the friction lives for a new user.

On the 82 API, the module hooks handleLoadPackage and passes the parameter to a helper, with an optional zygote init as well.

```kotlin
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
    // ...
    EzXposed.initHandleLoadPackage(lpparam)
}
```

The 101 API spreads the same job over three callbacks, which reflect a genuinely different lifecycle in the newer framework: onModuleLoaded for the module itself, onPackageLoaded for each package, and onPackageReady for the point where the package is fully usable.

```kotlin
override fun onModuleLoaded(param: ModuleLoadedParam) {
    EzXposed.initOnModuleLoaded(this, param)
}

@RequiresApi(Build.VERSION_CODES.Q)
override fun onPackageLoaded(param: PackageLoadedParam) {
    EzXposed.initOnPackageLoaded(param)
}

override fun onPackageReady(param: PackageReadyParam) {
    EzXposed.initOnPackageReady(param)
}
```

Note the annotation on the onPackageLoaded override, which marks it as requiring API level Q and above. The README also credits re-zero001 for the Xposed API-101 support, which is a useful signal about where that work came from.

If you are unsure which API your target framework exposes, the repository has both a libxposed/ directory and separate sample applications for each, so the working example for your case is already in the tree.

## Two hook styles, and a chain form that maps to Java

The hook API is where the library earns its keep, because the two calling conventions cover the two ways people write hooks.

The first is a createHook style with separate before and after blocks that receive a param object.

```kotlin
method.createHook {
    before { param ->
        param.args[0] = "before"
    }

    after { param ->
        android.util.Log.i("sample", "result=${param.result}")
    }
}
```

The second is a chain style, where you copy the arguments out, modify them, and pass the array to proceed.

```kotlin
method.hook { chain ->
    val args = chain.args.toTypedArray()
    args[0] = "chain"
    chain.proceed(args)
}
```

And because a large share of Xposed code is still Java, the README gives the Java equivalent of the chain form directly under it, with getArgs() returning the array, the assignment, and the call to proceed.

The reason the chain form is awkward to write by hand is the copying of the argument array, and the reason the library provides it is that you get the same call shape from Kotlin and from Java. If you already have a working hook written in one style, you can port it to the other without restructuring the surrounding code.

## Reflection is separated, and the ClassLoader has to be set

The reflection helper is a separate library in 3.x so it can run on the JVM, and it has one configuration step that will bite you if you skip it.

Before using the library, you call the init function to set the default ClassLoader. Without it, the library falls back to ClassLoader.getSystemClassLoader() as the reflection ClassLoader, which is the system class loader of the process you are running in. In an Xposed module that is almost never the loader that holds the class you want to reflect into, which lives in the target app's own loader.

```kotlin
EzXReflection.init(yourClassLoader)
```

So the sequence in a real module is: install the hook, find the class through the reflection helper with the right loader, then hook the method. Skipping the init call produces failures that look like a missing class rather than a misconfigured loader, which is exactly the kind of thing that costs an evening.

Running the reflection layer on the JVM is what makes this testable, and that is the practical payoff of the 3.x split.

## A library with a Chinese-first README and a small but real user base

One thing to know before you start: the README is written in Chinese, with an English version linked as README_en.md in the repository root, and the documentation site is at https://KyuubiRan.github.io/EzXHelper/. A Telegram group is offered for support.

The README also lists the projects that use the library, and the list is worth reading as a compatibility signal rather than as a popularity measure. It includes a template project for the library itself, QAssistant, QQCleaner, HideMyApplist, OneText, XAutoDaily, QAuxiliary, TMoe, WooBox for MIUI and for ColorOS, Miui XXL, TwiFucker and PureNGA. The spread is a useful one: modules for messaging apps, for launcher widgets, for customising system launchers on MIUI and ColorOS, and for removing ads, which tells you the library handles real apps with real obfuscation and real lifecycle complexity rather than only toy targets.

Two related projects are pointed at as alternatives for people who do not like this style. KavaRef is offered for developers who dislike how EzXHelper is written, and DexKit is described as a high performance runtime parsing library for dex, written in C++, used to find obfuscated classes, methods or properties. That second one is a different tool for a different job, and it composes rather than competes.

The licence is MIT, so using it in a module you distribute is straightforward as long as the notice is kept.

## Conclusion

Adopt EzXHelper if you build Xposed modules and want the reflection and hook boilerplate handled, especially if you target the 101 API, and skip it if you only need a single hook, since the setup cost of a second Gradle dependency is small but not zero. Before you start, pick the API level your target framework exposes and include only the matching artifact, and read the 3.x branch notes, since the reflection part was split into its own library that runs on the JVM and the last push was on 2026-05-02 with the last release tagged 3.0.1-rel in July 2025.

## FAQ

### How do I add EzXHelper to my Xposed module project?

Add the core artifact and the artifact for the Xposed API level you target, for example io.github.kyuubiran.ezxhelper:core and io.github.kyuubiran.ezxhelper:xposed-api-82, with the version held in a variable. The android-utils artifact is optional and covers Android related utility extensions.

### What is the difference between the xposed-api-82 and xposed-api-101 artifacts?

They target the two generations of the Xposed API. The 82 artifact uses handleLoadPackage with EzXposed.initHandleLoadPackage, while the 101 artifact uses onModuleLoaded, onPackageLoaded and onPackageReady with the corresponding EzXposed init calls.

### Why do I need to call EzXReflection.init before using the reflection helpers?

It sets the default ClassLoader. Without it the library uses ClassLoader.getSystemClassLoader() as the reflection ClassLoader, which in a module is not the loader that holds the class you want to reflect into.

### What changed in EzXHelper 3.x?

The 3.x version split the reflection part into a separate library so it can run on the JVM, which lets you unit test reflection logic off-device and use the helpers without the Xposed runtime. The releases are tagged 3.0.0-rel and 3.0.1-rel, on the 3.x branch.

## Sources

- [KyuubiRan/EzXHelper on GitHub](https://github.com/KyuubiRan/EzXHelper)
- [License: MIT](https://github.com/KyuubiRan/EzXHelper/blob/3.x/LICENSE)
- [Project website](https://KyuubiRan.github.io/EzXHelper/)
- [README](https://github.com/KyuubiRan/EzXHelper/blob/3.x/README.md)
- [Releases](https://github.com/KyuubiRan/EzXHelper/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kyuubiran-ezxhelper
