From b64c9a4d69b1c7604892bc32a01f234fb0913046 Mon Sep 17 00:00:00 2001 From: Fankesyooni Date: Fri, 15 Apr 2022 04:30:34 +0800 Subject: [PATCH] Added ModuleApplication function and merge findClass function to Xposed API --- README.md | 7 +- demo-module/src/main/AndroidManifest.xml | 1 + .../application/DemoApplication.kt | 39 +++++++++ .../yukihookapi/demo_module/hook/HookEntry.kt | 3 +- docs/_coverpage.md | 2 +- docs/api/document.md | 2 + docs/api/public/ModuleApplication.md | 76 ++++++++++++++++ docs/config/api-exception.md | 17 ++++ docs/guide/quick-start.md | 4 + .../YukiHookXposedProcessor.kt | 58 +++++++++---- yukihookapi/build.gradle | 3 +- yukihookapi/libs/free-reflection.jar | Bin 0 -> 6286 bytes yukihookapi/libs/module-injector.jar | Bin 0 -> 703 bytes .../hook/factory/ReflectionFactory.kt | 14 ++- .../xposed/application/ModuleApplication.kt | 82 ++++++++++++++++++ 15 files changed, 287 insertions(+), 21 deletions(-) create mode 100644 demo-module/src/main/java/com/highcapable/yukihookapi/demo_module/application/DemoApplication.kt create mode 100644 docs/api/public/ModuleApplication.md create mode 100644 yukihookapi/libs/free-reflection.jar create mode 100644 yukihookapi/libs/module-injector.jar create mode 100644 yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.kt diff --git a/README.md b/README.md index a41da96e..8a9b8476 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ > 你或许可能会遇到浏览器缓存造成文档不是最新版本的问题,若已经查看过一次文档,请手动在每个页面上刷新,以获取最新版本或清除浏览器缓存。 -最新版本更新时间:2022-04-13 13:57 +最新版本更新时间:2022-04-15 04:30 ## Contacts @@ -49,6 +49,11 @@ - 工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。

