Multi-Entry Variants
Here describes how to use build variants to be compatible with multiple base modules in the same project.
Only one entry annotation and one base module can exist in a build variant, but you can use product flavors of the Android Gradle Plugin to create a build variant for each base module, so that they share the same hook code and are packaged into modules for the corresponding base modules separately.
YukiHook generates the entry and configuration files for each build variant separately, so you do not need any extra configuration for it.
Notice
The solution on this page packages the same hook code into separate modules for the corresponding base modules, instead of merging them into one module.
Configure Build Variants
Create a build variant for each base module in the build.gradle.kts of your project, and add the corresponding base module and Xposed API to each of them.
The following example
android {
namespace = "io.github.mymodule"
defaultConfig {
applicationId = "io.github.mymodule"
}
buildFeatures {
buildConfig = true
}
flavorDimensions += "runtime"
productFlavors {
create("modern") {
dimension = "runtime"
}
create("legacy") {
dimension = "runtime"
}
}
}Then deploy the dependencies with the created build variants.
Version Catalog
dependencies {
implementation(libs.yukihook.core)
ksp(libs.yukihook.compiler)
"modernImplementation"(libs.yukihook.runtime.libxposed)
"modernCompileOnly"(libs.libxposed.api)
"legacyImplementation"(libs.yukihook.runtime.xposed82)
"legacyCompileOnly"(libs.xposed.framework.api)
}Traditional Method
dependencies {
implementation("com.highcapable.yukihookapi:yukihook-core:<version>")
ksp("com.highcapable.yukihookapi:yukihook-compiler:<version>")
"modernImplementation"("com.highcapable.yukihookapi:yukihook-runtime-libxposed:<version>")
"modernCompileOnly"("io.github.libxposed:api:<libxposed-version>")
"legacyImplementation"("com.highcapable.yukihookapi:yukihook-runtime-xposed82:<version>")
"legacyCompileOnly"("de.robv.android.xposed:api:82")
}Please change <version> to the version displayed at the top of this document, and refer to the documentation of the corresponding base module for <libxposed-version>.
The modern variant above uses the yukihook-runtime-libxposed base module, and the legacy variant uses the yukihook-runtime-xposed82 base module.
Notice
Please keep the buildConfig option enabled, because the yukihook-runtime-xposed82 base module depends on it, for details please refer to Module Package Name.
Directory Structure
The shared hook code is placed in the main source set, and the entry class and dedicated configuration of each variant are placed in the source set of the corresponding variant.
The following example
src
├─ main
│ ├─ AndroidManifest.xml
│ └─ java/io/github/mymodule/hook/HookEntry.kt
├─ modern
│ └─ java/io/github/mymodule/hook/ModernHookEntry.kt
└─ legacy
├─ AndroidManifest.xml
└─ java/io/github/mymodule/hook/LegacyHookEntry.ktCreate Entry Classes
Create a class implementing the YukiHookXposedModule interface in the main source set, and write your hook code in it.
The following example
object HookEntry : YukiHookXposedModule {
override fun onInit() = configure {
// Your code here.
}
override fun onHook() = encase {
loadApp("io.github.myapp") {
// Your code here.
}
}
}Next, create an entry class in the source set of each variant, add the entry annotation for the corresponding base module, and hand the implementation over to the shared class with Kotlin interface delegation.
The following example
@YukiHookLibXposedEntry(
targetApiVersion = 101,
scope = ["io.github.myapp"]
)
object ModernHookEntry : YukiHookXposedModule by HookEntry@YukiHookXposed82Entry
object LegacyHookEntry : YukiHookXposedModule by HookEntryFor the parameters of the entry annotations, please refer to the documentation of the corresponding base module.
Pay Attention
The shared entry class must not have an entry annotation, otherwise each build variant contains two entry annotations, which causes the compilation to fail.
Module Information
The two base modules read module information in different ways, but they are merged into one AndroidManifest.xml, so you can configure them separately.
For details, please refer to yukihook-runtime-libxposed → Module Information and yukihook-runtime-xposed82 → Module Information.
Notice
Please make sure to keep the common AndroidManifest.xml configuration in the main source set, and put the base module specific configuration in the AndroidManifest.xml of the corresponding variant.
Base Module Specific Features
Some features are only available in specific base modules, such as Module Shared Files and Module Scope.
When using these features in the shared code, you need to check the current base module first.
The following example
if (YukiHook.Status.runtime == YukiHookRuntime.LIBXPOSED) {
val names = sharedFiles.list()
}Notice
The features provided by the base modules themselves, such as registerFrameworkEvents, are used differently in the two base modules, you can only use them in the source set of the corresponding variant.
Build and Release
Each build variant generates a separate APK, such as assembleModernRelease and assembleLegacyRelease, you need to release them separately and tell users in the release notes to choose which APK to install based on the hook framework they use.
Notice
The packaged APKs have the same package name, so they cannot be installed on the same device at the same time, otherwise they will overwrite each other.