Added "isUsingResourcesHook" function in InjectYukiHookWithXposed

This commit is contained in:
2022-05-31 01:20:23 +08:00
parent 58fa99012f
commit 2eff2988f6
10 changed files with 156 additions and 69 deletions

View File

@@ -110,6 +110,7 @@ class HookEntry : IYukiHookXposedInit {
} }
// 得到需要 Hook 的 Resources // 得到需要 Hook 的 Resources
// 需要 Hook Framework 支持 Resources Hook(资源钩子) 才能成功 // 需要 Hook Framework 支持 Resources Hook(资源钩子) 才能成功
// 在 Zygote 中的 Resources Hook 只需要 Hook Framework 支持 - 无需启用此功能
resources().hook { resources().hook {
// 注入要 Hook 的 Resources // 注入要 Hook 的 Resources
injectResource { injectResource {
@@ -260,7 +261,7 @@ class HookEntry : IYukiHookXposedInit {
} }
} }
// 得到需要 Hook 的 Resources // 得到需要 Hook 的 Resources
// 需要 Hook Framework 支持 Resources Hook(资源钩子) 才能成功 // 需要 Hook Framework 支持 Resources Hook(资源钩子) 且启用此功能才能成功
resources().hook { resources().hook {
// 注入要 Hook 的 Resources // 注入要 Hook 的 Resources
injectResource { injectResource {

View File

@@ -4,7 +4,8 @@
annotation class InjectYukiHookWithXposed( annotation class InjectYukiHookWithXposed(
val sourcePath: String, val sourcePath: String,
val modulePackageName: String, val modulePackageName: String,
val entryClassName: String val entryClassName: String,
val isUsingResourcesHook: Boolean
) )
``` ```
@@ -16,6 +17,10 @@ annotation class InjectYukiHookWithXposed(
新增 `entryClassName` 参数 新增 `entryClassName` 参数
`v1.0.92` `修改`
新增 `isUsingResourcesHook` 参数
**功能描述** **功能描述**
> 标识 `YukiHookAPI` 注入 Xposed 入口的类注解。 > 标识 `YukiHookAPI` 注入 Xposed 入口的类注解。

View File

@@ -623,6 +623,8 @@ inline fun HookResources.hook(initiate: YukiResourcesHookCreater.() -> Unit)
> Hook APP 的 Resources。 > Hook APP 的 Resources。
!> 请注意你需要确保当前 Hook Framework 支持且 `InjectYukiHookWithXposed.isUsingResourcesHook` 已启用。
**功能示例** **功能示例**
Resources Hook 为固定用法,获取 `resources` 对象,然后调用 `hook` 方法开始 Hook。 Resources Hook 为固定用法,获取 `resources` 对象,然后调用 `hook` 方法开始 Hook。

View File

@@ -184,6 +184,8 @@ val isSupportResourcesHook: Boolean
!> 在 Xposed 环境中可能会延迟等待事件回调后才会返回 true。 !> 在 Xposed 环境中可能会延迟等待事件回调后才会返回 true。
!> 请注意你需要确保 `InjectYukiHookWithXposed.isUsingResourcesHook` 已启用,否则始终返回 false。
### Configs [object] ### Configs [object]
```kotlin ```kotlin

View File

@@ -18,7 +18,8 @@
annotation class InjectYukiHookWithXposed( annotation class InjectYukiHookWithXposed(
val sourcePath: String, val sourcePath: String,
val modulePackageName: String, val modulePackageName: String,
val entryClassName: String val entryClassName: String,
val isUsingResourcesHook: Boolean
) )
``` ```
@@ -96,7 +97,7 @@ Xposed 入口类处理如下。
> 示例如下 > 示例如下
```kotlin ```kotlin
class HookEntry_YukiHookXposedInit: IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources class HookEntry_YukiHookXposedInit: IXposedHookZygoteInit, IXposedHookLoadPackage, ...
``` ```
编译后的类名结构如下。 编译后的类名结构如下。
@@ -123,7 +124,7 @@ Xposed 入口类处理如下。
> 示例如下 > 示例如下
```kotlin ```kotlin
class HookXposedEntry: IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources class HookXposedEntry: IXposedHookZygoteInit, IXposedHookLoadPackage, ...
``` ```
编译后的类名结构如下。 编译后的类名结构如下。
@@ -138,6 +139,56 @@ class HookXposedEntry: IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHoo
!> 你定义的 `entryClassName` 不可与 `xposed_init` 中的类名相同,否则自动处理程序<u>会在编译时抛出异常</u> !> 你定义的 `entryClassName` 不可与 `xposed_init` 中的类名相同,否则自动处理程序<u>会在编译时抛出异常</u>
#### isUsingResourcesHook 参数
`isUsingResourcesHook` 决定了自动处理程序是否生成针对 Resources Hook 的相关代码,此功能默认是启用的。
启用后生成的入口类将为如下所示。
> 示例如下
```kotlin
class _YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources {
override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) {
// ...
}
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
// ...
}
override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {
// ...
}
}
```
若你当前的项目并不需要用到 Reources Hook可以设置 `isUsingResourcesHook = false` 来关闭自动生成。
> 示例如下
```kotlin
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
```
关闭后生成的入口类将为如下所示。
> 示例如下
```kotlin
class _YukiHookXposedInit : IXposedHookZygoteInit, IXposedHookLoadPackage {
override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) {
// ...
}
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
// ...
}
}
```
### IYukiHookXposedInit 接口 ### IYukiHookXposedInit 接口
`IYukiHookXposedInit` 接口为你的 `HookEntryClass` 必须实现的接口,这是你的模块开始 Hook 的起点。 `IYukiHookXposedInit` 接口为你的 `HookEntryClass` 必须实现的接口,这是你的模块开始 Hook 的起点。

View File

@@ -103,8 +103,14 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
* @param sourcePath 指定的 source 路径 * @param sourcePath 指定的 source 路径
* @param modulePackageName 模块包名 * @param modulePackageName 模块包名
* @param xInitClassName xposed_init 入口类名 * @param xInitClassName xposed_init 入口类名
* @param isUsingResourcesHook 是否启用 Resources Hook
*/ */
fun fetchKSClassDeclaration(sourcePath: String, modulePackageName: String, xInitClassName: String) { fun fetchKSClassDeclaration(
sourcePath: String,
modulePackageName: String,
xInitClassName: String,
isUsingResourcesHook: Boolean
) {
asSequence().filterIsInstance<KSClassDeclaration>().forEach { asSequence().filterIsInstance<KSClassDeclaration>().forEach {
if (isInjectOnce) when { if (isInjectOnce) when {
it.superTypes.any { type -> type.element.toString() == "IYukiHookXposedInit" } -> { it.superTypes.any { type -> type.element.toString() == "IYukiHookXposedInit" } -> {
@@ -117,7 +123,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
entryClassName = it.simpleName.asString(), entryClassName = it.simpleName.asString(),
xInitClassName = xcName xInitClassName = xcName
) )
injectClass(it.packageName.asString(), modulePackageName, it.simpleName.asString(), xcName) injectClass(it.packageName.asString(), modulePackageName, it.simpleName.asString(), xcName, isUsingResourcesHook)
} }
it.superTypes.any { type -> type.element.toString() == "YukiHookXposedInitProxy" } -> it.superTypes.any { type -> type.element.toString() == "YukiHookXposedInitProxy" } ->
problem(msg = "\"YukiHookXposedInitProxy\" was deprecated, please replace to \"IYukiHookXposedInit\"") problem(msg = "\"YukiHookXposedInitProxy\" was deprecated, please replace to \"IYukiHookXposedInit\"")
@@ -133,6 +139,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
var sourcePath = "" // 项目相对路径 var sourcePath = "" // 项目相对路径
var modulePackageName = "" // 模块包名 var modulePackageName = "" // 模块包名
var entryClassName = "" // xposed_init 入口类名 var entryClassName = "" // xposed_init 入口类名
var isUsingResourcesHook = false // 是否启用 Resources Hook
e.arguments.forEach { pease -> e.arguments.forEach { pease ->
if (pease.name?.asString() == "sourcePath") if (pease.name?.asString() == "sourcePath")
sourcePath = pease.value.toString().trim() sourcePath = pease.value.toString().trim()
@@ -140,6 +147,8 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
modulePackageName = pease.value.toString().trim() modulePackageName = pease.value.toString().trim()
if (pease.name?.asString() == "entryClassName") if (pease.name?.asString() == "entryClassName")
entryClassName = pease.value.toString().trim() entryClassName = pease.value.toString().trim()
if (pease.name?.asString() == "isUsingResourcesHook")
isUsingResourcesHook = pease.value as Boolean
} }
if ((modulePackageName.startsWith(".") || if ((modulePackageName.startsWith(".") ||
modulePackageName.endsWith(".") || modulePackageName.endsWith(".") ||
@@ -151,7 +160,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
true.let { for (i in 0..9) if (entryClassName.startsWith(i.toString())) return@let true;false }) true.let { for (i in 0..9) if (entryClassName.startsWith(i.toString())) return@let true;false })
&& entryClassName.isNotEmpty() && entryClassName.isNotEmpty()
) problem(msg = "Invalid entryClassName \"$entryClassName\"") ) problem(msg = "Invalid entryClassName \"$entryClassName\"")
else fetchKSClassDeclaration(sourcePath, modulePackageName, entryClassName) else fetchKSClassDeclaration(sourcePath, modulePackageName, entryClassName, isUsingResourcesHook)
} }
} }
} }
@@ -207,58 +216,64 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
* @param modulePackageName 模块包名 * @param modulePackageName 模块包名
* @param entryClassName 入口类名 * @param entryClassName 入口类名
* @param xInitClassName xposed_init 入口类名 * @param xInitClassName xposed_init 入口类名
* @param isUsingResourcesHook 是否启用 Resources Hook
*/ */
private fun injectClass(packageName: String, modulePackageName: String, entryClassName: String, xInitClassName: String) = private fun injectClass(
environment(ignoredError = true) { packageName: String,
if (modulePackageName.isNotBlank()) modulePackageName: String,
warn(msg = "You set the customize module package name to \"$modulePackageName\", please check for yourself if it is correct") entryClassName: String,
val fModulePackageName = modulePackageName.ifBlank { xInitClassName: String,
if (packageName.contains(other = ".hook.") || packageName.endsWith(suffix = ".hook")) isUsingResourcesHook: Boolean
packageName.split(".hook")[0] ) = environment(ignoredError = true) {
else error("Cannot identify your Module App's package name, please manually configure the package name") if (modulePackageName.isNotBlank())
} warn(msg = "You set the customize module package name to \"$modulePackageName\", please check for yourself if it is correct")
val mdAppInjectPackageName = "com.highcapable.yukihookapi.hook.xposed.application.inject" val fModulePackageName = modulePackageName.ifBlank {
val ykBridgeInjectPackageName = "com.highcapable.yukihookapi.hook.xposed.bridge.inject" if (packageName.contains(other = ".hook.") || packageName.endsWith(suffix = ".hook"))
/** 插入 ModuleApplication_Injector 代码 */ packageName.split(".hook")[0]
codeGenerator.createNewFile( else error("Cannot identify your Module App's package name, please manually configure the package name")
dependencies = Dependencies.ALL_FILES,
packageName = mdAppInjectPackageName,
fileName = "ModuleApplication_Injector"
).apply {
write(CodeSourceFileTemplate.getModuleApplicationInjectorFileByteArray(mdAppInjectPackageName, packageName, entryClassName))
flush()
close()
}
/** 插入 YukiHookBridge_Injector 代码 */
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = ykBridgeInjectPackageName,
fileName = "YukiHookBridge_Injector"
).apply {
write(CodeSourceFileTemplate.getYukiHookBridgeInjectorFileByteArray(ykBridgeInjectPackageName))
flush()
close()
}
/** 插入 xposed_init 代码 */
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = packageName,
fileName = xInitClassName
).apply {
write(CodeSourceFileTemplate.getXposedInitFileByteArray(packageName, entryClassName, xInitClassName))
flush()
close()
}
/** 插入 xposed_init_Impl 代码 */
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = packageName,
fileName = "${entryClassName}_Impl"
).apply {
write(CodeSourceFileTemplate.getXposedInitImplFileByteArray(packageName, fModulePackageName, entryClassName))
flush()
close()
}
} }
val mdAppInjectPackageName = "com.highcapable.yukihookapi.hook.xposed.application.inject"
val ykBridgeInjectPackageName = "com.highcapable.yukihookapi.hook.xposed.bridge.inject"
/** 插入 ModuleApplication_Injector 代码 */
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = mdAppInjectPackageName,
fileName = "ModuleApplication_Injector"
).apply {
write(CodeSourceFileTemplate.getModuleApplicationInjectorFileByteArray(mdAppInjectPackageName, packageName, entryClassName))
flush()
close()
}
/** 插入 YukiHookBridge_Injector 代码 */
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = ykBridgeInjectPackageName,
fileName = "YukiHookBridge_Injector"
).apply {
write(CodeSourceFileTemplate.getYukiHookBridgeInjectorFileByteArray(ykBridgeInjectPackageName))
flush()
close()
}
/** 插入 xposed_init 代码 */
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = packageName,
fileName = xInitClassName
).apply {
write(CodeSourceFileTemplate.getXposedInitFileByteArray(packageName, entryClassName, xInitClassName, isUsingResourcesHook))
flush()
close()
}
/** 插入 xposed_init_Impl 代码 */
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = packageName,
fileName = "${entryClassName}_Impl"
).apply {
write(CodeSourceFileTemplate.getXposedInitImplFileByteArray(packageName, fModulePackageName, entryClassName))
flush()
close()
}
}
} }
} }

