Added new functions to confirm the feature

This commit is contained in:
2022-03-18 04:10:34 +08:00
parent 106591e4f9
commit 8ee4d079d6
5 changed files with 128 additions and 26 deletions

View File

@@ -38,7 +38,7 @@ import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
@InjectYukiHookWithXposed @InjectYukiHookWithXposed
class HookEntry : YukiHookXposedInitProxy { class HookEntry : YukiHookXposedInitProxy {
override fun onHook() { override fun onInit() {
// 配置 YuKiHookAPI // 配置 YuKiHookAPI
// 可简写为 configs {} // 可简写为 configs {}
YukiHookAPI.configs { YukiHookAPI.configs {
@@ -48,7 +48,14 @@ class HookEntry : YukiHookXposedInitProxy {
isDebug = true isDebug = true
// 是否启用调试日志的输出功能 // 是否启用调试日志的输出功能
isAllowPrintingLogs = true isAllowPrintingLogs = true
// 是否启用 [YukiHookModulePrefs] 的键值缓存功能
// 若无和模块频繁交互数据在宿主重新启动之前建议开启
// 若需要实时交互数据建议关闭或从 [YukiHookModulePrefs] 中进行动态配置
isEnableModulePrefsCache = true
} }
}
override fun onHook() {
// 开始你的 Hook // 开始你的 Hook
// 可简写为 encase {} // 可简写为 encase {}
YukiHookAPI.encase { YukiHookAPI.encase {

View File

@@ -246,7 +246,13 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
" override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" + " override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" +
" if (lpparam == null) return\n" + " if (lpparam == null) return\n" +
" try {\n" + " try {\n" +
" $className().onInit()\n" +
" if (YukiHookAPI.isXposedCallbackSetUp) {\n" +
" loggerE(tag = \"YukiHookAPI\", msg = \"You cannot loading a hooker in \\\"onInit\\\" method! Aborted\")\n" +
" return\n" +
" }\n" +
" $className().onHook()\n" + " $className().onHook()\n" +
" YukiHookAPI.onXposedInitialized()\n" +
" } catch (e: Throwable) {\n" + " } catch (e: Throwable) {\n" +
" loggerE(tag = \"YukiHookAPI\", msg = \"YukiHookAPI try to load HookEntryClass failed\", e = e)\n" + " loggerE(tag = \"YukiHookAPI\", msg = \"YukiHookAPI try to load HookEntryClass failed\", e = e)\n" +
" }\n" + " }\n" +

View File

@@ -40,6 +40,7 @@ import com.highcapable.yukihookapi.hook.factory.processName
import com.highcapable.yukihookapi.hook.log.* import com.highcapable.yukihookapi.hook.log.*
import com.highcapable.yukihookapi.hook.param.PackageParam import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper import com.highcapable.yukihookapi.hook.param.wrapper.PackageParamWrapper
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
@@ -60,12 +61,25 @@ object YukiHookAPI {
/** 是否还未输出欢迎信息 */ /** 是否还未输出欢迎信息 */
private var isShowSplashLogOnceTime = true private var isShowSplashLogOnceTime = true
/** Xposed 是否装载完成 */
private var isXposedInitialized = false
/** 获取当前 [YukiHookAPI] 的版本 */ /** 获取当前 [YukiHookAPI] 的版本 */
const val API_VERSION_NAME = "1.0.4" const val API_VERSION_NAME = "1.0.4"
/** 获取当前 [YukiHookAPI] 的版本号 */ /** 获取当前 [YukiHookAPI] 的版本号 */
const val API_VERSION_CODE = 5 const val API_VERSION_CODE = 5
/**
* 模块是否装载了 Xposed 回调方法
*
* - ❗此变量为私有功能性 API - 你不应该手动调用此变量
* @return [Boolean]
*/
@DoNotUseField
val isXposedCallbackSetUp
get() = !isXposedInitialized && packageParamCallback != null
/** /**
* 预设的 Xposed 模块包名 * 预设的 Xposed 模块包名
* *
@@ -140,6 +154,15 @@ object YukiHookAPI {
* 当 [isAllowPrintingLogs] 关闭后 [isDebug] 也将同时关闭 * 当 [isAllowPrintingLogs] 关闭后 [isDebug] 也将同时关闭
*/ */
var isAllowPrintingLogs = true var isAllowPrintingLogs = true
/**
* 是否启用 [YukiHookModulePrefs] 的键值缓存功能
*
* - 为防止内存复用过高问题 - 此功能默认启用
*
* 你可以手动在 [YukiHookModulePrefs] 中自由开启和关闭缓存功能以及清除缓存
*/
var isEnableModulePrefsCache = true
} }
/** /**
@@ -151,6 +174,16 @@ object YukiHookAPI {
*/ */
fun configs(initiate: Configs.() -> Unit) = Configs.apply(initiate) fun configs(initiate: Configs.() -> Unit) = Configs.apply(initiate)
/**
* 标识 Xposed API 装载完成
*
* - ❗装载代码将自动生成 - 你不应该手动使用此方法装载 Xposed 模块事件
*/
@DoNotUseMethod
fun onXposedInitialized() {
isXposedInitialized = true
}
/** /**
* 装载 Xposed API 回调 * 装载 Xposed API 回调
* *

View File

@@ -79,6 +79,9 @@ class YukiHookModulePrefs(private val context: Context? = null) {
/** 缓存数据 */ /** 缓存数据 */
private var xPrefCacheKeyValueFloats = HashMap<String, Float>() private var xPrefCacheKeyValueFloats = HashMap<String, Float>()
/** 是否使用键值缓存 */
private var isUsingKeyValueCache = YukiHookAPI.Configs.isEnableModulePrefsCache
/** 检查是否处于自定义 Hook API 状态 */ /** 检查是否处于自定义 Hook API 状态 */
private fun checkApiInBaseContext() { private fun checkApiInBaseContext() {
if (YukiHookAPI.isLoadedFromBaseContext) error("YukiHookModulePrefs not allowed in Custom Hook API") if (YukiHookAPI.isLoadedFromBaseContext) error("YukiHookModulePrefs not allowed in Custom Hook API")
@@ -124,10 +127,24 @@ class YukiHookModulePrefs(private val context: Context? = null) {
* @return [YukiHookModulePrefs] * @return [YukiHookModulePrefs]
*/ */
fun name(name: String): YukiHookModulePrefs { fun name(name: String): YukiHookModulePrefs {
isUsingKeyValueCache = YukiHookAPI.Configs.isEnableModulePrefsCache
prefsName = name prefsName = name
return this return this
} }
/**
* 忽略缓存直接读取键值
*
* 无论是否开启 [YukiHookAPI.Configs.isEnableModulePrefsCache]
*
* - 仅在 [XSharedPreferences] 下生效
* @return [YukiHookModulePrefs]
*/
fun direct(): YukiHookModulePrefs {
isUsingKeyValueCache = false
return this
}
/** /**
* 获取 [String] 键值 * 获取 [String] 键值
* *
@@ -138,12 +155,14 @@ class YukiHookModulePrefs(private val context: Context? = null) {
*/ */
fun getString(key: String, default: String = "") = fun getString(key: String, default: String = "") =
(if (isXposedEnvironment) (if (isXposedEnvironment)
xPrefCacheKeyValueStrings[key].let { if (isUsingKeyValueCache)
(it ?: xPref.getString(key, default) ?: default).let { value -> xPrefCacheKeyValueStrings[key].let {
xPrefCacheKeyValueStrings[key] = value (it ?: xPref.getString(key, default) ?: default).let { value ->
value xPrefCacheKeyValueStrings[key] = value
value
}
} }
} else xPref.getString(key, default) ?: default
else sPref.getString(key, default) ?: default).let { else sPref.getString(key, default) ?: default).let {
makeWorldReadable() makeWorldReadable()
it it
@@ -159,12 +178,14 @@ class YukiHookModulePrefs(private val context: Context? = null) {
*/ */
fun getBoolean(key: String, default: Boolean = false) = fun getBoolean(key: String, default: Boolean = false) =
(if (isXposedEnvironment) (if (isXposedEnvironment)
xPrefCacheKeyValueBooleans[key].let { if (isUsingKeyValueCache)
it ?: xPref.getBoolean(key, default).let { value -> xPrefCacheKeyValueBooleans[key].let {
xPrefCacheKeyValueBooleans[key] = value it ?: xPref.getBoolean(key, default).let { value ->
value xPrefCacheKeyValueBooleans[key] = value
value
}
} }
} else xPref.getBoolean(key, default)
else sPref.getBoolean(key, default)).let { else sPref.getBoolean(key, default)).let {
makeWorldReadable() makeWorldReadable()
it it
@@ -180,12 +201,14 @@ class YukiHookModulePrefs(private val context: Context? = null) {
*/ */
fun getInt(key: String, default: Int = 0) = fun getInt(key: String, default: Int = 0) =
(if (isXposedEnvironment) (if (isXposedEnvironment)
xPrefCacheKeyValueInts[key].let { if (isUsingKeyValueCache)
it ?: xPref.getInt(key, default).let { value -> xPrefCacheKeyValueInts[key].let {
xPrefCacheKeyValueInts[key] = value it ?: xPref.getInt(key, default).let { value ->
value xPrefCacheKeyValueInts[key] = value
value
}
} }
} else xPref.getInt(key, default)
else sPref.getInt(key, default)).let { else sPref.getInt(key, default)).let {
makeWorldReadable() makeWorldReadable()
it it
@@ -201,12 +224,14 @@ class YukiHookModulePrefs(private val context: Context? = null) {
*/ */
fun getFloat(key: String, default: Float = 0f) = fun getFloat(key: String, default: Float = 0f) =
(if (isXposedEnvironment) (if (isXposedEnvironment)
xPrefCacheKeyValueFloats[key].let { if (isUsingKeyValueCache)
it ?: xPref.getFloat(key, default).let { value -> xPrefCacheKeyValueFloats[key].let {
xPrefCacheKeyValueFloats[key] = value it ?: xPref.getFloat(key, default).let { value ->
value xPrefCacheKeyValueFloats[key] = value
value
}
} }
} else xPref.getFloat(key, default)
else sPref.getFloat(key, default)).let { else sPref.getFloat(key, default)).let {
makeWorldReadable() makeWorldReadable()
it it
@@ -222,12 +247,14 @@ class YukiHookModulePrefs(private val context: Context? = null) {
*/ */
fun getLong(key: String, default: Long = 0L) = fun getLong(key: String, default: Long = 0L) =
(if (isXposedEnvironment) (if (isXposedEnvironment)
xPrefCacheKeyValueLongs[key].let { if (isUsingKeyValueCache)
it ?: xPref.getLong(key, default).let { value -> xPrefCacheKeyValueLongs[key].let {
xPrefCacheKeyValueLongs[key] = value it ?: xPref.getLong(key, default).let { value ->
value xPrefCacheKeyValueLongs[key] = value
value
}
} }
} else xPref.getLong(key, default)
else sPref.getLong(key, default)).let { else sPref.getLong(key, default)).let {
makeWorldReadable() makeWorldReadable()
it it
@@ -321,4 +348,19 @@ class YukiHookModulePrefs(private val context: Context? = null) {
sPref.edit().putLong(key, value).apply() sPref.edit().putLong(key, value).apply()
makeWorldReadable() makeWorldReadable()
} }
/**
* 无论是否开启 [YukiHookAPI.Configs.isEnableModulePrefsCache]
*
* 调用此方法将清除当前存储的全部键值缓存
*
* 下次将从 [XSharedPreferences] 重新读取
*/
fun clearCache() {
xPrefCacheKeyValueStrings.clear()
xPrefCacheKeyValueBooleans.clear()
xPrefCacheKeyValueInts.clear()
xPrefCacheKeyValueLongs.clear()
xPrefCacheKeyValueFloats.clear()
}
} }

View File

@@ -31,6 +31,7 @@ package com.highcapable.yukihookapi.hook.xposed.proxy
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.factory.configs
import com.highcapable.yukihookapi.hook.factory.encase import com.highcapable.yukihookapi.hook.factory.encase
/** /**
@@ -38,14 +39,27 @@ import com.highcapable.yukihookapi.hook.factory.encase
* *
* - ❗请在此类上添加注释 [InjectYukiHookWithXposed] 标记模块 Hook 入口 * - ❗请在此类上添加注释 [InjectYukiHookWithXposed] 标记模块 Hook 入口
* *
* [YukiHookAPI] 初始化时将自动调用 [onInit] 方法
*
* Hook 开始时将自动调用 [onHook] 方法 * Hook 开始时将自动调用 [onHook] 方法
* *
* 请在 [onInit] 中调用 [YukiHookAPI.configs] 或直接调用 [configs]
*
* 请在 [onHook] 中调用 [YukiHookAPI.encase] 或直接调用 [encase] * 请在 [onHook] 中调用 [YukiHookAPI.encase] 或直接调用 [encase]
* *
* 详情请参考 [YukiHookXposedInitProxy 接口](https://github.com/fankes/YukiHookAPI/wiki/%E4%BD%9C%E4%B8%BA-Xposed-%E6%A8%A1%E5%9D%97%E4%BD%BF%E7%94%A8%E7%9A%84%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE#yukihookxposedinitproxy-%E6%8E%A5%E5%8F%A3) * 详情请参考 [YukiHookXposedInitProxy 接口](https://github.com/fankes/YukiHookAPI/wiki/%E4%BD%9C%E4%B8%BA-Xposed-%E6%A8%A1%E5%9D%97%E4%BD%BF%E7%94%A8%E7%9A%84%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE#yukihookxposedinitproxy-%E6%8E%A5%E5%8F%A3)
*/ */
interface YukiHookXposedInitProxy { interface YukiHookXposedInitProxy {
/**
* 配置 [YukiHookAPI.Configs] 的初始化方法
*
* - ❗在这里只能进行初始化配置 - 不能进行 Hook 操作
*
* 此方法可选 - 你也可以选择不对 [YukiHookAPI.Configs] 进行配置
*/
fun onInit() {}
/** /**
* 模块装载调用入口方法 * 模块装载调用入口方法
* *