diff --git a/docs-source/src/en/config/api-example.md b/docs-source/src/en/config/api-example.md index 45d16617..19bb2a08 100644 --- a/docs-source/src/en/config/api-example.md +++ b/docs-source/src/en/config/api-example.md @@ -1,9 +1,397 @@ -# API Basic Configs * +# API Basic Configs + +> The basic configuration method of `YukiHookAPI` is introduced here. + +## Function Configs + +> Either [Use as Xposed Module Configs](../config/xposed-using) or [Use as Hook API Configs](../config/api-using), you can specify `YukiHookAPI` for configuration. + +### configs Method + +```kotlin:no-line-numbers +fun configs(initiate: Configs.() -> Unit) +``` + +The `configs` method implements a `lambda` method body on the `Configs` class, which you can easily call for configuration. + +::: tip + +For more functions, please refer to the [YukiHookAPI.configs](../api/public/com/highcapable/yukihookapi/YukiHookAPI#configs-method) method. + +::: + +## Hooker Configs + +> The most important part of an Xposed Module or Hook API is the creation and use of Hooker. `YukiHookAPI` provides two ways to use it. + +### Created by lambda + +> This solution is the simplest. If your module has few functions and a small amount of code, and does not need to be classified, it is recommended to create it in this way. + +#### encase Method + +```kotlin:no-line-numbers +fun encase(initiate: PackageParam.() -> Unit) +``` + +The `encase` method is the beginning of all Hook life. In a Module App or a Hook process, the `encase` method can only be used once to create a Hooker. + +`PackageParam` is an important instance object of the Host App, and `PackageParam` is used to implement all Hook operations on the current Hook object. + +::: tip + +For more functions, please refer to [PackageParam](../api/public/com/highcapable/yukihookapi/hook/param/PackageParam). + +::: + +The `encase` method can be created in the `onHook` method using two schemes. + +> Sample Code 1 + +```kotlin +YukiHookAPI.encase { + loadApp(name = "com.example.demo") { + findClass(name = "$packageName.DemoClass").hook { + // Your code here. + } + } +} +``` + +> Sample Code 2 + +```kotlin +encase { + loadApp(name = "com.example.demo") { + findClass(name = "$packageName.DemoClass").hook { + // Your code here. + } + } +} +``` + +Do your Hook operations in the `encase` method. + +### Created by Custom Hooker + +> This scheme is more suitable for large-scale projects, such as the need to classify Hooker or classify the role of Hook. + +#### encase Method + +```kotlin:no-line-numbers +fun encase(vararg hooker: YukiBaseHooker) +``` + +Also for the `encase` method, the variable array parameter `hooker` of the method here provides an object for creating an entry, you can load all Hookers extends `YukiBaseHooker` at one time. + +#### YukiBaseHooker Usage + +`YukiBaseHooker` extends `PackageParam`, you need to extends your child Hooker from `YukiBaseHooker`. + +::: tip + +For more functions, please refer to [YukiBaseHooker](../api/public/com/highcapable/yukihookapi/hook/entity/YukiBaseHooker). + +::: + +> The following example + +```kotlin +object CustomHooker : YukiBaseHooker() { + + override fun onHook() { + // Your code here. + } +} +``` + +Child Hooker **recommended** singleton `object` creation, you can also use `class` but not recommended. ::: warning -The current page has not been translated yet. +You don't need to re-call **encase** in the **onHook** method extends **YukiBaseHooker**, this is wrong and **will not take effect**, you should start writing your Hook code directly . -If necessary, please temporarily switch to the **Simplified Chinese** page, or help us improve the translation of this page. +::: + +> The following example + +```kotlin +object CustomHooker : YukiBaseHooker() { + + override fun onHook() { + loadApp(name = "com.example.demo1") { + findClass(name = "$packageName.DemoClass").hook { + // Your code here. + } + } + loadApp(name = "com.example.demo2") { + findClass(name = "$packageName.CustomClass").hook { + // Your code here. + } + } + } +} +``` + +As a child hooker, you can also call the `loadApp` method externally, and then directly start the Hook internally. + +> The following example + +```kotlin +class HookEntry : IYukiHookXposedInit { + + override fun onHook() = encase { + loadApp(name = "com.example.demo", ChildCustomHooker) + } +} + +object ChildCustomHooker : YukiBaseHooker() { + + override fun onHook() { + findClass(name = "$packageName.DemoClass").hook { + // Your code here. + } + } +} +``` + +You can use the `loadHooker` method to load another Hooker in multiple layers in the child Hooker, please do as you like. + +> The following example + +```kotlin +object FirstHooker : YukiBaseHooker() { + + override fun onHook() { + findClass(name = "$packageName.DemoClass").hook { + // Your code here. + } + loadHooker(SecondHooker) + loadHooker(ThirdHooker) + } +} +``` + +Once all Hookers are set up, you can load your Hooker in the `onHook` method of your `HookEntryClass`. + +> The following example + +```kotlin +class HookEntry : IYukiHookXposedInit { + + override fun onHook() = + YukiHookAPI.encase(FirstHooker, SecondHooker, ThirdHooker ...) +} +``` + +Of course, we can also abbreviate it. + +> The following example + +```kotlin +class HookEntry : IYukiHookXposedInit { + + override fun onHook() = encase(FirstHooker, SecondHooker, ThirdHooker ...) +} +``` + +### Expansion Features + +If your current Hook Framework supports and enables the Resources Hook feature, you can now create Resources Hooks directly in `encase`. + +You don't need to separate the `initZygote`, `handleLoadPackage`, `handleInitPackageResources` methods to perform different functions as before using the Xposed API. + +In `YukiHookAPI`, these functions **are seamless**. + +> The following example + +```kotlin +encase { + loadApp(name = "com.example.demo") { + findClass(name = "$packageName.DemoClass").hook { + // Your code here. + } + // Create a Resources Hook (fixed usage) + resources().hook { + // Your code here. + } + } +} +``` + +You can also use the `loadZygote` method to load the first event `initZygote` after a new process has been forked. + +> The following example + +```kotlin +encase { + loadZygote { + ActivityClass.hook { + // Your code here. + } + // Create a Resources Hook in Zygote + resources().hook { + // Your code here. + } + } + loadApp(name = "com.example.demo") { + findClass(name = "$packageName.DemoClass").hook { + // Your code here. + } + // Create a Resources Hook in the app + resources().hook { + // Your code here. + } + } +} +``` + +### Precautions + +It is wrong to load Hooker directly or start Hook directly, `encase` event will go through three callbacks after being loaded by Hook Framework. + +- load `initZygote` → `encase` + +- load `handleLoadPackage` → `encase` + +- load `handleInitPackageResources` → `encase` + +In this process, you need to use `loadApp`, `loadSystem`, `loadZygote` to distinguish the calling domain of each loading code, +otherwise your code will be executed **multiple times and cause errors**. + +::: warning + +Whether you use **encase** to create the **lambda** method body or use the Hooker form directly, you should not directly load the Hooker or start the Hook directly in the first **onHook** event. + +::: + +Below are two **error** examples. + +> Sample Code 1 + +```kotlin +encase { + // ❗ Wrong usage, can't start Hook directly + findClass(name = "com.example.demo.DemoClass").hook { + // ... + } + // ❗ Wrong usage, can't start Hook directly + resources().hook { + // ... + } +} +``` + +> Sample Code 2 + +```kotlin +class HookEntry : IYukiHookXposedInit { + + override fun onHook() { + // + encase { + loadHooker(CustomHooker) + } + // + encase(CustomHooker) + } +} + +object CustomHooker : YukiBaseHooker() { + + override fun onHook() { + // ❗ Wrong method of use, because there is no judgment object in the outer layer, you cannot start Hook directly + findClass(name = "com.example.demo.DemoClass").hook { + // ... + } + } +} +``` + +Below is a **correct** example of the wrong example above. + +> Sample Code 1 + +```kotlin +encase { + // ✅ Correct usage, load in Zygote + loadZygote(CustomHooker) + // ✅ Correct usage, load in Zygote + loadZygote { + // ✅ Correct usage, Hook in Zygote + resources().hook { + // ... + } + } + // ✅ The correct way to use it, use the app scope to load + loadApp(/** name parameter optional */, hooker = CustomHooker) + // ✅ The correct way to use it, load the Hooker after judging the scope of the app + loadApp(/** name parameter optional */) { + loadHooker(CustomHooker) + // ✅ Correct usage, Hook in app scope + findClass(name = "com.example.demo.DemoClass").hook { + // ... + } + // ✅ Correct usage, Hook in app scope + resources().hook { + // ... + } + } +} +``` + +> Sample Code 2 + +```kotlin +class HookEntry : IYukiHookXposedInit { + + override fun onHook() { + encase(CustomHooker) + } +} + +object CustomHooker : YukiBaseHooker() { + + override fun onHook() { + // ✅ The correct method of use, since there is no judgment object in the outer layer + // it is necessary to judge the scope of the app before performing Hook + loadApp(/** name parameter optional */) { + findClass(name = "com.example.demo.DemoClass").hook { + // ... + } + } + } +} +``` + +## Precautions when using as Hook API + +If you are using it as a Hook API, then you only need to differentiate the `encase` method at the entry point. + +::: warning + +The **encase** method provides two identical methods for use as a Hook API, but with only one more parameter **baseContext** than the previous two. + +::: + +> Method 1 + +```kotlin:no-line-numbers +fun encase(baseContext: Context?, initiate: PackageParam.() -> Unit) +``` + +> Method 2 + +```kotlin:no-line-numbers +fun encase(baseContext: Context?, vararg hooker: YukiBaseHooker) +``` + +The `baseContext` here only needs to fill in the `Context` you got at `attachBaseContext`, and other usages are exactly the same as the above. + +::: danger + +Never use the **encase** method in an Xposed way without omitting the **baseContext** parameter, this will lead to your Hook not work at all. + +The Resources Hook feature is not supported as Hook API. ::: \ No newline at end of file