mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-04 09:45:19 +08:00
Added ModuleApplication function and merge findClass function to Xposed API
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
|
||||
> 你或许可能会遇到浏览器缓存造成文档不是最新版本的问题,若已经查看过一次文档,请手动在每个页面上刷新,以获取最新版本或清除浏览器缓存。
|
||||
|
||||
最新版本更新时间:2022-04-13 13:57
|
||||
最新版本更新时间:2022-04-15 04:30
|
||||
|
||||
## Contacts
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
- 工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。<br/><br/>
|
||||
<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
|
||||
|
||||
- [MIT](https://choosealicense.com/licenses/mit)
|
||||
|
@@ -3,6 +3,7 @@
|
||||
package="com.highcapable.yukihookapi.demo_module">
|
||||
|
||||
<application
|
||||
android:name=".application.DemoApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_icon"
|
||||
android:label="@string/app_name"
|
||||
|
@@ -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")
|
||||
}
|
||||
}
|
@@ -45,7 +45,8 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
// 可简写为 configs {}
|
||||
YukiHookAPI.configs {
|
||||
// 全局调试用的 TAG
|
||||
debugTag = "YukiHookAPI"
|
||||
// 在 Logcat 控制台过滤此 TAG 可找到详细日志
|
||||
debugTag = "YukiHookAPI-Demo"
|
||||
// 是否开启调试模式
|
||||
isDebug = true
|
||||
// 是否启用调试日志的输出功能
|
||||
|
@@ -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)
|
||||
[Get Started](#介绍)
|
||||
|
@@ -18,6 +18,8 @@
|
||||
|
||||
[filename](public/PrefsData.md ':include')
|
||||
|
||||
[filename](public/ModuleApplication.md ':include')
|
||||
|
||||
[filename](public/ComponentTypeFactory.md ':include')
|
||||
|
||||
[filename](public/GraphicsTypeFactory.md ':include')
|
||||
|
76
docs/api/public/ModuleApplication.md
Normal file
76
docs/api/public/ModuleApplication.md
Normal 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` 实例。
|
@@ -355,6 +355,23 @@ method {
|
||||
|
||||
> 这些异常会直接导致 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
|
||||
|
||||
<b>异常原因</b>
|
||||
|
@@ -104,6 +104,10 @@ class MainHook : YukiHookXposedInitProxy {
|
||||
}
|
||||
```
|
||||
|
||||
你还可以将你的模块 APP 的 `Application` 继承于 `ModuleApplication` 以实现更多功能。
|
||||
|
||||
详情请参考 [ModuleApplication](api/document?id=moduleapplication-class)。
|
||||
|
||||
然后,你就可以开始编写 Hook 代码了。
|
||||
|
||||
有关作为 Xposed 模块使用的相关配置详细内容,你可以 [点击这里](config/xposed-using) 继续阅读。
|
||||
|
@@ -211,9 +211,49 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
|
||||
packageName.split(".hook")[0]
|
||||
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(
|
||||
Dependencies.ALL_FILES,
|
||||
packageName,
|
||||
dependencies = Dependencies.ALL_FILES,
|
||||
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"
|
||||
).apply {
|
||||
/** 插入 xposed_init 代码 */
|
||||
@@ -232,19 +272,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
|
||||
"import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" +
|
||||
"import $packageName.$className\n" +
|
||||
"\n" +
|
||||
"/**\n" +
|
||||
" * 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" +
|
||||
commentContent(name = "XposedInit") +
|
||||
"@Keep\n" +
|
||||
"@YukiGenerateApi\n" +
|
||||
"class $className$xposedClassShortName : IXposedHookLoadPackage {\n" +
|
||||
|
@@ -40,7 +40,8 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||
dependencies {
|
||||
// Used 82 API Version
|
||||
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'
|
||||
}
|
||||
|
||||
|
BIN
yukihookapi/libs/free-reflection.jar
Normal file
BIN
yukihookapi/libs/free-reflection.jar
Normal file
Binary file not shown.
BIN
yukihookapi/libs/module-injector.jar
Normal file
BIN
yukihookapi/libs/module-injector.jar
Normal file
Binary file not shown.
@@ -29,6 +29,7 @@
|
||||
|
||||
package com.highcapable.yukihookapi.hook.factory
|
||||
|
||||
import com.highcapable.yukihookapi.YukiHookAPI
|
||||
import com.highcapable.yukihookapi.hook.bean.CurrentClass
|
||||
import com.highcapable.yukihookapi.hook.bean.HookClass
|
||||
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.type.ModifierRules
|
||||
import com.highcapable.yukihookapi.hook.store.MemberCacheStore
|
||||
import de.robv.android.xposed.XposedHelpers
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Member
|
||||
@@ -71,8 +73,16 @@ val String.hasClass get() = hasClass(loader = null)
|
||||
fun classOf(name: String, loader: ClassLoader? = null): Class<*> {
|
||||
val hashCode = ("[$name][$loader]").hashCode()
|
||||
return MemberCacheStore.findClass(hashCode) ?: run {
|
||||
(if (loader == null) Class.forName(name)
|
||||
else loader.loadClass(name)).also { MemberCacheStore.putClass(hashCode, it) }
|
||||
when {
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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() }
|
||||
}
|
Reference in New Issue
Block a user