mirror of
https://github.com/HighCapable/YukiHookAPI.git
synced 2025-09-06 10:45:47 +08:00
Added injectModuleAppResources function in YukiHookFactory
This commit is contained in:
@@ -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} -->
|
||||||
|
|
||||||
**变更记录**
|
**变更记录**
|
||||||
|
@@ -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)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 仅判断模块是否在太极、无极中激活
|
* 仅判断模块是否在太极、无极中激活
|
||||||
*
|
*
|
||||||
|
@@ -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 }
|
||||||
|
Reference in New Issue
Block a user