Added injectModuleAppResources function in YukiHookFactory

This commit is contained in:
2022-08-08 00:12:28 +08:00
parent 55dfe81ecc
commit cc16bbaef3
3 changed files with 120 additions and 1 deletions

View File

@@ -108,6 +108,80 @@ val Context.processName: String
> 获取当前进程名称。 > 获取当前进程名称。
### injectModuleAppResources [method]
```kotlin
fun Context.injectModuleAppResources()
```
**变更记录**
`v1.0.93` `新增`
**功能描述**
> 向 Hook APP (宿主) `Context` 注入当前 Xposed 模块的资源。
注入成功后,你就可以直接使用例如 `ImageView.setImageResource``Resources.getString` 装载当前 Xposed 模块的资源 ID。
注入的资源作用域仅限当前 `Context`,你需要在每个用到宿主 `Context` 的地方重复调用此方法进行注入才能使用。
为防止资源 ID 互相冲突,你需要在当前 Xposed 模块项目的 `build.gradle` 中修改资源 ID。
- Kotlin Gradle DSL
```kotlin
androidResources.additionalParameters("--allow-reserved-package-id", "--package-id", "0x64")
```
- Groovy
```groovy
aaptOptions.additionalParameters '--allow-reserved-package-id', '--package-id', '0x64'
```
!> 提供的示例资源 ID 值仅供参考,为了防止当前宿主存在多个 Xposed 模块,建议自定义你自己的资源 ID。
!> 只能在 (Xposed) 宿主环境使用此功能,其它环境下使用将不生效且会打印警告信息。
**功能示例**
在 Hook 宿主之后,我们可以直接在 Hooker 中得到的 `Context` 注入当前模块资源。
> 示例如下
```kotlin
injectMember {
method {
name = "onCreate"
param(BundleClass)
}
afterHook {
instance<Activity>().also {
// 注入模块资源
it.injectModuleAppResources()
// 直接使用模块资源 ID
it.getString(R.id.app_name)
}
}
}
```
你还可以直接在 `AppLifecycle` 中注入当前模块资源。
> 示例如下
```kotlin
onAppLifecycle {
onCreate {
// 全局注入模块资源,但仅限于全局生命周期,类似 ImageView.setImageResource 这样的方法在 Activity 中需要单独注入
injectModuleAppResources()
// 直接使用模块资源 ID
getString(R.id.app_name)
}
}
```
### ~~isSupportResourcesHook [field]~~ <!-- {docsify-ignore} --> ### ~~isSupportResourcesHook [field]~~ <!-- {docsify-ignore} -->
**变更记录** **变更记录**

View File

@@ -31,12 +31,15 @@ package com.highcapable.yukihookapi.hook.factory
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.Resources
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Process import android.os.Process
import android.widget.ImageView
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.param.PackageParam import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
@@ -97,6 +100,29 @@ val Context.processName
} }
}.getOrNull() ?: packageName ?: "" }.getOrNull() ?: packageName ?: ""
/**
* 向 Hook APP (宿主) [Context] 注入当前 Xposed 模块的资源
*
* 注入成功后 - 你就可以直接使用例如 [ImageView.setImageResource] 或 [Resources.getString] 装载当前 Xposed 模块的资源 ID
*
* 注入的资源作用域仅限当前 [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
*
* - ❗只能在 (Xposed) 宿主环境使用此功能 - 其它环境下使用将不生效且会打印警告信息
*/
fun Context.injectModuleAppResources() = YukiHookBridge.injectModuleAppResources(context = this)
/** /**
* 仅判断模块是否在太极、无极中激活 * 仅判断模块是否在太极、无极中激活
* *

View File

@@ -41,6 +41,7 @@ import android.content.res.Resources
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.YukiGenerateApi import com.highcapable.yukihookapi.annotation.YukiGenerateApi
import com.highcapable.yukihookapi.hook.factory.hasClass import com.highcapable.yukihookapi.hook.factory.hasClass
import com.highcapable.yukihookapi.hook.log.yLoggerE
import com.highcapable.yukihookapi.hook.log.yLoggerW import com.highcapable.yukihookapi.hook.log.yLoggerW
import com.highcapable.yukihookapi.hook.param.PackageParam import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.param.type.HookEntryType import com.highcapable.yukihookapi.hook.param.type.HookEntryType
@@ -91,7 +92,10 @@ object YukiHookBridge {
private val loadedPackageNames = HashSet<String>() private val loadedPackageNames = HashSet<String>()
/** 当前 [PackageParamWrapper] 实例数组 */ /** 当前 [PackageParamWrapper] 实例数组 */
private var packageParamWrappers = HashMap<String, PackageParamWrapper>() private val packageParamWrappers = HashMap<String, PackageParamWrapper>()
/** 已被注入到宿主 [Context] 中的当前 Xposed 模块资源 HashCode 数组 */
private val injectedHostContextHashCodes = HashSet<Int>()
/** 当前 [PackageParam] 方法体回调 */ /** 当前 [PackageParam] 方法体回调 */
internal var packageParamCallback: (PackageParam.() -> Unit)? = null internal var packageParamCallback: (PackageParam.() -> Unit)? = null
@@ -322,6 +326,21 @@ object YukiHookBridge {
} }
} }
/**
* 向 Hook APP (宿主) [Context] 注入当前 Xposed 模块的资源
* @param context 需要注入的 [Context]
*/
internal fun injectModuleAppResources(context: Context) {
if (injectedHostContextHashCodes.contains(context.hashCode())) return
if (hasXposedBridge)
runCatching {
YukiHookHelper.findMethod(AssetManagerClass, name = "addAssetPath", StringType)
.invoke(context.resources.assets, moduleAppFilePath)
injectedHostContextHashCodes.add(context.hashCode())
}.onFailure { yLoggerE(msg = "Failed to inject module resources in context [$context]", e = it) }
else yLoggerW(msg = "You can only inject module resources in Xposed Environment")
}
/** 刷新当前 Xposed 模块自身 [Resources] */ /** 刷新当前 Xposed 模块自身 [Resources] */
internal fun refreshModuleAppResources() { internal fun refreshModuleAppResources() {
dynamicModuleAppResources?.let { moduleAppResources = it } dynamicModuleAppResources?.let { moduleAppResources = it }