+## 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) diff --git a/demo-module/src/main/AndroidManifest.xml b/demo-module/src/main/AndroidManifest.xml index 6b859da0..ff213c17 100644 --- a/demo-module/src/main/AndroidManifest.xml +++ b/demo-module/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="com.highcapable.yukihookapi.demo_module"> `更新时间 2022-04-13 13:57` +`更新时间 2022-04-15 04:30` [GitHub](https://github.com/fankes/YukiHookAPI) [Get Started](#介绍) diff --git a/docs/api/document.md b/docs/api/document.md index 5b40cb69..8a3e87c8 100644 --- a/docs/api/document.md +++ b/docs/api/document.md @@ -18,6 +18,8 @@ [filename](public/PrefsData.md ':include') +[filename](public/ModuleApplication.md ':include') + [filename](public/ComponentTypeFactory.md ':include') [filename](public/GraphicsTypeFactory.md ':include') diff --git a/docs/api/public/ModuleApplication.md b/docs/api/public/ModuleApplication.md new file mode 100644 index 00000000..0f50f9fa --- /dev/null +++ b/docs/api/public/ModuleApplication.md @@ -0,0 +1,76 @@ +## ModuleApplication [class] + +```kotlin +open class ModuleApplication: Application() +``` + +变更记录 + +`v1.0.76` `新增` + +功能描述 + +> 这是对使用 `YukiHookAPI` Xposed 模块实现中的一个扩展功能。 + +在你的 Xposed 模块的 `Application` 中继承此类。 + +或在 `AndroidManifest.xml` 的 `application` 标签中指定此类。 + +目前可实现功能如下 + +- 全局共享模块中静态的 `appContext` + +- 在模块与宿主中装载 `YukiHookAPI.Config` 以确保 `YukiHookAPI.Configs.debugTag` 不需要重复定义 + +- 在模块中使用系统隐藏 API,核心技术引用了开源项目 [FreeReflection](https://github.com/tiann/FreeReflection) + +功能示例 + +将此类继承到你的自定义 `Application` 上。 + +> 示例如下 + +```kotlin +package com.demo + +class MyApplication: ModuleApplication() { + + override fun onCreate() { + super.onCreate() + } +} +``` + +在 `AndroidManifest.xml` 的 `application` 标签中指定自定义的 `Application`。 + +> 示例如下 + +```xml + +``` + +如果你不需要自定义 `Application` 可以直接将 `ModuleApplication` 设置到 `AndroidManifest.xml` 的 `application` 标签中。 + +> 示例如下 + +```xml + +``` + +### appContext [field] + +```kotlin +val appContext: ModuleApplication +``` + +变更记录 + +`v1.0.76` `新增` + +功能描述 + +> 全局静态 `Application` 实例。 \ No newline at end of file diff --git a/docs/config/api-exception.md b/docs/config/api-exception.md index 4f7d1f9e..de673020 100644 --- a/docs/config/api-exception.md +++ b/docs/config/api-exception.md @@ -355,6 +355,23 @@ method { > 这些异常会直接导致 APP 停止运行(FC),同时会在控制台打印 `E` 级别的日志,还会造成 Hook 进程“死掉”。 +!> `IllegalStateException` App is dead, You cannot call to appContext + +异常原因 + +使用 `ModuleApplication` 时调用了 `appContext` 功能但是 APP 可能已经被销毁或没有正确启动。 + +> 示例如下 + +```kotlin +// 调用了此变量但是 APP 可能已被销毁或没有正确启动 +ModuleApplication.appContext +``` + +解决方案 + +这种情况基本不存在,由于 `appContext` 是在 `onCreate` 中被赋值的,除非遇到多进程并发启动或 APP 没有启动完成前被反射调用了父类的 `onCreate` 方法。 + !> `IllegalStateException` YukiHookModulePrefs not allowed in Custom Hook API 异常原因 diff --git a/docs/guide/quick-start.md b/docs/guide/quick-start.md index bae8f48a..9001a241 100644 --- a/docs/guide/quick-start.md +++ b/docs/guide/quick-start.md @@ -104,6 +104,10 @@ class MainHook : YukiHookXposedInitProxy { } ``` +你还可以将你的模块 APP 的 `Application` 继承于 `ModuleApplication` 以实现更多功能。 + +详情请参考 [ModuleApplication](api/document?id=moduleapplication-class)。 + 然后,你就可以开始编写 Hook 代码了。 有关作为 Xposed 模块使用的相关配置详细内容,你可以 [点击这里](config/xposed-using) 继续阅读。 diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt index a955135c..d5842c61 100644 --- a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt +++ b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt @@ -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" + diff --git a/yukihookapi/build.gradle b/yukihookapi/build.gradle index a3b6dbe1..436618bb 100644 --- a/yukihookapi/build.gradle +++ b/yukihookapi/build.gradle @@ -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' } diff --git a/yukihookapi/libs/free-reflection.jar b/yukihookapi/libs/free-reflection.jar new file mode 100644 index 0000000000000000000000000000000000000000..e21de47a806360a80c18b8e43607e69aee50f614 GIT binary patch literal 6286 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 J^eO&Y{Trr?tJ?qo literal 0 HcmV?d00001 diff --git a/yukihookapi/libs/module-injector.jar b/yukihookapi/libs/module-injector.jar new file mode 100644 index 0000000000000000000000000000000000000000..eafaf3d1b63a1b1a20051663c688d9d83ebae567 GIT binary patch literal 703 zcmWIWW@Zs#-~d7f21Ou-00SllhG+&|hUENQ{fx}?jO4_E#H5^5{mRnp%#8f}?8Jgh zeGsi*QIKDpnxdarP>_?EoLG{XpQoRhmzA1aqVJoZQks+Mh>(c)1WV)>=_ThR78i$x z@G`K&>;uuI72FJrEFcz`sL0`DU>9Kq@wYT?4LtA7h zp~BU&R^jvuk;hgqUhLYuW_MzJnEJv6@BRi}JR^2xHz{=V;f-yb)4FMobL1K-9> z<#ti-t2SY|OE#n}OiP?Q!FtlZo<7c(Rg1k(%vrHdVT$a_?(T|9!VgW~S4OS0I`uSe zdi$j#_mkA5PH8^8R(Q3A_i4h5PX|(NB->1LUV6-C!Wo0vtXW#Wde|G)W92-b8o%ss zk=|H*wcqw)l*+r?o=&a4PJ!pYL^bBTmgOvSKe|x++>)7l|CT@e*J1xbNaqP>^s{p| z@Az+ozHu*7@=IUG(KCO-TbIK8;}+%|=Knu&IHhhpn0mgWCF*Wu$6Spm{}$YQ@rWVv zulKVh4r#T$tg?n@mssvLXSY?&j84`QysVL>Q!8nrpQ)Gdb9qI$^_h+F6Lzg$_WZ=2 zmmPJb1`&R{!t59WyxBSSM!Q6KF)}cKVmZK@kx7IZkphtAq8SuG!4C#o8bQ { 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) } } } diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.kt new file mode 100644 index 00000000..6859e5b7 --- /dev/null +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.kt @@ -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() } +} \ No newline at end of file