View File

@@ -101,9 +101,10 @@ object CodeSourceFileTemplate {
* @param packageName 包名 * @param packageName 包名
* @param entryClassName 入口类名 * @param entryClassName 入口类名
* @param xInitClassName xposed_init 入口类名 * @param xInitClassName xposed_init 入口类名
* @param isUsingResourcesHook 是否启用 Resources Hook
* @return [ByteArray] * @return [ByteArray]
*/ */
fun getXposedInitFileByteArray(packageName: String, entryClassName: String, xInitClassName: String) = fun getXposedInitFileByteArray(packageName: String, entryClassName: String, xInitClassName: String, isUsingResourcesHook: Boolean) =
("@file:Suppress(\"ClassName\")\n" + ("@file:Suppress(\"ClassName\")\n" +
"\n" + "\n" +
"package $packageName\n" + "package $packageName\n" +
@@ -111,16 +112,17 @@ object CodeSourceFileTemplate {
"import androidx.annotation.Keep\n" + "import androidx.annotation.Keep\n" +
"import com.highcapable.yukihookapi.hook.xposed.bridge.event.YukiXposedEvent\n" + "import com.highcapable.yukihookapi.hook.xposed.bridge.event.YukiXposedEvent\n" +
"import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" + "import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" +
"import de.robv.android.xposed.IXposedHookInitPackageResources\n" + (if (isUsingResourcesHook) "import de.robv.android.xposed.IXposedHookInitPackageResources\n" else "") +
"import de.robv.android.xposed.IXposedHookLoadPackage\n" + "import de.robv.android.xposed.IXposedHookLoadPackage\n" +
"import de.robv.android.xposed.IXposedHookZygoteInit\n" + "import de.robv.android.xposed.IXposedHookZygoteInit\n" +
"import de.robv.android.xposed.callbacks.XC_InitPackageResources\n" + (if (isUsingResourcesHook) "import de.robv.android.xposed.callbacks.XC_InitPackageResources\n" else "") +
"import de.robv.android.xposed.callbacks.XC_LoadPackage\n" + "import de.robv.android.xposed.callbacks.XC_LoadPackage\n" +
"\n" + "\n" +
getCommentContent(entryClassName, currrentClassTag = "Xposed Init") + getCommentContent(entryClassName, currrentClassTag = "Xposed Init") +
"@Keep\n" + "@Keep\n" +
"@YukiGenerateApi\n" + "@YukiGenerateApi\n" +
"class $xInitClassName : IXposedHookZygoteInit, IXposedHookLoadPackage, IXposedHookInitPackageResources {\n" + "class $xInitClassName : IXposedHookZygoteInit, IXposedHookLoadPackage" +
"${if (isUsingResourcesHook) ", IXposedHookInitPackageResources" else ""} {\n" +
"\n" + "\n" +
" override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" + " override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" +
" ${entryClassName}_Impl.callInitZygote(sparam)\n" + " ${entryClassName}_Impl.callInitZygote(sparam)\n" +
@@ -131,11 +133,11 @@ object CodeSourceFileTemplate {
" ${entryClassName}_Impl.callHandleLoadPackage(lpparam)\n" + " ${entryClassName}_Impl.callHandleLoadPackage(lpparam)\n" +
" YukiXposedEvent.EventHandler.callHandleLoadPackage(lpparam)\n" + " YukiXposedEvent.EventHandler.callHandleLoadPackage(lpparam)\n" +
" }\n" + " }\n" +
"\n" + (if (isUsingResourcesHook)
" override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" + ("\n override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" +
" ${entryClassName}_Impl.callHandleInitPackageResources(resparam)\n" + " ${entryClassName}_Impl.callHandleInitPackageResources(resparam)\n" +
" YukiXposedEvent.EventHandler.callHandleInitPackageResources(resparam)\n" + " YukiXposedEvent.EventHandler.callHandleInitPackageResources(resparam)\n" +
" }\n" + " }\n") else "") +
"}").toByteArray() "}").toByteArray()
/** /**

View File

@@ -34,6 +34,7 @@ import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import com.highcapable.yukihookapi.YukiHookAPI.configs import com.highcapable.yukihookapi.YukiHookAPI.configs
import com.highcapable.yukihookapi.YukiHookAPI.encase import com.highcapable.yukihookapi.YukiHookAPI.encase
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder import com.highcapable.yukihookapi.hook.core.finder.ConstructorFinder
import com.highcapable.yukihookapi.hook.core.finder.FieldFinder import com.highcapable.yukihookapi.hook.core.finder.FieldFinder
import com.highcapable.yukihookapi.hook.core.finder.MethodFinder import com.highcapable.yukihookapi.hook.core.finder.MethodFinder
@@ -143,6 +144,8 @@ object YukiHookAPI {
* - ❗在模块环境中需要启用 [Configs.isEnableHookModuleStatus] * - ❗在模块环境中需要启用 [Configs.isEnableHookModuleStatus]
* *
* - ❗在 Xposed 环境中可能会延迟等待事件回调后才会返回 true * - ❗在 Xposed 环境中可能会延迟等待事件回调后才会返回 true
*
* - ❗请注意你需要确保 [InjectYukiHookWithXposed.isUsingResourcesHook] 已启用 - 否则始终返回 false
* @return [Boolean] 是否支持 * @return [Boolean] 是否支持
*/ */
val isSupportResourcesHook val isSupportResourcesHook

View File

@@ -29,6 +29,7 @@ package com.highcapable.yukihookapi.annotation.xposed
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
import de.robv.android.xposed.IXposedHookInitPackageResources
/** /**
* 标识 [YukiHookAPI] 注入 Xposed 入口的类注解 * 标识 [YukiHookAPI] 注入 Xposed 入口的类注解
@@ -61,10 +62,12 @@ import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
* @param sourcePath 你的项目 source 相对路径 - 默认为 ..src/main.. * @param sourcePath 你的项目 source 相对路径 - 默认为 ..src/main..
* @param modulePackageName 模块包名 - 使用标准路径可不填会自动生成 * @param modulePackageName 模块包名 - 使用标准路径可不填会自动生成
* @param entryClassName 定义 [YukiHookAPI] 自动生成 Xposed 模块入口类的名称 - 不填默认使用 HookEntryClass_YukiHookXposedInit 进行生成 * @param entryClassName 定义 [YukiHookAPI] 自动生成 Xposed 模块入口类的名称 - 不填默认使用 HookEntryClass_YukiHookXposedInit 进行生成
* @param isUsingResourcesHook 是否启用 Resources Hook (资源钩子) - 启用后将自动注入 [IXposedHookInitPackageResources] - 默认是
*/ */
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
annotation class InjectYukiHookWithXposed( annotation class InjectYukiHookWithXposed(
val sourcePath: String = "src/main", val sourcePath: String = "src/main",
val modulePackageName: String = "", val modulePackageName: String = "",
val entryClassName: String = "" val entryClassName: String = "",
val isUsingResourcesHook: Boolean = true
) )

View File

@@ -36,6 +36,7 @@ import android.content.pm.ApplicationInfo
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.bean.HookClass import com.highcapable.yukihookapi.hook.bean.HookClass
import com.highcapable.yukihookapi.hook.bean.HookResources import com.highcapable.yukihookapi.hook.bean.HookResources
import com.highcapable.yukihookapi.hook.bean.VariousClass import com.highcapable.yukihookapi.hook.bean.VariousClass
@@ -375,6 +376,8 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
/** /**
* Hook APP 的 Resources * Hook APP 的 Resources
*
* - ❗请注意你需要确保当前 Hook Framework 支持且 [InjectYukiHookWithXposed.isUsingResourcesHook] 已启用
* @param initiate 方法体 * @param initiate 方法体
*/ */
inline fun HookResources.hook(initiate: YukiResourcesHookCreater.() -> Unit) = inline fun HookResources.hook(initiate: YukiResourcesHookCreater.() -> Unit) =