Added ModuleApplication function and merge findClass function to Xposed API

This commit is contained in:
2022-04-15 04:30:34 +08:00
parent 099ac65e55
commit b64c9a4d69
15 changed files with 287 additions and 21 deletions

View File

@@ -24,7 +24,7 @@
> 你或许可能会遇到浏览器缓存造成文档不是最新版本的问题,若已经查看过一次文档,请手动在每个页面上刷新,以获取最新版本或清除浏览器缓存。 > 你或许可能会遇到浏览器缓存造成文档不是最新版本的问题,若已经查看过一次文档,请手动在每个页面上刷新,以获取最新版本或清除浏览器缓存。
最新版本更新时间2022-04-13 13:57 最新版本更新时间2022-04-15 04:30
## Contacts ## Contacts
@@ -49,6 +49,11 @@
- 工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。<br/><br/> - 工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。<br/><br/>
<img src="https://github.com/fankes/YuKiHookAPI/blob/master/img-src/wechat_code.jpg" width = "200" height = "200"/> <img src="https://github.com/fankes/YuKiHookAPI/blob/master/img-src/wechat_code.jpg" width = "200" height = "200"/>
## Third-Party Open Source Usage Statement
- [Kotlin Symbol Processing API](https://github.com/google/ksp)
- [FreeReflection](https://github.com/tiann/FreeReflection)
## License ## License
- [MIT](https://choosealicense.com/licenses/mit) - [MIT](https://choosealicense.com/licenses/mit)

View File

@@ -3,6 +3,7 @@
package="com.highcapable.yukihookapi.demo_module"> package="com.highcapable.yukihookapi.demo_module">
<application <application
android:name=".application.DemoApplication"
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_icon" android:icon="@mipmap/ic_icon"
android:label="@string/app_name" android:label="@string/app_name"

View File

@@ -0,0 +1,39 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/4/15.
*/
package com.highcapable.yukihookapi.demo_module.application
import com.highcapable.yukihookapi.hook.log.loggerD
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
class DemoApplication : ModuleApplication() {
override fun onCreate() {
super.onCreate()
loggerD(msg = "I am running in module space")
}
}

View File

@@ -45,7 +45,8 @@ class HookEntry : YukiHookXposedInitProxy {
// 可简写为 configs {} // 可简写为 configs {}
YukiHookAPI.configs { YukiHookAPI.configs {
// 全局调试用的 TAG // 全局调试用的 TAG
debugTag = "YukiHookAPI" // 在 Logcat 控制台过滤此 TAG 可找到详细日志
debugTag = "YukiHookAPI-Demo"
// 是否开启调试模式 // 是否开启调试模式
isDebug = true isDebug = true
// 是否启用调试日志的输出功能 // 是否启用调试日志的输出功能

View File

@@ -12,7 +12,7 @@
- 方便移植 快速上手 - 方便移植 快速上手
<font size=3 style="opacity: 0.6">`更新时间 2022-04-13 13:57`</font> <font size=3 style="opacity: 0.6">`更新时间 2022-04-15 04:30`</font>
[GitHub](https://github.com/fankes/YukiHookAPI) [GitHub](https://github.com/fankes/YukiHookAPI)
[Get Started](#介绍) [Get Started](#介绍)

View File

@@ -18,6 +18,8 @@
[filename](public/PrefsData.md ':include') [filename](public/PrefsData.md ':include')
[filename](public/ModuleApplication.md ':include')
[filename](public/ComponentTypeFactory.md ':include') [filename](public/ComponentTypeFactory.md ':include')
[filename](public/GraphicsTypeFactory.md ':include') [filename](public/GraphicsTypeFactory.md ':include')

View File

@@ -0,0 +1,76 @@
## ModuleApplication [class]
```kotlin
open class ModuleApplication: Application()
```
<b>变更记录</b>
`v1.0.76` `新增`
<b>功能描述</b>
> 这是对使用 `YukiHookAPI` Xposed 模块实现中的一个扩展功能。
在你的 Xposed 模块的 `Application` 中继承此类。
或在 `AndroidManifest.xml``application` 标签中指定此类。
目前可实现功能如下
- 全局共享模块中静态的 `appContext`
- 在模块与宿主中装载 `YukiHookAPI.Config` 以确保 `YukiHookAPI.Configs.debugTag` 不需要重复定义
- 在模块中使用系统隐藏 API核心技术引用了开源项目 [FreeReflection](https://github.com/tiann/FreeReflection)
<b>功能示例</b>
将此类继承到你的自定义 `Application` 上。
> 示例如下
```kotlin
package com.demo
class MyApplication: ModuleApplication() {
override fun onCreate() {
super.onCreate()
}
}
```
`AndroidManifest.xml``application` 标签中指定自定义的 `Application`
> 示例如下
```xml
<application
android:name="com.demo.MyApplication"
...>
```
如果你不需要自定义 `Application` 可以直接将 `ModuleApplication` 设置到 `AndroidManifest.xml``application` 标签中。
> 示例如下
```xml
<application
android:name="com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication"
...>
```
### appContext [field]
```kotlin
val appContext: ModuleApplication
```
<b>变更记录</b>
`v1.0.76` `新增`
<b>功能描述</b>
> 全局静态 `Application` 实例。

View File

@@ -355,6 +355,23 @@ method {
> 这些异常会直接导致 APP 停止运行(FC),同时会在控制台打印 `E` 级别的日志,还会造成 Hook 进程“死掉”。 > 这些异常会直接导致 APP 停止运行(FC),同时会在控制台打印 `E` 级别的日志,还会造成 Hook 进程“死掉”。
!> `IllegalStateException` App is dead, You cannot call to appContext
<b>异常原因</b>
使用 `ModuleApplication` 时调用了 `appContext` 功能但是 APP 可能已经被销毁或没有正确启动。
> 示例如下
```kotlin
// 调用了此变量但是 APP 可能已被销毁或没有正确启动
ModuleApplication.appContext
```
<b>解决方案</b>
这种情况基本不存在,由于 `appContext` 是在 `onCreate` 中被赋值的,除非遇到多进程并发启动或 APP 没有启动完成前被反射调用了父类的 `onCreate` 方法。
!> `IllegalStateException` YukiHookModulePrefs not allowed in Custom Hook API !> `IllegalStateException` YukiHookModulePrefs not allowed in Custom Hook API
<b>异常原因</b> <b>异常原因</b>

View File

@@ -104,6 +104,10 @@ class MainHook : YukiHookXposedInitProxy {
} }
``` ```
你还可以将你的模块 APP 的 `Application` 继承于 `ModuleApplication` 以实现更多功能。
详情请参考 [ModuleApplication](api/document?id=moduleapplication-class)。
然后,你就可以开始编写 Hook 代码了。 然后,你就可以开始编写 Hook 代码了。
有关作为 Xposed 模块使用的相关配置详细内容,你可以 [点击这里](config/xposed-using) 继续阅读。 有关作为 Xposed 模块使用的相关配置详细内容,你可以 [点击这里](config/xposed-using) 继续阅读。

View File

@@ -211,9 +211,49 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
packageName.split(".hook")[0] packageName.split(".hook")[0]
else error(msg = "Cannot identify your App's package name, please manually configure the package name") else error(msg = "Cannot identify your App's package name, please manually configure the package name")
} }
val injectPackageName = "com.highcapable.yukihookapi.hook.xposed.application.inject"
fun commentContent(name: String) = ("/**\n" +
" * $name Inject Class\n" +
" *\n" +
" * Compiled from YukiHookXposedProcessor\n" +
" *\n" +
" * HookEntryClass: [$className]\n" +
" *\n" +
" * Generate Date: ${SimpleDateFormat.getDateTimeInstance().format(Date())}\n" +
" *\n" +
" * Powered by YukiHookAPI (C) HighCapable 2022\n" +
" *\n" +
" * Project Address: [YukiHookAPI](https://github.com/fankes/YukiHookAPI)\n" +
" */\n")
codeGenerator.createNewFile( codeGenerator.createNewFile(
Dependencies.ALL_FILES, dependencies = Dependencies.ALL_FILES,
packageName, packageName = injectPackageName,
fileName = "ModuleApplication_Injector"
).apply {
/** 插入 ModuleApplication_Injector 代码 */
write(
("@file:Suppress(\"ClassName\")\n" +
"\n" +
"package $injectPackageName\n" +
"\n" +
"import $packageName.$className\n" +
"\n" +
commentContent(name = "ModuleApplication") +
"object ModuleApplication_Injector {\n" +
"\n" +
" @JvmStatic\n" +
" fun callApiInit() = try {\n" +
" $className().onInit()\n" +
" } catch (_: Throwable) {\n" +
" }\n" +
"}").toByteArray()
)
flush()
close()
}
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = packageName,
fileName = "$className$xposedClassShortName" fileName = "$className$xposedClassShortName"
).apply { ).apply {
/** 插入 xposed_init 代码 */ /** 插入 xposed_init 代码 */
@@ -232,19 +272,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
"import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" + "import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" +
"import $packageName.$className\n" + "import $packageName.$className\n" +
"\n" + "\n" +
"/**\n" + commentContent(name = "XposedInit") +
" * XposedInit Inject Class\n" +
" *\n" +
" * Compiled from YukiHookXposedProcessor\n" +
" *\n" +
" * HookEntryClass: [$className]\n" +
" *\n" +
" * Generate Date: ${SimpleDateFormat.getDateTimeInstance().format(Date())}\n" +
" *\n" +
" * Powered by YukiHookAPI (C) HighCapable 2022\n" +
" *\n" +
" * Project Address: https://github.com/fankes/YukiHookAPI\n" +
" */\n" +
"@Keep\n" + "@Keep\n" +
"@YukiGenerateApi\n" + "@YukiGenerateApi\n" +
"class $className$xposedClassShortName : IXposedHookLoadPackage {\n" + "class $className$xposedClassShortName : IXposedHookLoadPackage {\n" +

View File

@@ -40,7 +40,8 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
dependencies { dependencies {
// Used 82 API Version // Used 82 API Version
compileOnly 'de.robv.android.xposed:api:82' compileOnly 'de.robv.android.xposed:api:82'
compileOnly fileTree(include: ['android-stub.jar'], dir: 'libs') compileOnly fileTree(include: ['android-stub.jar', 'module-injector.jar'], dir: 'libs')
implementation fileTree(include: ['free-reflection.jar'], dir: 'libs')
implementation 'androidx.annotation:annotation:1.3.0' implementation 'androidx.annotation:annotation:1.3.0'
} }

Binary file not shown.

Binary file not shown.

View File

@@ -29,6 +29,7 @@
package com.highcapable.yukihookapi.hook.factory package com.highcapable.yukihookapi.hook.factory
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.bean.CurrentClass import com.highcapable.yukihookapi.hook.bean.CurrentClass
import com.highcapable.yukihookapi.hook.bean.HookClass import com.highcapable.yukihookapi.hook.bean.HookClass
import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder
@@ -36,6 +37,7 @@ import com.highcapable.yukihookapi.hook.core.finder.FieldFinder
import com.highcapable.yukihookapi.hook.core.finder.MethodFinder import com.highcapable.yukihookapi.hook.core.finder.MethodFinder
import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules import com.highcapable.yukihookapi.hook.core.finder.type.ModifierRules
import com.highcapable.yukihookapi.hook.store.MemberCacheStore import com.highcapable.yukihookapi.hook.store.MemberCacheStore
import de.robv.android.xposed.XposedHelpers
import java.lang.reflect.Constructor import java.lang.reflect.Constructor
import java.lang.reflect.Field import java.lang.reflect.Field
import java.lang.reflect.Member import java.lang.reflect.Member
@@ -71,8 +73,16 @@ val String.hasClass get() = hasClass(loader = null)
fun classOf(name: String, loader: ClassLoader? = null): Class<*> { fun classOf(name: String, loader: ClassLoader? = null): Class<*> {
val hashCode = ("[$name][$loader]").hashCode() val hashCode = ("[$name][$loader]").hashCode()
return MemberCacheStore.findClass(hashCode) ?: run { return MemberCacheStore.findClass(hashCode) ?: run {
(if (loader == null) Class.forName(name) when {
else loader.loadClass(name)).also { MemberCacheStore.putClass(hashCode, it) } YukiHookAPI.hasXposedBridge ->
runCatching { XposedHelpers.findClassIfExists(name, loader) }.getOrNull()
?: when (loader) {
null -> Class.forName(name)
else -> loader.loadClass(name)
}
loader == null -> Class.forName(name)
else -> loader.loadClass(name)
}.also { MemberCacheStore.putClass(hashCode, it) }
} }
} }

View File

@@ -0,0 +1,82 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/4/15.
*/
package com.highcapable.yukihookapi.hook.xposed.application
import android.app.Application
import android.content.Context
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
import com.highcapable.yukihookapi.hook.xposed.application.inject.ModuleApplication_Injector
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
import me.weishu.reflection.Reflection
/**
* 这是对使用 [YukiHookAPI] Xposed 模块实现中的一个扩展功能
*
* 在你的 Xposed 模块的 [Application] 中继承此类
*
* 或在 AndroidManifest.xml 的 application 标签中指定此类
*
* 目前可实现功能如下
*
* - 全局共享模块中静态的 [appContext]
*
* - 在模块与宿主中装载 [YukiHookAPI.Configs] 以确保 [YukiHookAPI.Configs.debugTag] 不需要重复定义
*
* - 在模块中使用系统隐藏 API - 核心技术引用了开源项目 [FreeReflection](https://github.com/tiann/FreeReflection)
*
* 详情请参考 [ModuleApplication](https://fankes.github.io/YukiHookAPI/#/api/document?id=moduleapplication-class)
*/
open class ModuleApplication : Application() {
companion object {
/** 全局静态 [Application] 实例 */
private var currentContext: ModuleApplication? = null
/**
* 全局静态 [Application] 实例
* @throws IllegalStateException 如果 [Application] 没有正确装载完成
*/
val appContext get() = currentContext ?: error("App is dead, You cannot call to appContext")
}
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
Reflection.unseal(base)
}
override fun onCreate() {
super.onCreate()
currentContext = this
callApiInit()
}
/** 调用入口类的 [YukiHookXposedInitProxy.onInit] 方法 */
private fun callApiInit() = runCatching { ModuleApplication_Injector.callApiInit() }
}