From 6d23b85541cb8f1f3db76a0cf863973c2d0a9117 Mon Sep 17 00:00:00 2001 From: fankesyooni Date: Tue, 9 Aug 2022 23:56:04 +0800 Subject: [PATCH] Added injectModuleAppResources on Resources function in YukiHookFactory --- docs/api/public/YukiHookFactory.md | 15 ++++++++--- .../hook/factory/YukiHookFactory.kt | 27 ++++++++++--------- .../hook/xposed/bridge/YukiHookBridge.kt | 20 +++++++------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/docs/api/public/YukiHookFactory.md b/docs/api/public/YukiHookFactory.md index 9e728aa6..b4f9a0f7 100644 --- a/docs/api/public/YukiHookFactory.md +++ b/docs/api/public/YukiHookFactory.md @@ -114,17 +114,21 @@ val Context.processName: String fun Context.injectModuleAppResources() ``` +```kotlin +fun Resources.injectModuleAppResources() +``` + **变更记录** `v1.0.93` `新增` **功能描述** -> 向 Hook APP (宿主) `Context` 注入当前 Xposed 模块的资源。 +> 向 Hook APP (宿主) `Context` 或 `Resources` 注入当前 Xposed 模块的资源。 注入成功后,你就可以直接使用例如 `ImageView.setImageResource` 或 `Resources.getString` 装载当前 Xposed 模块的资源 ID。 -注入的资源作用域仅限当前 `Context`,你需要在每个用到宿主 `Context` 的地方重复调用此方法进行注入才能使用。 +注入的资源作用域仅限当前 `Context` 或 `Resources`,你需要在每个用到宿主 `Context` 或 `Resources` 的地方重复调用此方法进行注入才能使用。 为防止资源 ID 互相冲突,你需要在当前 Xposed 模块项目的 `build.gradle` 中修改资源 ID。 @@ -158,8 +162,10 @@ injectMember { } afterHook { instance().also { - // 注入模块资源 + // <方案1> 通过 Context 注入模块资源 it.injectModuleAppResources() + // <方案2> 直接得到宿主 Resources 注入模块资源 + it.resources.injectModuleAppResources() // 直接使用模块资源 ID it.getString(R.id.app_name) } @@ -175,7 +181,10 @@ injectMember { onAppLifecycle { onCreate { // 全局注入模块资源,但仅限于全局生命周期,类似 ImageView.setImageResource 这样的方法在 Activity 中需要单独注入 + // <方案1> 通过 Context 注入模块资源 injectModuleAppResources() + // <方案2> 直接得到宿主 Resources 注入模块资源 + resources.injectModuleAppResources() // 直接使用模块资源 ID getString(R.id.app_name) } diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.kt index 3ce65499..4fbf1579 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.kt @@ -107,21 +107,24 @@ val Context.processName * * 注入的资源作用域仅限当前 [Context] - 你需要在每个用到宿主 [Context] 的地方重复调用此方法进行注入才能使用 * - * 为防止资源 ID 互相冲突 - 你需要在当前 Xposed 模块项目的 build.gradle 中修改资源 ID - * - * - Kotlin Gradle DSL ↓ - * - * androidResources.additionalParameters("--allow-reserved-package-id", "--package-id", "0x64") - * - * - Groovy ↓ - * - * aaptOptions.additionalParameters '--allow-reserved-package-id', '--package-id', '0x64' - * - * - ❗提供的示例资源 ID 值仅供参考 - 为了防止当前宿主存在多个 Xposed 模块 - 建议自定义你自己的资源 ID + * 详情请参考 [injectModuleAppResources](https://fankes.github.io/YukiHookAPI/#/api/document?id=injectmoduleappresources-method) * * - ❗只能在 (Xposed) 宿主环境使用此功能 - 其它环境下使用将不生效且会打印警告信息 */ -fun Context.injectModuleAppResources() = YukiHookBridge.injectModuleAppResources(context = this) +fun Context.injectModuleAppResources() = resources?.injectModuleAppResources() + +/** + * 向 Hook APP (宿主) 指定 [Resources] 直接注入当前 Xposed 模块的资源 + * + * 注入成功后 - 你就可以直接使用例如 [ImageView.setImageResource] 或 [Resources.getString] 装载当前 Xposed 模块的资源 ID + * + * 注入的资源作用域仅限当前 [Resources] - 你需要在每个用到宿主 [Resources] 的地方重复调用此方法进行注入才能使用 + * + * 详情请参考 [injectModuleAppResources](https://fankes.github.io/YukiHookAPI/#/api/document?id=injectmoduleappresources-method) + * + * - ❗只能在 (Xposed) 宿主环境使用此功能 - 其它环境下使用将不生效且会打印警告信息 + */ +fun Resources.injectModuleAppResources() = YukiHookBridge.injectModuleAppResources(hostResources = this) /** * 仅判断模块是否在太极、无极中激活 diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt index b9db76d0..a1839f78 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/YukiHookBridge.kt @@ -101,8 +101,8 @@ object YukiHookBridge { /** 当前 [PackageParamWrapper] 实例数组 */ private val packageParamWrappers = HashMap() - /** 已被注入到宿主 [Context] 中的当前 Xposed 模块资源 HashCode 数组 */ - private val injectedHostContextHashCodes = HashSet() + /** 已被注入到宿主 [Resources] 中的当前 Xposed 模块资源 HashCode 数组 */ + private val injectedHostResourcesHashCodes = HashSet() /** 当前 [PackageParam] 方法体回调 */ internal var packageParamCallback: (PackageParam.() -> Unit)? = null @@ -336,20 +336,20 @@ object YukiHookBridge { } /** - * 向 Hook APP (宿主) [Context] 注入当前 Xposed 模块的资源 - * @param context 需要注入的 [Context] + * 向 Hook APP (宿主) 注入当前 Xposed 模块的资源 + * @param hostResources 需要注入的宿主 [Resources] */ - internal fun injectModuleAppResources(context: Context) { - if (injectedHostContextHashCodes.contains(context.hashCode())) return - injectedHostContextHashCodes.add(context.hashCode()) + internal fun injectModuleAppResources(hostResources: Resources) { + if (injectedHostResourcesHashCodes.contains(hostResources.hashCode())) return + injectedHostResourcesHashCodes.add(hostResources.hashCode()) if (hasXposedBridge) AssetManagerClass.method { name = "addAssetPath" param(StringType) }.ignored().onNoSuchMethod { - runCatching { injectedHostContextHashCodes.remove(context.hashCode()) } - yLoggerE(msg = "Failed to inject module resources in context [$context]", e = it) - }.get(context.resources.assets).call(moduleAppFilePath) + runCatching { injectedHostResourcesHashCodes.remove(hostResources.hashCode()) } + yLoggerE(msg = "Failed to inject module resources into [$hostResources]", e = it) + }.get(hostResources.assets).call(moduleAppFilePath) else yLoggerW(msg = "You can only inject module resources in Xposed Environment") }