diff --git a/docs-source/src/.vuepress/configs/template.ts b/docs-source/src/.vuepress/configs/template.ts index 62e50936..be37adfc 100644 --- a/docs-source/src/.vuepress/configs/template.ts +++ b/docs-source/src/.vuepress/configs/template.ts @@ -29,7 +29,7 @@ const navigationLinks = { baseApiPath + 'hook/param/HookParam', baseApiPath + 'annotation/xposed/InjectYukiHookWithXposed', baseApiPath + 'hook/xposed/proxy/IYukiHookXposedInit', - baseApiPath + 'hook/xposed/prefs/YukiHookModulePrefs', + baseApiPath + 'hook/xposed/prefs/YukiHookPrefsBridge', baseApiPath + 'hook/xposed/prefs/ui/ModulePreferenceFragment', baseApiPath + 'hook/xposed/prefs/data/PrefsData', baseApiPath + 'hook/xposed/channel/YukiHookDataChannel', diff --git a/docs-source/src/en/about/future.md b/docs-source/src/en/about/future.md index 4e415c52..68ffc2a1 100644 --- a/docs-source/src/en/about/future.md +++ b/docs-source/src/en/about/future.md @@ -6,7 +6,7 @@ > Here are the unresolved issues with `YukiHookAPI`. -### YukiHookModulePrefs +### YukiHookPrefsBridge Currently only supports LSPosed perfectly, other Xposed Framework need to downgrade the module target api. diff --git a/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md b/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md index ae46a1e9..7eb57611 100644 --- a/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md +++ b/docs-source/src/en/api/public/com/highcapable/yukihookapi/YukiHookAPI.md @@ -404,23 +404,33 @@ var isDebug: Boolean 请转移到 `YukiHookLogger.Configs.isEnable` -### isEnableModulePrefsCache - field - -```kotlin:no-line-numbers -var isEnableModulePrefsCache: Boolean -``` +

isEnableModulePrefsCache - field

**Change Records** `v1.0.5` `added` +`v1.1.9` `deprecated` + +请转移到 `isEnablePrefsBridgeCache` + +### isEnablePrefsBridgeCache - field + +```kotlin:no-line-numbers +var isEnablePrefsBridgeCache: Boolean +``` + +**Change Records** + +`v1.1.9` `added` + **Function Illustrate** -> 是否启用 `YukiHookModulePrefs` 的键值缓存功能。 +> 是否启用 `YukiHookPrefsBridge` 的键值缓存功能。 为防止内存复用过高问题,此功能默认启用。 -你可以手动在 `YukiHookModulePrefs` 中自由开启和关闭缓存功能以及清除缓存。 +你可以手动在 `YukiHookPrefsBridge` 中自由开启和关闭缓存功能以及清除缓存。 ### isEnableModuleAppResourcesCache - field @@ -488,7 +498,7 @@ var isEnableHookSharedPreferences: Boolean 这是一个可选的实验性功能,此功能默认不启用。 -仅用于修复某些系统可能会出现在启用了 **New XSharedPreferences** 后依然出现文件权限错误问题,若你能正常使用 **YukiHookModulePrefs** 就不建议启用此功能。 +仅用于修复某些系统可能会出现在启用了 **New XSharedPreferences** 后依然出现文件权限错误问题,若你能正常使用 **YukiHookPrefsBridge** 就不建议启用此功能。 ::: @@ -572,7 +582,7 @@ object HookEntry : IYukiHookXposedInit { elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) } isDebug = BuildConfig.DEBUG - isEnableModulePrefsCache = true + isEnablePrefsBridgeCache = true isEnableModuleAppResourcesCache = true isEnableHookModuleStatus = true isEnableHookSharedPreferences = false @@ -602,7 +612,7 @@ object HookEntry : IYukiHookXposedInit { elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) } isDebug = BuildConfig.DEBUG - isEnableModulePrefsCache = true + isEnablePrefsBridgeCache = true isEnableModuleAppResourcesCache = true isEnableHookModuleStatus = true isEnableHookSharedPreferences = false @@ -634,7 +644,7 @@ object HookEntry : IYukiHookXposedInit { YukiHookLogger.Configs.USER_ID ) YukiHookAPI.Configs.isDebug = BuildConfig.DEBUG - YukiHookAPI.Configs.isEnableModulePrefsCache = true + YukiHookAPI.Configs.isEnablePrefsBridgeCache = true YukiHookAPI.Configs.isEnableModuleAppResourcesCache = true YukiHookAPI.Configs.isEnableHookModuleStatus = true YukiHookAPI.Configs.isEnableHookSharedPreferences = false diff --git a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.md b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.md index 4b60f89f..029a9078 100644 --- a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.md +++ b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.md @@ -64,33 +64,45 @@ fun IYukiHookXposedInit.encase(vararg hooker: YukiBaseHooker) > 在 `IYukiHookXposedInit` 中调用 `YukiHookAPI`。 -## Context.modulePrefs - ext-field - -```kotlin:no-line-numbers -val Context.modulePrefs: YukiHookModulePrefs -``` +

Context.modulePrefs - ext-field

**Change Records** `v1.0` `first` -**Function Illustrate** +`v1.1.9` `deprecated` -> 获取模块的存取对象。 +请转移到 `prefs` 方法 -## Context.modulePrefs - ext-method - -```kotlin:no-line-numbers -fun Context.modulePrefs(name: String): YukiHookModulePrefs -``` +

Context.modulePrefs - ext-method

**Change Records** `v1.0` `first` +`v1.1.9` `deprecated` + +请转移到 `prefs` 方法 + +## Context.prefs - ext-method + +```kotlin:no-line-numbers +fun Context.prefs(name: String): YukiHookPrefsBridge +``` + +**Change Records** + +`v1.1.9` `added` + **Function Illustrate** -> 获取模块的存取对象,可设置 `name` 为自定义 Sp 存储名称。 +> 获取 `YukiHookPrefsBridge` 对象。 + +可以同时在模块与 (Xposed) 宿主环境中使用。 + +如果你想在 (Xposed) 宿主环境将数据存入当前宿主的私有空间,请使用 `YukiHookPrefsBridge.native` 方法。 + +在未声明任何条件的情况下 (Xposed) 宿主环境默认读取模块中的数据。 ## Context.dataChannel - ext-method diff --git a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.md b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.md index 32cc7c8a..7c845f89 100644 --- a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.md +++ b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.md @@ -243,7 +243,7 @@ val moduleAppResources: YukiModuleResources ## prefs - field ```kotlin:no-line-numbers -val prefs: YukiHookModulePrefs +val prefs: YukiHookPrefsBridge ``` **Change Records** @@ -263,7 +263,7 @@ val prefs: YukiHookModulePrefs ## prefs - method ```kotlin:no-line-numbers -fun prefs(name: String): YukiHookModulePrefs +fun prefs(name: String): YukiHookPrefsBridge ``` **Change Records** diff --git a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.md b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.md similarity index 89% rename from docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.md rename to docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.md index cb8493d8..00a82e39 100644 --- a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.md +++ b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.md @@ -10,25 +10,29 @@ You can use the **Chrome Translation Plugin** to translate entire pages for refe ::: -# YukiHookModulePrefs - class +# YukiHookPrefsBridge - class ```kotlin:no-line-numbers -class YukiHookModulePrefs private constructor(private var context: Context?) +class YukiHookPrefsBridge private constructor(private var context: Context?) ``` **Change Records** `v1.0` `first` +`v1.1.9` `modified` + +~~`YukiHookModulePrefs`~~ 更名为 `YukiHookPrefsBridge` + **Function Illustrate** -> 实现 Xposed 模块的数据存取,对接 `SharedPreferences` 和 `XSharedPreferences`。 +> `YukiHookAPI` 对 `SharedPreferences`、`XSharedPreferences` 的扩展存储桥实现。 在不同环境智能选择存取使用的对象。 ::: danger -此功能为实验性功能,仅在 LSPosed 环境测试通过,EdXposed 理论也可以使用但不再推荐。 +模块与宿主之前共享数据存储为实验性功能,仅在 LSPosed 环境测试通过,EdXposed 理论也可以使用但不再推荐。 ::: @@ -42,13 +46,7 @@ class YukiHookModulePrefs private constructor(private var context: Context?) 太极请参阅 [文件权限/配置/XSharedPreference](https://taichi.cool/zh/doc/for-xposed-dev.html#文件权限-配置-xsharedpreference)。 -::: danger - -当你在 Xposed 模块中存取数据的时候 **context** 必须不能是空的。 - -::: - -若你正在使用 `PreferenceFragmentCompat`,请迁移到 `ModulePreferenceFragment` 以适配上述功能特性。 +对于在模块环境中使用 `PreferenceFragmentCompat`,`YukiHookAPI` 提供了 `ModulePreferenceFragment` 来实现同样的功能。 **Optional Configuration** @@ -96,7 +94,7 @@ val isPreferencesAvailable: Boolean **Function Illustrate** -> 获取当前 `YukiHookModulePrefs` 的可用状态。 +> 获取当前 `YukiHookPrefsBridge` 的可用状态。 在 (Xposed) 宿主环境中返回 `XSharedPreferences` 可用状态 (可读)。 @@ -105,7 +103,7 @@ val isPreferencesAvailable: Boolean ## name - method ```kotlin:no-line-numbers -fun name(name: String): YukiHookModulePrefs +fun name(name: String): YukiHookPrefsBridge ``` **Change Records** @@ -123,7 +121,7 @@ fun name(name: String): YukiHookModulePrefs > The following example ```kotlin -modulePrefs("custom_name").getString("custom_key") +prefs("custom_name").getString("custom_key") ``` 在 (Xposed) 宿主环境 `PackageParam` 中的使用方法。 @@ -137,7 +135,7 @@ prefs("custom_name").getString("custom_key") ## direct - method ```kotlin:no-line-numbers -fun direct(): YukiHookModulePrefs +fun direct(): YukiHookPrefsBridge ``` **Change Records** @@ -148,10 +146,24 @@ fun direct(): YukiHookModulePrefs > 忽略缓存直接读取键值。 -无论是否开启 `YukiHookAPI.Configs.isEnableModulePrefsCache`。 +无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`。 仅在 `XSharedPreferences` 下生效。 +## native - method + +```kotlin:no-line-numbers +fun native(): YukiHookPrefsBridge +``` + +**Change Records** + +`v1.1.9` `added` + +**Function Illustrate** + +> 忽略当前环境直接使用 `Context.getSharedPreferences` 存取数据。 + ## getString - method ```kotlin:no-line-numbers @@ -434,7 +446,7 @@ fun clearCache() > 清除 `XSharedPreferences` 中缓存的键值数据。 -无论是否开启 `YukiHookAPI.Configs.isEnableModulePrefsCache`。 +无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`。 调用此方法将清除当前存储的全部键值缓存。 @@ -454,7 +466,7 @@ inner class Editor internal constructor() **Function Illustrate** -> `YukiHookModulePrefs` 的存储代理类。 +> `YukiHookPrefsBridge` 的存储代理类。 请使用 `edit` 方法来获取 `Editor`。 diff --git a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.md b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.md index e1c6e6b2..ec97c7f5 100644 --- a/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.md +++ b/docs-source/src/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.md @@ -28,7 +28,7 @@ data class PrefsData(var key: String, var value: T) : Serializable > 键值对存储构造类。 -这个类是对 `YukiHookModulePrefs` 的一个扩展用法。 +这个类是对 `YukiHookPrefsBridge` 的一个扩展用法。 **Function Example** @@ -51,9 +51,9 @@ object DataConst { ```kotlin // 读取 -val data = modulePrefs.get(DataConst.TEST_KV_DATA_1) +val data = prefs().get(DataConst.TEST_KV_DATA_1) // 写入 -modulePrefs.put(DataConst.TEST_KV_DATA_1, "written value") +prefs().edit { put(DataConst.TEST_KV_DATA_1, "written value") } ``` > 宿主示例如下 diff --git a/docs-source/src/en/api/special-features/xposed-storage.md b/docs-source/src/en/api/special-features/xposed-storage.md index ae8ebd06..e4368a77 100644 --- a/docs-source/src/en/api/special-features/xposed-storage.md +++ b/docs-source/src/en/api/special-features/xposed-storage.md @@ -10,7 +10,7 @@ The native `Xposed` provides us with a `XSharedPreferences` for reading the `Sp` ## Use in Activity -> Loading `YukiHookModulePrefs` in `Activity` is described here. +> Loading `YukiHookPrefsBridge` in `Activity` is described here. Usually we can initialize it in Host App like this. @@ -29,7 +29,7 @@ When you store data in a Module App, you can use the following methods if you ar > The following example ```kotlin -modulePrefs.putString("test_name", "saved_value") +prefs().edit { putString("test_name", "saved_value") } ``` When you read data in a Host App, you can use the following methods. @@ -40,7 +40,7 @@ When you read data in a Host App, you can use the following methods. val testName = prefs.getString("test_name", "default_value") ``` -You don't need to consider the module package name and a series of complicated permission configurations, everything is handled by `YukiHookModulePrefs`. +You don't need to consider the module package name and a series of complicated permission configurations, everything is handled by `YukiHookPrefsBridge`. To achieve localization of storage, you can specify the name of each `prefs` file. @@ -50,9 +50,9 @@ This is used in the `Activity` of the Module App. ```kotlin // Recommended usage -modulePrefs("specify_file_name").putString("test_name", "saved_value") +prefs("specify_file_name").edit { putString("test_name", "saved_value") } // Can also be used like this -modulePrefs.name("specify_file_name").putString("test_name", "saved_value") +prefs().name("specify_file_name").edit { putString("test_name", "saved_value") } ``` Read like this in Host App. @@ -68,21 +68,40 @@ val testName = prefs.name("specify_file_name").getString("test_name", "default_v If your project has a lot of fixed data that needs to be stored and read, it is recommended to use `PrefsData` to create templates. +Through the above example, you can call the `edit` method to store data in batches in the following two ways. + +> The following example + +```kotlin +// +prefs().edit { + putString("test_name_1", "saved_value_1") + putString("test_name_2", "saved_value_2") + putString("test_name_3", "saved_value_3") +} +// +prefs(). edit() + .putString("test_name_1", "saved_value_1") + .putString("test_name_2", "saved_value_2") + .putString("test_name_3", "saved_value_3") + .apply() +``` + ::: tip -For more functions, please refer to [YukiHookModulePrefs](../public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs), [PrefsData](../public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData). +For more functions, please refer to [YukiHookPrefsBridge](../public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge), [PrefsData](../public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData). ::: ## Use in PreferenceFragment -> Loading `YukiHookModulePrefs` in `PreferenceFragment` is described here. +> Loading `YukiHookPrefsBridge` in `PreferenceFragment` is described here. If your Module App uses `PreferenceFragmentCompat`, you can now start migrating its extends `ModulePreferenceFragment`. ::: danger -You must extends **ModulePreferenceFragment** to implement the module storage function of **YukiHookModulePrefs**. +You must extends **ModulePreferenceFragment** to implement the module storage function of **YukiHookPrefsBridge**. ::: @@ -90,4 +109,50 @@ You must extends **ModulePreferenceFragment** to implement the module storage fu For more functions, please refer to [ModulePreferenceFragment](../public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment). +::: + +## Use Native Storage + +In the Module environment, `YukiHookPrefsBridge` will store data in the Module App's own private directory (or the shared directory provided by Hook Framework) by default. + +Using `YukiHookPrefsBridge` in the Host environment will read the data in the Module App's own private directory (or the shared directory provided by Hook Framework) by default. + +If you want to store data directly into a Module App or Host App's own private directory, you can use the `native` method. + +For example, the directory of the Module App is `.../com.demo.test.module/shared_prefs`, and the directory of the Host App is `.../com.demo.test.host/shared_prefs`. + +The following is the usage in `Activity`. + +> The following example + +```kotlin +// Store private data +prefs().native().edit { putBoolean("isolation_data", true) } +// Read private data +val privateData = prefs().native().getBoolean("isolation_data") +// Store shared data +prefs().edit { putBoolean("public_data", true) } +// Read shared data +val publicData = prefs().getBoolean("public_data") +``` + +The following is the usage in `PackageParam`. + +> The following example + +```kotlin +// Store private data +prefs.native().edit { putBoolean("isolation_data", true) } +// Read private data +val privateData = prefs.native().getBoolean("isolation_data") +// Read shared data +val publicData = prefs.getBoolean("public_data") +``` + +After using the `native` method, no matter in `Activity` or `PackageParam`, the data **will be stored and read in the private directory of the corresponding environment**, and the data will be isolated from each other. + +::: tip + +For more functions, please refer to [YukiHookPrefsBridge](../public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge). + ::: \ No newline at end of file diff --git a/docs-source/src/en/guide/quick-start.md b/docs-source/src/en/guide/quick-start.md index 32124161..f7f8cf37 100644 --- a/docs-source/src/en/guide/quick-start.md +++ b/docs-source/src/en/guide/quick-start.md @@ -218,6 +218,6 @@ For configuration details related to use as a Hook API, you can [click here](../ ::: warning -**YukiHookModulePrefs**, **YukiHookDataChannel** and Resources Hook functionality will not work when using a custom Hook Framework instead of the full Xposed Module. +**YukiHookPrefsBridge**, **YukiHookDataChannel** and Resources Hook functionality will not work when using a custom Hook Framework instead of the full Xposed Module. ::: \ No newline at end of file diff --git a/docs-source/src/zh-cn/about/future.md b/docs-source/src/zh-cn/about/future.md index 8485861f..d72956e2 100644 --- a/docs-source/src/zh-cn/about/future.md +++ b/docs-source/src/zh-cn/about/future.md @@ -6,7 +6,7 @@ > 这里收录了 `YukiHookAPI` 尚未解决的问题。 -### YukiHookModulePrefs +### YukiHookPrefsBridge 目前仅限完美支持 LSPosed,其它 Xposed 框架需要降级模块 API。 diff --git a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md index 2fcf6e82..d9eadabc 100644 --- a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md +++ b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/YukiHookAPI.md @@ -396,23 +396,33 @@ var isDebug: Boolean 请转移到 `YukiHookLogger.Configs.isEnable` -### isEnableModulePrefsCache - field - -```kotlin:no-line-numbers -var isEnableModulePrefsCache: Boolean -``` +

isEnableModulePrefsCache - field

**变更记录** `v1.0.5` `新增` +`v1.1.9` `作废` + +请转移到 `isEnablePrefsBridgeCache` + +### isEnablePrefsBridgeCache - field + +```kotlin:no-line-numbers +var isEnablePrefsBridgeCache: Boolean +``` + +**变更记录** + +`v1.1.9` `新增` + **功能描述** -> 是否启用 `YukiHookModulePrefs` 的键值缓存功能。 +> 是否启用 `YukiHookPrefsBridge` 的键值缓存功能。 为防止内存复用过高问题,此功能默认启用。 -你可以手动在 `YukiHookModulePrefs` 中自由开启和关闭缓存功能以及清除缓存。 +你可以手动在 `YukiHookPrefsBridge` 中自由开启和关闭缓存功能以及清除缓存。 ### isEnableModuleAppResourcesCache - field @@ -480,7 +490,7 @@ var isEnableHookSharedPreferences: Boolean 这是一个可选的实验性功能,此功能默认不启用。 -仅用于修复某些系统可能会出现在启用了 **New XSharedPreferences** 后依然出现文件权限错误问题,若你能正常使用 **YukiHookModulePrefs** 就不建议启用此功能。 +仅用于修复某些系统可能会出现在启用了 **New XSharedPreferences** 后依然出现文件权限错误问题,若你能正常使用 **YYukiHookPrefsBridge** 就不建议启用此功能。 ::: @@ -564,7 +574,7 @@ object HookEntry : IYukiHookXposedInit { elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) } isDebug = BuildConfig.DEBUG - isEnableModulePrefsCache = true + isEnablePrefsBridgeCache = true isEnableModuleAppResourcesCache = true isEnableHookModuleStatus = true isEnableHookSharedPreferences = false @@ -594,7 +604,7 @@ object HookEntry : IYukiHookXposedInit { elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) } isDebug = BuildConfig.DEBUG - isEnableModulePrefsCache = true + isEnablePrefsBridgeCache = true isEnableModuleAppResourcesCache = true isEnableHookModuleStatus = true isEnableHookSharedPreferences = false @@ -626,7 +636,7 @@ object HookEntry : IYukiHookXposedInit { YukiHookLogger.Configs.USER_ID ) YukiHookAPI.Configs.isDebug = BuildConfig.DEBUG - YukiHookAPI.Configs.isEnableModulePrefsCache = true + YukiHookAPI.Configs.isEnablePrefsBridgeCache = true YukiHookAPI.Configs.isEnableModuleAppResourcesCache = true YukiHookAPI.Configs.isEnableHookModuleStatus = true YukiHookAPI.Configs.isEnableHookSharedPreferences = false diff --git a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.md b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.md index b300760f..04b27bbd 100644 --- a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.md +++ b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.md @@ -56,33 +56,45 @@ fun IYukiHookXposedInit.encase(vararg hooker: YukiBaseHooker) > 在 `IYukiHookXposedInit` 中调用 `YukiHookAPI`。 -## Context.modulePrefs - ext-field - -```kotlin:no-line-numbers -val Context.modulePrefs: YukiHookModulePrefs -``` +

Context.modulePrefs - ext-field

**变更记录** `v1.0` `添加` -**功能描述** +`v1.1.9` `作废` -> 获取模块的存取对象。 +请转移到 `prefs` 方法 -## Context.modulePrefs - ext-method - -```kotlin:no-line-numbers -fun Context.modulePrefs(name: String): YukiHookModulePrefs -``` +

Context.modulePrefs - ext-method

**变更记录** `v1.0` `添加` +`v1.1.9` `作废` + +请转移到 `prefs` 方法 + +## Context.prefs - ext-method + +```kotlin:no-line-numbers +fun Context.prefs(name: String): YukiHookPrefsBridge +``` + +**变更记录** + +`v1.1.9` `新增` + **功能描述** -> 获取模块的存取对象,可设置 `name` 为自定义 Sp 存储名称。 +> 获取 `YukiHookPrefsBridge` 对象。 + +可以同时在模块与 (Xposed) 宿主环境中使用。 + +如果你想在 (Xposed) 宿主环境将数据存入当前宿主的私有空间,请使用 `YukiHookPrefsBridge.native` 方法。 + +在未声明任何条件的情况下 (Xposed) 宿主环境默认读取模块中的数据。 ## Context.dataChannel - ext-method diff --git a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.md b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.md index 05cb3ae1..a54c8b9f 100644 --- a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.md +++ b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/param/PackageParam.md @@ -235,7 +235,7 @@ val moduleAppResources: YukiModuleResources ## prefs - field ```kotlin:no-line-numbers -val prefs: YukiHookModulePrefs +val prefs: YukiHookPrefsBridge ``` **变更记录** @@ -255,7 +255,7 @@ val prefs: YukiHookModulePrefs ## prefs - method ```kotlin:no-line-numbers -fun prefs(name: String): YukiHookModulePrefs +fun prefs(name: String): YukiHookPrefsBridge ``` **变更记录** diff --git a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.md b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.md similarity index 88% rename from docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.md rename to docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.md index 95f44209..511a8782 100644 --- a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.md +++ b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.md @@ -2,25 +2,29 @@ pageClass: code-page --- -# YukiHookModulePrefs - class +# YukiHookPrefsBridge - class ```kotlin:no-line-numbers -class YukiHookModulePrefs private constructor(private var context: Context?) +class YukiHookPrefsBridge private constructor(private var context: Context?) ``` **变更记录** `v1.0` `添加` +`v1.1.9` `修改` + +~~`YukiHookModulePrefs`~~ 更名为 `YukiHookPrefsBridge` + **功能描述** -> 实现 Xposed 模块的数据存取,对接 `SharedPreferences` 和 `XSharedPreferences`。 +> `YukiHookAPI` 对 `SharedPreferences`、`XSharedPreferences` 的扩展存储桥实现。 在不同环境智能选择存取使用的对象。 ::: danger -此功能为实验性功能,仅在 LSPosed 环境测试通过,EdXposed 理论也可以使用但不再推荐。 +模块与宿主之前共享数据存储为实验性功能,仅在 LSPosed 环境测试通过,EdXposed 理论也可以使用但不再推荐。 ::: @@ -34,13 +38,7 @@ class YukiHookModulePrefs private constructor(private var context: Context?) 太极请参阅 [文件权限/配置/XSharedPreference](https://taichi.cool/zh/doc/for-xposed-dev.html#文件权限-配置-xsharedpreference)。 -::: danger - -当你在 Xposed 模块中存取数据的时候 **context** 必须不能是空的。 - -::: - -若你正在使用 `PreferenceFragmentCompat`,请迁移到 `ModulePreferenceFragment` 以适配上述功能特性。 +对于在模块环境中使用 `PreferenceFragmentCompat`,`YukiHookAPI` 提供了 `ModulePreferenceFragment` 来实现同样的功能。 **可选配置** @@ -88,7 +86,7 @@ val isPreferencesAvailable: Boolean **功能描述** -> 获取当前 `YukiHookModulePrefs` 的可用状态。 +> 获取当前 `YukiHookPrefsBridge` 的可用状态。 在 (Xposed) 宿主环境中返回 `XSharedPreferences` 可用状态 (可读)。 @@ -97,7 +95,7 @@ val isPreferencesAvailable: Boolean ## name - method ```kotlin:no-line-numbers -fun name(name: String): YukiHookModulePrefs +fun name(name: String): YukiHookPrefsBridge ``` **变更记录** @@ -115,7 +113,7 @@ fun name(name: String): YukiHookModulePrefs > 示例如下 ```kotlin -modulePrefs("custom_name").getString("custom_key") +prefs("custom_name").getString("custom_key") ``` 在 (Xposed) 宿主环境 `PackageParam` 中的使用方法。 @@ -129,7 +127,7 @@ prefs("custom_name").getString("custom_key") ## direct - method ```kotlin:no-line-numbers -fun direct(): YukiHookModulePrefs +fun direct(): YukiHookPrefsBridge ``` **变更记录** @@ -140,10 +138,24 @@ fun direct(): YukiHookModulePrefs > 忽略缓存直接读取键值。 -无论是否开启 `YukiHookAPI.Configs.isEnableModulePrefsCache`。 +无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`。 仅在 `XSharedPreferences` 下生效。 +## native - method + +```kotlin:no-line-numbers +fun native(): YukiHookPrefsBridge +``` + +**变更记录** + +`v1.1.9` `新增` + +**功能描述** + +> 忽略当前环境直接使用 `Context.getSharedPreferences` 存取数据。 + ## getString - method ```kotlin:no-line-numbers @@ -426,7 +438,7 @@ fun clearCache() > 清除 `XSharedPreferences` 中缓存的键值数据。 -无论是否开启 `YukiHookAPI.Configs.isEnableModulePrefsCache`。 +无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`。 调用此方法将清除当前存储的全部键值缓存。 @@ -446,7 +458,7 @@ inner class Editor internal constructor() **功能描述** -> `YukiHookModulePrefs` 的存储代理类。 +> `YukiHookPrefsBridge` 的存储代理类。 请使用 `edit` 方法来获取 `Editor`。 diff --git a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.md b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.md index b8c9e088..8cd2dd56 100644 --- a/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.md +++ b/docs-source/src/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.md @@ -20,7 +20,7 @@ data class PrefsData(var key: String, var value: T) : Serializable > 键值对存储构造类。 -这个类是对 `YukiHookModulePrefs` 的一个扩展用法。 +这个类是对 `YukiHookPrefsBridge` 的一个扩展用法。 **功能示例** @@ -43,9 +43,9 @@ object DataConst { ```kotlin // 读取 -val data = modulePrefs.get(DataConst.TEST_KV_DATA_1) +val data = prefs().get(DataConst.TEST_KV_DATA_1) // 写入 -modulePrefs.put(DataConst.TEST_KV_DATA_1, "written value") +prefs().edit { put(DataConst.TEST_KV_DATA_1, "written value") } ``` > 宿主示例如下 diff --git a/docs-source/src/zh-cn/api/special-features/xposed-storage.md b/docs-source/src/zh-cn/api/special-features/xposed-storage.md index c388c794..e6906661 100644 --- a/docs-source/src/zh-cn/api/special-features/xposed-storage.md +++ b/docs-source/src/zh-cn/api/special-features/xposed-storage.md @@ -8,7 +8,7 @@ ## 在 Activity 中使用 -> 这里描述了在 `Activity` 中装载 `YukiHookModulePrefs` 的场景。 +> 这里描述了在 `Activity` 中装载 `YukiHookPrefsBridge` 的场景。 通常情况下我们可以这样在 Hook APP (宿主) 内对其进行初始化。 @@ -25,7 +25,7 @@ XSharedPreferences(BuildConfig.APPLICATION_ID) > 示例如下 ```kotlin -modulePrefs.putString("test_name", "saved_value") +prefs().edit { putString("test_name", "saved_value") } ``` 当你在 Hook APP (宿主) 中读取数据时,可以使用如下方法。 @@ -36,7 +36,7 @@ modulePrefs.putString("test_name", "saved_value") val testName = prefs.getString("test_name", "default_value") ``` -你不需要考虑传入模块的包名以及一系列复杂的权限配置,一切都交给 `YukiHookModulePrefs` 来处理。 +你不需要考虑传入模块的包名以及一系列复杂的权限配置,一切都交给 `YukiHookPrefsBridge` 来处理。 若要实现存储的区域划分,你可以指定每个 `prefs` 文件的名称。 @@ -46,9 +46,9 @@ val testName = prefs.getString("test_name", "default_value") ```kotlin // 推荐用法 -modulePrefs("specify_file_name").putString("test_name", "saved_value") +prefs("specify_file_name").edit { putString("test_name", "saved_value") } // 也可以这样用 -modulePrefs.name("specify_file_name").putString("test_name", "saved_value") +prefs().name("specify_file_name").edit { putString("test_name", "saved_value") } ``` 在 Hook APP (宿主) 中这样读取。 @@ -64,21 +64,40 @@ val testName = prefs.name("specify_file_name").getString("test_name", "default_v 若你的项目中有大量的固定数据需要存储和读取,推荐使用 `PrefsData` 来创建模板。 +通过上面的示例,你可以调用 `edit` 方法使用以下两种方式来批量存储数据。 + +> 示例如下 + +```kotlin +// <方案 1> +prefs().edit { + putString("test_name_1", "saved_value_1") + putString("test_name_2", "saved_value_2") + putString("test_name_3", "saved_value_3") +} +// <方案 2> +prefs().edit() + .putString("test_name_1", "saved_value_1") + .putString("test_name_2", "saved_value_2") + .putString("test_name_3", "saved_value_3") + .apply() +``` + ::: tip -更多功能请参考 [YukiHookModulePrefs](../public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs)、[PrefsData](../public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData)。 +更多功能请参考 [YukiHookPrefsBridge](../public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge)、[PrefsData](../public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData)。 ::: ## 在 PreferenceFragment 中使用 -> 这里描述了在 `PreferenceFragment` 中装载 `YukiHookModulePrefs` 的场景。 +> 这里描述了在 `PreferenceFragment` 中装载 `YukiHookPrefsBridge` 的场景。 若你的模块使用了 `PreferenceFragmentCompat`,你现在可以将其继承类开始迁移到 `ModulePreferenceFragment`。 ::: danger -你必须继承 **ModulePreferenceFragment** 才能实现 **YukiHookModulePrefs** 的模块存储功能。 +你必须继承 **ModulePreferenceFragment** 才能实现 **YukiHookPrefsBridge** 的模块存储功能。 ::: @@ -86,4 +105,50 @@ val testName = prefs.name("specify_file_name").getString("test_name", "default_v 更多功能请参考 [ModulePreferenceFragment](../public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment)。 +::: + +## 使用原生方式存储 + +在模块环境中 `YukiHookPrefsBridge` 默认会将数据存储到模块自己的私有目录 (或 Hook Framework 提供的共享目录) 中。 + +在宿主环境中使用 `YukiHookPrefsBridge` 默认会读取模块自己的私有目录 (或 Hook Framework 提供的共享目录) 中的数据。 + +如果你想直接将数据存储到模块或宿主当前环境自身的私有目录,你可以使用 `native` 方法。 + +例如模块的目录是 `.../com.demo.test.module/shared_prefs`,宿主的目录是 `.../com.demo.test.host/shared_prefs`。 + +以下是在 `Activity` 中的用法。 + +> 示例如下 + +```kotlin +// 存储私有数据 +prefs().native().edit { putBoolean("isolation_data", true) } +// 读取私有数据 +val privateData = prefs().native().getBoolean("isolation_data") +// 存储共享数据 +prefs().edit { putBoolean("public_data", true) } +// 读取共享数据 +val publicData = prefs().getBoolean("public_data") +``` + +以下是在 `PackageParam` 中的用法。 + +> 示例如下 + +```kotlin +// 存储私有数据 +prefs.native().edit { putBoolean("isolation_data", true) } +// 读取私有数据 +val privateData = prefs.native().getBoolean("isolation_data") +// 读取共享数据 +val publicData = prefs.getBoolean("public_data") +``` + +使用 `native` 方法后,无论在 `Activity` 还是 `PackageParam` 中都会将数据**在对应环境的私有目录中**存储、读取,数据相互隔离。 + +::: tip + +更多功能请参考 [YukiHookPrefsBridge](../public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge)。 + ::: \ No newline at end of file diff --git a/docs-source/src/zh-cn/guide/quick-start.md b/docs-source/src/zh-cn/guide/quick-start.md index cff2d83b..4a8636b6 100644 --- a/docs-source/src/zh-cn/guide/quick-start.md +++ b/docs-source/src/zh-cn/guide/quick-start.md @@ -215,6 +215,6 @@ override fun attachBaseContext(base: Context?) { ::: warning -使用自定义的 Hook Framework 而并非完整的 Xposed 模块时,**YukiHookModulePrefs**、**YukiHookDataChannel** 以及 Resources Hook 功能将失效。 +使用自定义的 Hook Framework 而并非完整的 Xposed 模块时,**YukiHookPrefsBridge**、**YukiHookDataChannel** 以及 Resources Hook 功能将失效。 ::: \ No newline at end of file diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/YukiHookAPI.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/YukiHookAPI.kt index 7d8c4ca3..f8178304 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/YukiHookAPI.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/YukiHookAPI.kt @@ -57,7 +57,7 @@ import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule import com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiXposedModuleStatus import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel -import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs +import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookPrefsBridge import java.lang.reflect.Constructor import java.lang.reflect.Field import java.lang.reflect.Member @@ -281,13 +281,27 @@ object YukiHookAPI { } /** - * 是否启用 [YukiHookModulePrefs] 的键值缓存功能 + * 是否启用 [YukiHookPrefsBridge] 的键值缓存功能 + * + * - ❗此方法已弃用 - 在之后的版本中将直接被删除 + * + * - ❗请现在转移到 [isEnablePrefsBridgeCache] + */ + @Deprecated(message = "请使用新的命名方法来实现此功能", ReplaceWith("isEnablePrefsBridgeCache")) + var isEnableModulePrefsCache + get() = isEnablePrefsBridgeCache + set(value) { + isEnablePrefsBridgeCache = value + } + + /** + * 是否启用 [YukiHookPrefsBridge] 的键值缓存功能 * * - 为防止内存复用过高问题 - 此功能默认启用 * - * 你可以手动在 [YukiHookModulePrefs] 中自由开启和关闭缓存功能以及清除缓存 + * 你可以手动在 [YukiHookPrefsBridge] 中自由开启和关闭缓存功能以及清除缓存 */ - var isEnableModulePrefsCache = true + var isEnablePrefsBridgeCache = true /** * 是否启用当前 Xposed 模块自身 [Resources] 缓存功能 @@ -316,7 +330,7 @@ object YukiHookAPI { * * - ❗这是一个可选的实验性功能 - 此功能默认不启用 * - * - 仅用于修复某些系统可能会出现在启用了 New XSharedPreferences 后依然出现文件权限错误问题 - 若你能正常使用 [YukiHookModulePrefs] 就不建议启用此功能 + * - 仅用于修复某些系统可能会出现在启用了 New XSharedPreferences 后依然出现文件权限错误问题 - 若你能正常使用 [YukiHookPrefsBridge] 就不建议启用此功能 */ var isEnableHookSharedPreferences = false diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.kt index fefa2dc3..daa3f339 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/factory/YukiHookFactory.kt @@ -49,7 +49,7 @@ import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.base.ModuleAppActivity import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.base.ModuleAppCompatActivity import com.highcapable.yukihookapi.hook.xposed.parasitic.context.wrapper.ModuleContextThemeWrapper -import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs +import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookPrefsBridge import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit import java.io.BufferedReader import java.io.File @@ -76,16 +76,38 @@ fun IYukiHookXposedInit.encase(vararg hooker: YukiBaseHooker) = YukiHookAPI.enca /** * 获取模块的存取对象 - * @return [YukiHookModulePrefs] + * + * - ❗此方法已弃用 - 在之后的版本中将直接被删除 + * + * - ❗请现在转移到 [Context.prefs] 方法 + * @return [YukiHookPrefsBridge] */ -val Context.modulePrefs get() = YukiHookModulePrefs.instance(context = this) +@Deprecated(message = "请使用新的命名方法", ReplaceWith("prefs()")) +val Context.modulePrefs get() = prefs() /** * 获取模块的存取对象 - * @param name 自定义 Sp 存储名称 - * @return [YukiHookModulePrefs] + * + * - ❗此方法已弃用 - 在之后的版本中将直接被删除 + * + * - ❗请现在转移到 [Context.prefs] 方法 + * @return [YukiHookPrefsBridge] */ -fun Context.modulePrefs(name: String) = modulePrefs.name(name) +@Deprecated(message = "请使用新的命名方法", ReplaceWith("prefs(name)")) +fun Context.modulePrefs(name: String) = prefs(name) + +/** + * 获取 [YukiHookPrefsBridge] 对象 + * + * 可以同时在模块与 (Xposed) 宿主环境中使用 + * + * 如果你想在 (Xposed) 宿主环境将数据存入当前宿主的私有空间 - 请使用 [YukiHookPrefsBridge.native] 方法 + * + * 在未声明任何条件的情况下 (Xposed) 宿主环境默认读取模块中的数据 + * @param name 自定义 Sp 存储名称 - 默认空 + * @return [YukiHookPrefsBridge] + */ +fun Context.prefs(name: String = "") = YukiHookPrefsBridge.instance(context = this).let { if (name.isNotBlank()) it.name(name) else it } /** * 获取模块的数据通讯桥命名空间对象 diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/param/PackageParam.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/param/PackageParam.kt index f851e122..1468f836 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/param/PackageParam.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/param/PackageParam.kt @@ -56,7 +56,7 @@ import com.highcapable.yukihookapi.hook.xposed.bridge.resources.YukiResources import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics -import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs +import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookPrefsBridge /** * 装载 Hook 的目标 APP 入口对象实现类 @@ -181,16 +181,16 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper: * 获得当前使用的存取数据对象缓存实例 * * - ❗作为 Hook API 装载时无法使用 - 会抛出异常 - * @return [YukiHookModulePrefs] + * @return [YukiHookPrefsBridge] */ - val prefs get() = YukiHookModulePrefs.instance() + val prefs get() = YukiHookPrefsBridge.instance() /** * 获得当前使用的存取数据对象缓存实例 * * - ❗作为 Hook API 装载时无法使用 - 会抛出异常 * @param name 自定义 Sp 存储名称 - * @return [YukiHookModulePrefs] + * @return [YukiHookPrefsBridge] */ fun prefs(name: String) = prefs.name(name) diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.kt similarity index 83% rename from yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.kt rename to yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.kt index 54f0e38b..0782503f 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge.kt @@ -37,42 +37,35 @@ import com.highcapable.yukihookapi.hook.log.yLoggerE import com.highcapable.yukihookapi.hook.log.yLoggerW import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule import com.highcapable.yukihookapi.hook.xposed.bridge.delegate.XSharedPreferencesDelegate +import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData import com.highcapable.yukihookapi.hook.xposed.prefs.ui.ModulePreferenceFragment import de.robv.android.xposed.XSharedPreferences import java.io.File /** - * 实现 Xposed 模块的数据存取 - * - * 对接 [SharedPreferences] 和 [XSharedPreferences] + * [YukiHookAPI] 对 [SharedPreferences]、[XSharedPreferences] 的扩展存储桥实现 * * 在不同环境智能选择存取使用的对象 * - * - ❗请注意此功能为实验性功能 - 仅在 LSPosed 环境测试通过 - EdXposed 理论也可以使用但不再推荐 + * - ❗模块与宿主之前共享数据存储为实验性功能 - 仅在 LSPosed 环境测试通过 - EdXposed 理论也可以使用但不再推荐 * - * - 使用 LSPosed 环境请在 AndroidManifests.xml 中将 "xposedminversion" 最低设置为 93 + * 对于在模块环境中使用 [PreferenceFragmentCompat] - [YukiHookAPI] 提供了 [ModulePreferenceFragment] 来实现同样的功能 * - * - 未使用 LSPosed 环境请将你的模块 API 降至 26 以下 - [YukiHookAPI] 将会尝试使用 [makeWorldReadable] 但仍有可能不成功 + * 详情请参考 [API 文档 - YukiHookPrefsBridge](https://fankes.github.io/YukiHookAPI/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge) * - * - ❗当你在模块中存取数据的时候 [context] 必须不能是空的 - * - * - 若你正在使用 [PreferenceFragmentCompat] - 请迁移到 [ModulePreferenceFragment] 以适配上述功能特性 - * - * 详情请参考 [API 文档 - YukiHookModulePrefs](https://fankes.github.io/YukiHookAPI/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs) - * - * For English version, see [API Document - YukiHookModulePrefs](https://fankes.github.io/YukiHookAPI/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookModulePrefs) + * For English version, see [API Document - YukiHookPrefsBridge](https://fankes.github.io/YukiHookAPI/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge) * @param context 上下文实例 - 默认空 */ -class YukiHookModulePrefs private constructor(private var context: Context? = null) { +class YukiHookPrefsBridge private constructor(private var context: Context? = null) { internal companion object { /** 当前是否为 (Xposed) 宿主环境 */ private val isXposedEnvironment = YukiXposedModule.isXposedEnvironment - /** 当前 [YukiHookModulePrefs] 单例 */ - private var instance: YukiHookModulePrefs? = null + /** 当前 [YukiHookPrefsBridge] 单例 */ + private var instance: YukiHookPrefsBridge? = null /** 当前缓存的 [XSharedPreferencesDelegate] 实例数组 */ private val xPrefs = HashMap() @@ -81,12 +74,12 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu private val sPrefs = HashMap() /** - * 获取 [YukiHookModulePrefs] 单例 + * 获取 [YukiHookPrefsBridge] 单例 * @param context 实例 - (Xposed) 宿主环境为空 - * @return [YukiHookModulePrefs] + * @return [YukiHookPrefsBridge] */ internal fun instance(context: Context? = null) = - instance?.apply { if (context != null) this.context = context } ?: YukiHookModulePrefs(context).apply { instance = this } + instance?.apply { if (context != null) this.context = context } ?: YukiHookPrefsBridge(context).apply { instance = this } /** * 设置全局可读可写 @@ -105,15 +98,28 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu } } - /** 存储名称 - 默认包名 + _preferences */ - private var prefsName = "${YukiXposedModule.modulePackageName.ifBlank { context?.packageName ?: "" }}_preferences" + /** 存储名称 */ + private var prefsName = "" + + /** + * 获取当前存储名称 - 默认包名 + _preferences + * @return [String] + */ + private val currentPrefsName + get() = prefsName.ifBlank { + if (isUsingNativeStorage) "${context?.packageName ?: "unknown"}_preferences" + else "${YukiXposedModule.modulePackageName.ifBlank { context?.packageName ?: "unknown" }}_preferences" + } /** 是否使用键值缓存 */ - private var isUsingKeyValueCache = YukiHookAPI.Configs.isEnableModulePrefsCache + private var isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache - /** 是否使用新版存储方式 EdXposed/LSPosed */ + /** 是否使用新版存储方式 EdXposed、LSPosed */ private var isUsingNewXSharedPreferences = false + /** 是否启用原生存储方式 */ + private var isUsingNativeStorage = false + /** * [XSharedPreferences] 缓存的键值数据 */ @@ -150,7 +156,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu /** 检查 API 装载状态 */ private fun checkApi() { - if (YukiHookAPI.isLoadedFromBaseContext) error("YukiHookModulePrefs not allowed in Custom Hook API") + if (YukiHookAPI.isLoadedFromBaseContext) error("YukiHookPrefsBridge not allowed in Custom Hook API") if (isXposedEnvironment && YukiXposedModule.modulePackageName.isBlank()) error("Xposed modulePackageName load failed, please reset and rebuild it") } @@ -162,9 +168,10 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu private val currentXsp get() = checkApi().let { runCatching { - (xPrefs[prefsName]?.instance ?: XSharedPreferencesDelegate.from(YukiXposedModule.modulePackageName, prefsName).also { - xPrefs[prefsName] = it - }.instance).apply { + (xPrefs[currentPrefsName]?.instance ?: XSharedPreferencesDelegate.from(YukiXposedModule.modulePackageName, currentPrefsName) + .also { + xPrefs[currentPrefsName] = it + }.instance).apply { makeWorldReadable() reload() } @@ -180,21 +187,22 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu get() = checkApi().let { runCatching { @Suppress("DEPRECATION", "WorldReadableFiles") - sPrefs[context.toString() + prefsName] ?: context?.getSharedPreferences(prefsName, Context.MODE_WORLD_READABLE)?.also { - isUsingNewXSharedPreferences = true - sPrefs[context.toString() + prefsName] = it - } ?: error("YukiHookModulePrefs missing Context instance") + sPrefs[context.toString() + currentPrefsName] ?: context?.getSharedPreferences(currentPrefsName, Context.MODE_WORLD_READABLE) + ?.also { + isUsingNewXSharedPreferences = true + sPrefs[context.toString() + currentPrefsName] = it + } ?: error("YukiHookPrefsBridge missing Context instance") }.getOrElse { - sPrefs[context.toString() + prefsName] ?: context?.getSharedPreferences(prefsName, Context.MODE_PRIVATE)?.also { + sPrefs[context.toString() + currentPrefsName] ?: context?.getSharedPreferences(currentPrefsName, Context.MODE_PRIVATE)?.also { isUsingNewXSharedPreferences = false - sPrefs[context.toString() + prefsName] = it - } ?: error("YukiHookModulePrefs missing Context instance") + sPrefs[context.toString() + currentPrefsName] = it + } ?: error("YukiHookPrefsBridge missing Context instance") } } /** 设置全局可读可写 */ private fun makeWorldReadable() = runCatching { - if (isUsingNewXSharedPreferences.not()) makeWorldReadable(context, prefsFileName = "${prefsName}.xml") + if (isUsingNewXSharedPreferences.not()) makeWorldReadable(context, prefsFileName = "${currentPrefsName}.xml") } /** @@ -209,7 +217,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu val isXSharePrefsReadable get() = isPreferencesAvailable /** - * 获取 [YukiHookModulePrefs] 是否正处于 EdXposed/LSPosed 的最高权限运行 + * 获取 [YukiHookPrefsBridge] 是否正处于 EdXposed/LSPosed 的最高权限运行 * * - ❗此方法已弃用 - 在之后的版本中将直接被删除 * @@ -220,7 +228,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu val isRunInNewXShareMode get() = isPreferencesAvailable /** - * 获取当前 [YukiHookModulePrefs] 的可用状态 + * 获取当前 [YukiHookPrefsBridge] 的可用状态 * * - 在 (Xposed) 宿主环境中返回 [XSharedPreferences] 可用状态 (可读) * @@ -239,10 +247,10 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu /** * 自定义 Sp 存储名称 * @param name 自定义的 Sp 存储名称 - * @return [YukiHookModulePrefs] + * @return [YukiHookPrefsBridge] */ - fun name(name: String): YukiHookModulePrefs { - isUsingKeyValueCache = YukiHookAPI.Configs.isEnableModulePrefsCache + fun name(name: String): YukiHookPrefsBridge { + isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache prefsName = name return this } @@ -253,13 +261,25 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * 无论是否开启 [YukiHookAPI.Configs.isEnableModulePrefsCache] * * - 仅在 [XSharedPreferences] 下生效 - * @return [YukiHookModulePrefs] + * @return [YukiHookPrefsBridge] */ - fun direct(): YukiHookModulePrefs { + fun direct(): YukiHookPrefsBridge { isUsingKeyValueCache = false return this } + /** + * 忽略当前环境直接使用 [Context.getSharedPreferences] 存取数据 + * @return [YukiHookPrefsBridge] + * @throws IllegalStateException 如果 [context] 为空 + */ + fun native(): YukiHookPrefsBridge { + if (isXposedEnvironment && context == null) context = AppParasitics.currentApplication + ?: error("The Host App's Context has not yet initialized successfully, the native function cannot be used at this time") + isUsingNativeStorage = true + return this + } + /** * 获取 [String] 键值 * @@ -271,7 +291,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * @return [String] */ fun getString(key: String, value: String = "") = - (if (isXposedEnvironment) + (if (isXposedEnvironment && isUsingNativeStorage.not()) if (isUsingKeyValueCache) XSharedPreferencesCaches.stringData[key].let { (it ?: currentXsp.getString(key, value) ?: value).let { value -> @@ -282,7 +302,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu else resetCacheSet { currentXsp.getString(key, value) ?: value } else currentSp.getString(key, value) ?: value).let { makeWorldReadable() - it + resetNativeSet { it } } /** @@ -296,7 +316,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * @return [Set]<[String]> */ fun getStringSet(key: String, value: Set) = - (if (isXposedEnvironment) + (if (isXposedEnvironment && isUsingNativeStorage.not()) if (isUsingKeyValueCache) XSharedPreferencesCaches.stringSetData[key].let { (it ?: currentXsp.getStringSet(key, value) ?: value).let { value -> @@ -307,7 +327,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu else resetCacheSet { currentXsp.getStringSet(key, value) ?: value } else currentSp.getStringSet(key, value) ?: value).let { makeWorldReadable() - it + resetNativeSet { it } } /** @@ -321,7 +341,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * @return [Boolean] */ fun getBoolean(key: String, value: Boolean = false) = - (if (isXposedEnvironment) + (if (isXposedEnvironment && isUsingNativeStorage.not()) if (isUsingKeyValueCache) XSharedPreferencesCaches.booleanData[key].let { it ?: currentXsp.getBoolean(key, value).let { value -> @@ -332,7 +352,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu else resetCacheSet { currentXsp.getBoolean(key, value) } else currentSp.getBoolean(key, value)).let { makeWorldReadable() - it + resetNativeSet { it } } /** @@ -346,7 +366,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * @return [Int] */ fun getInt(key: String, value: Int = 0) = - (if (isXposedEnvironment) + (if (isXposedEnvironment && isUsingNativeStorage.not()) if (isUsingKeyValueCache) XSharedPreferencesCaches.intData[key].let { it ?: currentXsp.getInt(key, value).let { value -> @@ -357,7 +377,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu else resetCacheSet { currentXsp.getInt(key, value) } else currentSp.getInt(key, value)).let { makeWorldReadable() - it + resetNativeSet { it } } /** @@ -371,7 +391,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * @return [Float] */ fun getFloat(key: String, value: Float = 0f) = - (if (isXposedEnvironment) + (if (isXposedEnvironment && isUsingNativeStorage.not()) if (isUsingKeyValueCache) XSharedPreferencesCaches.floatData[key].let { it ?: currentXsp.getFloat(key, value).let { value -> @@ -382,7 +402,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu else resetCacheSet { currentXsp.getFloat(key, value) } else currentSp.getFloat(key, value)).let { makeWorldReadable() - it + resetNativeSet { it } } /** @@ -396,7 +416,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * @return [Long] */ fun getLong(key: String, value: Long = 0L) = - (if (isXposedEnvironment) + (if (isXposedEnvironment && isUsingNativeStorage.not()) if (isUsingKeyValueCache) XSharedPreferencesCaches.longData[key].let { it ?: currentXsp.getLong(key, value).let { value -> @@ -407,7 +427,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu else resetCacheSet { currentXsp.getLong(key, value) } else currentSp.getLong(key, value)).let { makeWorldReadable() - it + resetNativeSet { it } } /** @@ -617,12 +637,22 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * @return [T] */ private inline fun resetCacheSet(result: () -> T): T { - isUsingKeyValueCache = YukiHookAPI.Configs.isEnableModulePrefsCache + isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache return result() } /** - * [YukiHookModulePrefs] 的存储代理类 + * 恢复 [isUsingNativeStorage] 为默认状态 + * @param result 回调方法体的结果 + * @return [T] + */ + private inline fun resetNativeSet(result: () -> T): T { + isUsingNativeStorage = false + return result() + } + + /** + * [YukiHookPrefsBridge] 的存储代理类 * * - ❗请使用 [edit] 方法来获取 [Editor] * @@ -770,10 +800,10 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * 提交更改 (同步) * @return [Boolean] 是否成功 */ - fun commit() = editor?.commit()?.also { makeWorldReadable() } ?: false + fun commit() = resetNativeSet { editor?.commit()?.also { makeWorldReadable() } ?: false } /** 提交更改 (异步) */ - fun apply() = editor?.apply().also { makeWorldReadable() } ?: Unit + fun apply() = resetNativeSet { editor?.apply().also { makeWorldReadable() } ?: Unit } /** * 仅在模块环境执行 @@ -783,8 +813,8 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu * @return [Editor] */ private inline fun moduleEnvironment(callback: () -> Unit): Editor { - if (isXposedEnvironment.not()) callback() - else yLoggerW(msg = "YukiHookModulePrefs.Editor not allowed in Xposed Environment") + if (isXposedEnvironment.not() || isUsingNativeStorage) callback() + else yLoggerW(msg = "YukiHookPrefsBridge.Editor not allowed in Xposed Environment") return this } } diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.kt index e0f69ee6..ad286f03 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData.kt @@ -27,13 +27,13 @@ */ package com.highcapable.yukihookapi.hook.xposed.prefs.data -import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs +import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookPrefsBridge import java.io.Serializable /** * 键值对存储构造类 * - * 这个类是对 [YukiHookModulePrefs] 的一个扩展用法 + * 这个类是对 [YukiHookPrefsBridge] 的一个扩展用法 * * 详情请参考 [API 文档 - PrefsData](https://fankes.github.io/YukiHookAPI/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData) * diff --git a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.kt b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.kt index 0f0b0877..d5d02564 100644 --- a/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.kt +++ b/yukihookapi/src/main/java/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment.kt @@ -38,7 +38,7 @@ import androidx.preference.PreferenceManager import androidx.preference.PreferenceScreen import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.hook.utils.unit -import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs +import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookPrefsBridge /** * 这是对使用 [YukiHookAPI] Xposed 模块实现中的一个扩展功能 @@ -105,5 +105,5 @@ abstract class ModulePreferenceFragment : PreferenceFragmentCompat(), SharedPref private fun makeNewXShareReadableIfPossible() = runCatching { @Suppress("DEPRECATION", "WorldReadableFiles") currentActivity.getSharedPreferences(prefsName, Context.MODE_WORLD_READABLE) - }.onFailure { YukiHookModulePrefs.makeWorldReadable(currentActivity, prefsFileName = "$prefsName.xml") }.unit() + }.onFailure { YukiHookPrefsBridge.makeWorldReadable(currentActivity, prefsFileName = "$prefsName.xml") }.unit() } \ No newline at end of file