Modify change YukiHookModulePrefs name to YukiHookPrefsBridge and make it support native storage usage in YukiHookPrefsBridge

This commit is contained in:
2023-04-17 03:35:05 +08:00
parent e298f19e33
commit 390ee9e509
23 changed files with 458 additions and 194 deletions

View File

@@ -29,7 +29,7 @@ const navigationLinks = {
baseApiPath + 'hook/param/HookParam', baseApiPath + 'hook/param/HookParam',
baseApiPath + 'annotation/xposed/InjectYukiHookWithXposed', baseApiPath + 'annotation/xposed/InjectYukiHookWithXposed',
baseApiPath + 'hook/xposed/proxy/IYukiHookXposedInit', 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/ui/ModulePreferenceFragment',
baseApiPath + 'hook/xposed/prefs/data/PrefsData', baseApiPath + 'hook/xposed/prefs/data/PrefsData',
baseApiPath + 'hook/xposed/channel/YukiHookDataChannel', baseApiPath + 'hook/xposed/channel/YukiHookDataChannel',

View File

@@ -6,7 +6,7 @@
> Here are the unresolved issues with `YukiHookAPI`. > Here are the unresolved issues with `YukiHookAPI`.
### YukiHookModulePrefs ### YukiHookPrefsBridge
Currently only supports LSPosed perfectly, other Xposed Framework need to downgrade the module target api. Currently only supports LSPosed perfectly, other Xposed Framework need to downgrade the module target api.

View File

@@ -404,23 +404,33 @@ var isDebug: Boolean
请转移到 `YukiHookLogger.Configs.isEnable` 请转移到 `YukiHookLogger.Configs.isEnable`
### isEnableModulePrefsCache <span class="symbol">- field</span> <h3 class="deprecated">isEnableModulePrefsCache - field</h3>
```kotlin:no-line-numbers
var isEnableModulePrefsCache: Boolean
```
**Change Records** **Change Records**
`v1.0.5` `added` `v1.0.5` `added`
`v1.1.9` `deprecated`
请转移到 `isEnablePrefsBridgeCache`
### isEnablePrefsBridgeCache <span class="symbol">- field</span>
```kotlin:no-line-numbers
var isEnablePrefsBridgeCache: Boolean
```
**Change Records**
`v1.1.9` `added`
**Function Illustrate** **Function Illustrate**
> 是否启用 `YukiHookModulePrefs` 的键值缓存功能。 > 是否启用 `YukiHookPrefsBridge` 的键值缓存功能。
为防止内存复用过高问题,此功能默认启用。 为防止内存复用过高问题,此功能默认启用。
你可以手动在 `YukiHookModulePrefs` 中自由开启和关闭缓存功能以及清除缓存。 你可以手动在 `YukiHookPrefsBridge` 中自由开启和关闭缓存功能以及清除缓存。
### isEnableModuleAppResourcesCache <span class="symbol">- field</span> ### isEnableModuleAppResourcesCache <span class="symbol">- field</span>
@@ -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) elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
} }
isDebug = BuildConfig.DEBUG isDebug = BuildConfig.DEBUG
isEnableModulePrefsCache = true isEnablePrefsBridgeCache = true
isEnableModuleAppResourcesCache = true isEnableModuleAppResourcesCache = true
isEnableHookModuleStatus = true isEnableHookModuleStatus = true
isEnableHookSharedPreferences = false isEnableHookSharedPreferences = false
@@ -602,7 +612,7 @@ object HookEntry : IYukiHookXposedInit {
elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
} }
isDebug = BuildConfig.DEBUG isDebug = BuildConfig.DEBUG
isEnableModulePrefsCache = true isEnablePrefsBridgeCache = true
isEnableModuleAppResourcesCache = true isEnableModuleAppResourcesCache = true
isEnableHookModuleStatus = true isEnableHookModuleStatus = true
isEnableHookSharedPreferences = false isEnableHookSharedPreferences = false
@@ -634,7 +644,7 @@ object HookEntry : IYukiHookXposedInit {
YukiHookLogger.Configs.USER_ID YukiHookLogger.Configs.USER_ID
) )
YukiHookAPI.Configs.isDebug = BuildConfig.DEBUG YukiHookAPI.Configs.isDebug = BuildConfig.DEBUG
YukiHookAPI.Configs.isEnableModulePrefsCache = true YukiHookAPI.Configs.isEnablePrefsBridgeCache = true
YukiHookAPI.Configs.isEnableModuleAppResourcesCache = true YukiHookAPI.Configs.isEnableModuleAppResourcesCache = true
YukiHookAPI.Configs.isEnableHookModuleStatus = true YukiHookAPI.Configs.isEnableHookModuleStatus = true
YukiHookAPI.Configs.isEnableHookSharedPreferences = false YukiHookAPI.Configs.isEnableHookSharedPreferences = false

View File

@@ -64,33 +64,45 @@ fun IYukiHookXposedInit.encase(vararg hooker: YukiBaseHooker)
> 在 `IYukiHookXposedInit` 中调用 `YukiHookAPI`。 > 在 `IYukiHookXposedInit` 中调用 `YukiHookAPI`。
## Context.modulePrefs <span class="symbol">- ext-field</span> <h2 class="deprecated">Context.modulePrefs - ext-field</h2>
```kotlin:no-line-numbers
val Context.modulePrefs: YukiHookModulePrefs
```
**Change Records** **Change Records**
`v1.0` `first` `v1.0` `first`
**Function Illustrate** `v1.1.9` `deprecated`
> 获取模块的存取对象。 请转移到 `prefs` 方法
## Context.modulePrefs <span class="symbol">- ext-method</span> <h2 class="deprecated">Context.modulePrefs - ext-method</h2>
```kotlin:no-line-numbers
fun Context.modulePrefs(name: String): YukiHookModulePrefs
```
**Change Records** **Change Records**
`v1.0` `first` `v1.0` `first`
`v1.1.9` `deprecated`
请转移到 `prefs` 方法
## Context.prefs <span class="symbol">- ext-method</span>
```kotlin:no-line-numbers
fun Context.prefs(name: String): YukiHookPrefsBridge
```
**Change Records**
`v1.1.9` `added`
**Function Illustrate** **Function Illustrate**
> 获取模块的存取对象,可设置 `name` 为自定义 Sp 存储名称 > 获取 `YukiHookPrefsBridge` 对象
可以同时在模块与 (Xposed) 宿主环境中使用。
如果你想在 (Xposed) 宿主环境将数据存入当前宿主的私有空间,请使用 `YukiHookPrefsBridge.native` 方法。
在未声明任何条件的情况下 (Xposed) 宿主环境默认读取模块中的数据。
## Context.dataChannel <span class="symbol">- ext-method</span> ## Context.dataChannel <span class="symbol">- ext-method</span>

View File

@@ -243,7 +243,7 @@ val moduleAppResources: YukiModuleResources
## prefs <span class="symbol">- field</span> ## prefs <span class="symbol">- field</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
val prefs: YukiHookModulePrefs val prefs: YukiHookPrefsBridge
``` ```
**Change Records** **Change Records**
@@ -263,7 +263,7 @@ val prefs: YukiHookModulePrefs
## prefs <span class="symbol">- method</span> ## prefs <span class="symbol">- method</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
fun prefs(name: String): YukiHookModulePrefs fun prefs(name: String): YukiHookPrefsBridge
``` ```
**Change Records** **Change Records**

View File

@@ -10,25 +10,29 @@ You can use the **Chrome Translation Plugin** to translate entire pages for refe
::: :::
# YukiHookModulePrefs <span class="symbol">- class</span> # YukiHookPrefsBridge <span class="symbol">- class</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
class YukiHookModulePrefs private constructor(private var context: Context?) class YukiHookPrefsBridge private constructor(private var context: Context?)
``` ```
**Change Records** **Change Records**
`v1.0` `first` `v1.0` `first`
`v1.1.9` `modified`
~~`YukiHookModulePrefs`~~ 更名为 `YukiHookPrefsBridge`
**Function Illustrate** **Function Illustrate**
> 实现 Xposed 模块的数据存取,对接 `SharedPreferences``XSharedPreferences` > `YukiHookAPI` `SharedPreferences``XSharedPreferences` 的扩展存储桥实现
在不同环境智能选择存取使用的对象。 在不同环境智能选择存取使用的对象。
::: danger ::: 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)。 太极请参阅 [文件权限/配置/XSharedPreference](https://taichi.cool/zh/doc/for-xposed-dev.html#文件权限-配置-xsharedpreference)。
::: danger 对于在模块环境中使用 `PreferenceFragmentCompat``YukiHookAPI` 提供了 `ModulePreferenceFragment` 来实现同样的功能。
当你在 Xposed 模块中存取数据的时候 **context** 必须不能是空的。
:::
若你正在使用 `PreferenceFragmentCompat`,请迁移到 `ModulePreferenceFragment` 以适配上述功能特性。
**Optional Configuration** **Optional Configuration**
@@ -96,7 +94,7 @@ val isPreferencesAvailable: Boolean
**Function Illustrate** **Function Illustrate**
> 获取当前 `YukiHookModulePrefs` 的可用状态。 > 获取当前 `YukiHookPrefsBridge` 的可用状态。
在 (Xposed) 宿主环境中返回 `XSharedPreferences` 可用状态 (可读)。 在 (Xposed) 宿主环境中返回 `XSharedPreferences` 可用状态 (可读)。
@@ -105,7 +103,7 @@ val isPreferencesAvailable: Boolean
## name <span class="symbol">- method</span> ## name <span class="symbol">- method</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
fun name(name: String): YukiHookModulePrefs fun name(name: String): YukiHookPrefsBridge
``` ```
**Change Records** **Change Records**
@@ -123,7 +121,7 @@ fun name(name: String): YukiHookModulePrefs
> The following example > The following example
```kotlin ```kotlin
modulePrefs("custom_name").getString("custom_key") prefs("custom_name").getString("custom_key")
``` ```
在 (Xposed) 宿主环境 `PackageParam` 中的使用方法。 在 (Xposed) 宿主环境 `PackageParam` 中的使用方法。
@@ -137,7 +135,7 @@ prefs("custom_name").getString("custom_key")
## direct <span class="symbol">- method</span> ## direct <span class="symbol">- method</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
fun direct(): YukiHookModulePrefs fun direct(): YukiHookPrefsBridge
``` ```
**Change Records** **Change Records**
@@ -148,10 +146,24 @@ fun direct(): YukiHookModulePrefs
> 忽略缓存直接读取键值。 > 忽略缓存直接读取键值。
无论是否开启 `YukiHookAPI.Configs.isEnableModulePrefsCache` 无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`
仅在 `XSharedPreferences` 下生效。 仅在 `XSharedPreferences` 下生效。
## native <span class="symbol">- method</span>
```kotlin:no-line-numbers
fun native(): YukiHookPrefsBridge
```
**Change Records**
`v1.1.9` `added`
**Function Illustrate**
> 忽略当前环境直接使用 `Context.getSharedPreferences` 存取数据。
## getString <span class="symbol">- method</span> ## getString <span class="symbol">- method</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
@@ -434,7 +446,7 @@ fun clearCache()
> 清除 `XSharedPreferences` 中缓存的键值数据。 > 清除 `XSharedPreferences` 中缓存的键值数据。
无论是否开启 `YukiHookAPI.Configs.isEnableModulePrefsCache` 无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`
调用此方法将清除当前存储的全部键值缓存。 调用此方法将清除当前存储的全部键值缓存。
@@ -454,7 +466,7 @@ inner class Editor internal constructor()
**Function Illustrate** **Function Illustrate**
> `YukiHookModulePrefs` 的存储代理类。 > `YukiHookPrefsBridge` 的存储代理类。
请使用 `edit` 方法来获取 `Editor` 请使用 `edit` 方法来获取 `Editor`

View File

@@ -28,7 +28,7 @@ data class PrefsData<T>(var key: String, var value: T) : Serializable
> 键值对存储构造类。 > 键值对存储构造类。
这个类是对 `YukiHookModulePrefs` 的一个扩展用法。 这个类是对 `YukiHookPrefsBridge` 的一个扩展用法。
**Function Example** **Function Example**
@@ -51,9 +51,9 @@ object DataConst {
```kotlin ```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") }
``` ```
> 宿主示例如下 > 宿主示例如下

View File

@@ -10,7 +10,7 @@ The native `Xposed` provides us with a `XSharedPreferences` for reading the `Sp`
## Use in Activity ## 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. 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 > The following example
```kotlin ```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. 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") 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. 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 ```kotlin
// Recommended usage // 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 // 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. 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. 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
// <Scenario 1>
prefs().edit {
putString("test_name_1", "saved_value_1")
putString("test_name_2", "saved_value_2")
putString("test_name_3", "saved_value_3")
}
// <Scenario 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 ::: 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 ## 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`. If your Module App uses `PreferenceFragmentCompat`, you can now start migrating its extends `ModulePreferenceFragment`.
::: danger ::: 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**.
::: :::
@@ -91,3 +110,49 @@ 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). 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 <u>**will be stored and read in the private directory of the corresponding environment**</u>, 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).
:::

View File

@@ -218,6 +218,6 @@ For configuration details related to use as a Hook API, you can [click here](../
::: warning ::: 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.
::: :::

View File

@@ -6,7 +6,7 @@
> 这里收录了 `YukiHookAPI` 尚未解决的问题。 > 这里收录了 `YukiHookAPI` 尚未解决的问题。
### YukiHookModulePrefs ### YukiHookPrefsBridge
目前仅限完美支持 LSPosed其它 Xposed 框架需要降级模块 API。 目前仅限完美支持 LSPosed其它 Xposed 框架需要降级模块 API。

View File

@@ -396,23 +396,33 @@ var isDebug: Boolean
请转移到 `YukiHookLogger.Configs.isEnable` 请转移到 `YukiHookLogger.Configs.isEnable`
### isEnableModulePrefsCache <span class="symbol">- field</span> <h3 class="deprecated">isEnableModulePrefsCache - field</h3>
```kotlin:no-line-numbers
var isEnableModulePrefsCache: Boolean
```
**变更记录** **变更记录**
`v1.0.5` `新增` `v1.0.5` `新增`
`v1.1.9` `作废`
请转移到 `isEnablePrefsBridgeCache`
### isEnablePrefsBridgeCache <span class="symbol">- field</span>
```kotlin:no-line-numbers
var isEnablePrefsBridgeCache: Boolean
```
**变更记录**
`v1.1.9` `新增`
**功能描述** **功能描述**
> 是否启用 `YukiHookModulePrefs` 的键值缓存功能。 > 是否启用 `YukiHookPrefsBridge` 的键值缓存功能。
为防止内存复用过高问题,此功能默认启用。 为防止内存复用过高问题,此功能默认启用。
你可以手动在 `YukiHookModulePrefs` 中自由开启和关闭缓存功能以及清除缓存。 你可以手动在 `YukiHookPrefsBridge` 中自由开启和关闭缓存功能以及清除缓存。
### isEnableModuleAppResourcesCache <span class="symbol">- field</span> ### isEnableModuleAppResourcesCache <span class="symbol">- field</span>
@@ -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) elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
} }
isDebug = BuildConfig.DEBUG isDebug = BuildConfig.DEBUG
isEnableModulePrefsCache = true isEnablePrefsBridgeCache = true
isEnableModuleAppResourcesCache = true isEnableModuleAppResourcesCache = true
isEnableHookModuleStatus = true isEnableHookModuleStatus = true
isEnableHookSharedPreferences = false isEnableHookSharedPreferences = false
@@ -594,7 +604,7 @@ object HookEntry : IYukiHookXposedInit {
elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID) elements(TAG, PRIORITY, PACKAGE_NAME, USER_ID)
} }
isDebug = BuildConfig.DEBUG isDebug = BuildConfig.DEBUG
isEnableModulePrefsCache = true isEnablePrefsBridgeCache = true
isEnableModuleAppResourcesCache = true isEnableModuleAppResourcesCache = true
isEnableHookModuleStatus = true isEnableHookModuleStatus = true
isEnableHookSharedPreferences = false isEnableHookSharedPreferences = false
@@ -626,7 +636,7 @@ object HookEntry : IYukiHookXposedInit {
YukiHookLogger.Configs.USER_ID YukiHookLogger.Configs.USER_ID
) )
YukiHookAPI.Configs.isDebug = BuildConfig.DEBUG YukiHookAPI.Configs.isDebug = BuildConfig.DEBUG
YukiHookAPI.Configs.isEnableModulePrefsCache = true YukiHookAPI.Configs.isEnablePrefsBridgeCache = true
YukiHookAPI.Configs.isEnableModuleAppResourcesCache = true YukiHookAPI.Configs.isEnableModuleAppResourcesCache = true
YukiHookAPI.Configs.isEnableHookModuleStatus = true YukiHookAPI.Configs.isEnableHookModuleStatus = true
YukiHookAPI.Configs.isEnableHookSharedPreferences = false YukiHookAPI.Configs.isEnableHookSharedPreferences = false

View File

@@ -56,33 +56,45 @@ fun IYukiHookXposedInit.encase(vararg hooker: YukiBaseHooker)
> 在 `IYukiHookXposedInit` 中调用 `YukiHookAPI`。 > 在 `IYukiHookXposedInit` 中调用 `YukiHookAPI`。
## Context.modulePrefs <span class="symbol">- ext-field</span> <h2 class="deprecated">Context.modulePrefs - ext-field</h2>
```kotlin:no-line-numbers
val Context.modulePrefs: YukiHookModulePrefs
```
**变更记录** **变更记录**
`v1.0` `添加` `v1.0` `添加`
**功能描述** `v1.1.9` `作废`
> 获取模块的存取对象。 请转移到 `prefs` 方法
## Context.modulePrefs <span class="symbol">- ext-method</span> <h2 class="deprecated">Context.modulePrefs - ext-method</h2>
```kotlin:no-line-numbers
fun Context.modulePrefs(name: String): YukiHookModulePrefs
```
**变更记录** **变更记录**
`v1.0` `添加` `v1.0` `添加`
`v1.1.9` `作废`
请转移到 `prefs` 方法
## Context.prefs <span class="symbol">- ext-method</span>
```kotlin:no-line-numbers
fun Context.prefs(name: String): YukiHookPrefsBridge
```
**变更记录**
`v1.1.9` `新增`
**功能描述** **功能描述**
> 获取模块的存取对象,可设置 `name` 为自定义 Sp 存储名称 > 获取 `YukiHookPrefsBridge` 对象
可以同时在模块与 (Xposed) 宿主环境中使用。
如果你想在 (Xposed) 宿主环境将数据存入当前宿主的私有空间,请使用 `YukiHookPrefsBridge.native` 方法。
在未声明任何条件的情况下 (Xposed) 宿主环境默认读取模块中的数据。
## Context.dataChannel <span class="symbol">- ext-method</span> ## Context.dataChannel <span class="symbol">- ext-method</span>

View File

@@ -235,7 +235,7 @@ val moduleAppResources: YukiModuleResources
## prefs <span class="symbol">- field</span> ## prefs <span class="symbol">- field</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
val prefs: YukiHookModulePrefs val prefs: YukiHookPrefsBridge
``` ```
**变更记录** **变更记录**
@@ -255,7 +255,7 @@ val prefs: YukiHookModulePrefs
## prefs <span class="symbol">- method</span> ## prefs <span class="symbol">- method</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
fun prefs(name: String): YukiHookModulePrefs fun prefs(name: String): YukiHookPrefsBridge
``` ```
**变更记录** **变更记录**

View File

@@ -2,25 +2,29 @@
pageClass: code-page pageClass: code-page
--- ---
# YukiHookModulePrefs <span class="symbol">- class</span> # YukiHookPrefsBridge <span class="symbol">- class</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
class YukiHookModulePrefs private constructor(private var context: Context?) class YukiHookPrefsBridge private constructor(private var context: Context?)
``` ```
**变更记录** **变更记录**
`v1.0` `添加` `v1.0` `添加`
`v1.1.9` `修改`
~~`YukiHookModulePrefs`~~ 更名为 `YukiHookPrefsBridge`
**功能描述** **功能描述**
> 实现 Xposed 模块的数据存取,对接 `SharedPreferences``XSharedPreferences` > `YukiHookAPI` `SharedPreferences``XSharedPreferences` 的扩展存储桥实现
在不同环境智能选择存取使用的对象。 在不同环境智能选择存取使用的对象。
::: danger ::: 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)。 太极请参阅 [文件权限/配置/XSharedPreference](https://taichi.cool/zh/doc/for-xposed-dev.html#文件权限-配置-xsharedpreference)。
::: danger 对于在模块环境中使用 `PreferenceFragmentCompat``YukiHookAPI` 提供了 `ModulePreferenceFragment` 来实现同样的功能。
当你在 Xposed 模块中存取数据的时候 **context** 必须不能是空的。
:::
若你正在使用 `PreferenceFragmentCompat`,请迁移到 `ModulePreferenceFragment` 以适配上述功能特性。
**可选配置** **可选配置**
@@ -88,7 +86,7 @@ val isPreferencesAvailable: Boolean
**功能描述** **功能描述**
> 获取当前 `YukiHookModulePrefs` 的可用状态。 > 获取当前 `YukiHookPrefsBridge` 的可用状态。
在 (Xposed) 宿主环境中返回 `XSharedPreferences` 可用状态 (可读)。 在 (Xposed) 宿主环境中返回 `XSharedPreferences` 可用状态 (可读)。
@@ -97,7 +95,7 @@ val isPreferencesAvailable: Boolean
## name <span class="symbol">- method</span> ## name <span class="symbol">- method</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
fun name(name: String): YukiHookModulePrefs fun name(name: String): YukiHookPrefsBridge
``` ```
**变更记录** **变更记录**
@@ -115,7 +113,7 @@ fun name(name: String): YukiHookModulePrefs
> 示例如下 > 示例如下
```kotlin ```kotlin
modulePrefs("custom_name").getString("custom_key") prefs("custom_name").getString("custom_key")
``` ```
在 (Xposed) 宿主环境 `PackageParam` 中的使用方法。 在 (Xposed) 宿主环境 `PackageParam` 中的使用方法。
@@ -129,7 +127,7 @@ prefs("custom_name").getString("custom_key")
## direct <span class="symbol">- method</span> ## direct <span class="symbol">- method</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
fun direct(): YukiHookModulePrefs fun direct(): YukiHookPrefsBridge
``` ```
**变更记录** **变更记录**
@@ -140,10 +138,24 @@ fun direct(): YukiHookModulePrefs
> 忽略缓存直接读取键值。 > 忽略缓存直接读取键值。
无论是否开启 `YukiHookAPI.Configs.isEnableModulePrefsCache` 无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`
仅在 `XSharedPreferences` 下生效。 仅在 `XSharedPreferences` 下生效。
## native <span class="symbol">- method</span>
```kotlin:no-line-numbers
fun native(): YukiHookPrefsBridge
```
**变更记录**
`v1.1.9` `新增`
**功能描述**
> 忽略当前环境直接使用 `Context.getSharedPreferences` 存取数据。
## getString <span class="symbol">- method</span> ## getString <span class="symbol">- method</span>
```kotlin:no-line-numbers ```kotlin:no-line-numbers
@@ -426,7 +438,7 @@ fun clearCache()
> 清除 `XSharedPreferences` 中缓存的键值数据。 > 清除 `XSharedPreferences` 中缓存的键值数据。
无论是否开启 `YukiHookAPI.Configs.isEnableModulePrefsCache` 无论是否开启 `YukiHookAPI.Configs.isEnablePrefsBridgeCache`
调用此方法将清除当前存储的全部键值缓存。 调用此方法将清除当前存储的全部键值缓存。
@@ -446,7 +458,7 @@ inner class Editor internal constructor()
**功能描述** **功能描述**
> `YukiHookModulePrefs` 的存储代理类。 > `YukiHookPrefsBridge` 的存储代理类。
请使用 `edit` 方法来获取 `Editor` 请使用 `edit` 方法来获取 `Editor`

View File

@@ -20,7 +20,7 @@ data class PrefsData<T>(var key: String, var value: T) : Serializable
> 键值对存储构造类。 > 键值对存储构造类。
这个类是对 `YukiHookModulePrefs` 的一个扩展用法。 这个类是对 `YukiHookPrefsBridge` 的一个扩展用法。
**功能示例** **功能示例**
@@ -43,9 +43,9 @@ object DataConst {
```kotlin ```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") }
``` ```
> 宿主示例如下 > 宿主示例如下

View File

@@ -8,7 +8,7 @@
## 在 Activity 中使用 ## 在 Activity 中使用
> 这里描述了在 `Activity` 中装载 `YukiHookModulePrefs` 的场景。 > 这里描述了在 `Activity` 中装载 `YukiHookPrefsBridge` 的场景。
通常情况下我们可以这样在 Hook APP (宿主) 内对其进行初始化。 通常情况下我们可以这样在 Hook APP (宿主) 内对其进行初始化。
@@ -25,7 +25,7 @@ XSharedPreferences(BuildConfig.APPLICATION_ID)
> 示例如下 > 示例如下
```kotlin ```kotlin
modulePrefs.putString("test_name", "saved_value") prefs().edit { putString("test_name", "saved_value") }
``` ```
当你在 Hook APP (宿主) 中读取数据时,可以使用如下方法。 当你在 Hook APP (宿主) 中读取数据时,可以使用如下方法。
@@ -36,7 +36,7 @@ modulePrefs.putString("test_name", "saved_value")
val testName = prefs.getString("test_name", "default_value") val testName = prefs.getString("test_name", "default_value")
``` ```
你不需要考虑传入模块的包名以及一系列复杂的权限配置,一切都交给 `YukiHookModulePrefs` 来处理。 你不需要考虑传入模块的包名以及一系列复杂的权限配置,一切都交给 `YukiHookPrefsBridge` 来处理。
若要实现存储的区域划分,你可以指定每个 `prefs` 文件的名称。 若要实现存储的区域划分,你可以指定每个 `prefs` 文件的名称。
@@ -46,9 +46,9 @@ val testName = prefs.getString("test_name", "default_value")
```kotlin ```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 (宿主) 中这样读取。 在 Hook APP (宿主) 中这样读取。
@@ -64,21 +64,40 @@ val testName = prefs.name("specify_file_name").getString("test_name", "default_v
若你的项目中有大量的固定数据需要存储和读取,推荐使用 `PrefsData` 来创建模板。 若你的项目中有大量的固定数据需要存储和读取,推荐使用 `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 ::: 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 中使用
> 这里描述了在 `PreferenceFragment` 中装载 `YukiHookModulePrefs` 的场景。 > 这里描述了在 `PreferenceFragment` 中装载 `YukiHookPrefsBridge` 的场景。
若你的模块使用了 `PreferenceFragmentCompat`,你现在可以将其继承类开始迁移到 `ModulePreferenceFragment` 若你的模块使用了 `PreferenceFragmentCompat`,你现在可以将其继承类开始迁移到 `ModulePreferenceFragment`
::: danger ::: danger
你必须继承 **ModulePreferenceFragment** 才能实现 **YukiHookModulePrefs** 的模块存储功能。 你必须继承 **ModulePreferenceFragment** 才能实现 **YukiHookPrefsBridge** 的模块存储功能。
::: :::
@@ -87,3 +106,49 @@ val testName = prefs.name("specify_file_name").getString("test_name", "default_v
更多功能请参考 [ModulePreferenceFragment](../public/com/highcapable/yukihookapi/hook/xposed/prefs/ui/ModulePreferenceFragment)。 更多功能请参考 [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` 中都会将数据<u>**在对应环境的私有目录中**</u>存储、读取,数据相互隔离。
::: tip
更多功能请参考 [YukiHookPrefsBridge](../public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge)。
:::

View File

@@ -215,6 +215,6 @@ override fun attachBaseContext(base: Context?) {
::: warning ::: warning
使用自定义的 Hook Framework 而并非完整的 Xposed 模块时,**YukiHookModulePrefs**、**YukiHookDataChannel** 以及 Resources Hook 功能将失效。 使用自定义的 Hook Framework 而并非完整的 Xposed 模块时,**YukiHookPrefsBridge**、**YukiHookDataChannel** 以及 Resources Hook 功能将失效。
::: :::

View File

@@ -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.status.YukiXposedModuleStatus
import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType import com.highcapable.yukihookapi.hook.xposed.bridge.type.HookEntryType
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.YukiHookPrefsBridge
import java.lang.reflect.Constructor import java.lang.reflect.Constructor
import java.lang.reflect.Field import java.lang.reflect.Field
import java.lang.reflect.Member 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] 缓存功能 * 是否启用当前 Xposed 模块自身 [Resources] 缓存功能
@@ -316,7 +330,7 @@ object YukiHookAPI {
* *
* - ❗这是一个可选的实验性功能 - 此功能默认不启用 * - ❗这是一个可选的实验性功能 - 此功能默认不启用
* *
* - 仅用于修复某些系统可能会出现在启用了 New XSharedPreferences 后依然出现文件权限错误问题 - 若你能正常使用 [YukiHookModulePrefs] 就不建议启用此功能 * - 仅用于修复某些系统可能会出现在启用了 New XSharedPreferences 后依然出现文件权限错误问题 - 若你能正常使用 [YukiHookPrefsBridge] 就不建议启用此功能
*/ */
var isEnableHookSharedPreferences = false var isEnableHookSharedPreferences = false

View File

@@ -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.ModuleAppActivity
import com.highcapable.yukihookapi.hook.xposed.parasitic.activity.base.ModuleAppCompatActivity 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.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 com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
import java.io.BufferedReader import java.io.BufferedReader
import java.io.File 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 }
/** /**
* 获取模块的数据通讯桥命名空间对象 * 获取模块的数据通讯桥命名空间对象

View File

@@ -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.bridge.type.HookEntryType
import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel import com.highcapable.yukihookapi.hook.xposed.channel.YukiHookDataChannel
import com.highcapable.yukihookapi.hook.xposed.parasitic.AppParasitics 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 入口对象实现类 * 装载 Hook 的目标 APP 入口对象实现类
@@ -181,16 +181,16 @@ open class PackageParam internal constructor(@PublishedApi internal var wrapper:
* 获得当前使用的存取数据对象缓存实例 * 获得当前使用的存取数据对象缓存实例
* *
* - ❗作为 Hook API 装载时无法使用 - 会抛出异常 * - ❗作为 Hook API 装载时无法使用 - 会抛出异常
* @return [YukiHookModulePrefs] * @return [YukiHookPrefsBridge]
*/ */
val prefs get() = YukiHookModulePrefs.instance() val prefs get() = YukiHookPrefsBridge.instance()
/** /**
* 获得当前使用的存取数据对象缓存实例 * 获得当前使用的存取数据对象缓存实例
* *
* - ❗作为 Hook API 装载时无法使用 - 会抛出异常 * - ❗作为 Hook API 装载时无法使用 - 会抛出异常
* @param name 自定义 Sp 存储名称 * @param name 自定义 Sp 存储名称
* @return [YukiHookModulePrefs] * @return [YukiHookPrefsBridge]
*/ */
fun prefs(name: String) = prefs.name(name) fun prefs(name: String) = prefs.name(name)

View File

@@ -37,42 +37,35 @@ 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.xposed.bridge.YukiXposedModule import com.highcapable.yukihookapi.hook.xposed.bridge.YukiXposedModule
import com.highcapable.yukihookapi.hook.xposed.bridge.delegate.XSharedPreferencesDelegate 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.data.PrefsData
import com.highcapable.yukihookapi.hook.xposed.prefs.ui.ModulePreferenceFragment import com.highcapable.yukihookapi.hook.xposed.prefs.ui.ModulePreferenceFragment
import de.robv.android.xposed.XSharedPreferences import de.robv.android.xposed.XSharedPreferences
import java.io.File import java.io.File
/** /**
* 实现 Xposed 模块的数据存取 * [YukiHookAPI] [SharedPreferences][XSharedPreferences] 的扩展存储桥实现
*
* 对接 [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] 必须不能是空的 * For English version, see [API Document - YukiHookPrefsBridge](https://fankes.github.io/YukiHookAPI/en/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/YukiHookPrefsBridge)
*
* - 若你正在使用 [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)
* @param context 上下文实例 - 默认空 * @param context 上下文实例 - 默认空
*/ */
class YukiHookModulePrefs private constructor(private var context: Context? = null) { class YukiHookPrefsBridge private constructor(private var context: Context? = null) {
internal companion object { internal companion object {
/** 当前是否为 (Xposed) 宿主环境 */ /** 当前是否为 (Xposed) 宿主环境 */
private val isXposedEnvironment = YukiXposedModule.isXposedEnvironment private val isXposedEnvironment = YukiXposedModule.isXposedEnvironment
/** 当前 [YukiHookModulePrefs] 单例 */ /** 当前 [YukiHookPrefsBridge] 单例 */
private var instance: YukiHookModulePrefs? = null private var instance: YukiHookPrefsBridge? = null
/** 当前缓存的 [XSharedPreferencesDelegate] 实例数组 */ /** 当前缓存的 [XSharedPreferencesDelegate] 实例数组 */
private val xPrefs = HashMap<String, XSharedPreferencesDelegate>() private val xPrefs = HashMap<String, XSharedPreferencesDelegate>()
@@ -81,12 +74,12 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
private val sPrefs = HashMap<String, SharedPreferences>() private val sPrefs = HashMap<String, SharedPreferences>()
/** /**
* 获取 [YukiHookModulePrefs] 单例 * 获取 [YukiHookPrefsBridge] 单例
* @param context 实例 - (Xposed) 宿主环境为空 * @param context 实例 - (Xposed) 宿主环境为空
* @return [YukiHookModulePrefs] * @return [YukiHookPrefsBridge]
*/ */
internal fun instance(context: Context? = null) = 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 */ /** 是否使用新版存储方式 EdXposedLSPosed */
private var isUsingNewXSharedPreferences = false private var isUsingNewXSharedPreferences = false
/** 是否启用原生存储方式 */
private var isUsingNativeStorage = false
/** /**
* [XSharedPreferences] 缓存的键值数据 * [XSharedPreferences] 缓存的键值数据
*/ */
@@ -150,7 +156,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
/** 检查 API 装载状态 */ /** 检查 API 装载状态 */
private fun checkApi() { 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()) if (isXposedEnvironment && YukiXposedModule.modulePackageName.isBlank())
error("Xposed modulePackageName load failed, please reset and rebuild it") 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 private val currentXsp
get() = checkApi().let { get() = checkApi().let {
runCatching { runCatching {
(xPrefs[prefsName]?.instance ?: XSharedPreferencesDelegate.from(YukiXposedModule.modulePackageName, prefsName).also { (xPrefs[currentPrefsName]?.instance ?: XSharedPreferencesDelegate.from(YukiXposedModule.modulePackageName, currentPrefsName)
xPrefs[prefsName] = it .also {
}.instance).apply { xPrefs[currentPrefsName] = it
}.instance).apply {
makeWorldReadable() makeWorldReadable()
reload() reload()
} }
@@ -180,21 +187,22 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
get() = checkApi().let { get() = checkApi().let {
runCatching { runCatching {
@Suppress("DEPRECATION", "WorldReadableFiles") @Suppress("DEPRECATION", "WorldReadableFiles")
sPrefs[context.toString() + prefsName] ?: context?.getSharedPreferences(prefsName, Context.MODE_WORLD_READABLE)?.also { sPrefs[context.toString() + currentPrefsName] ?: context?.getSharedPreferences(currentPrefsName, Context.MODE_WORLD_READABLE)
isUsingNewXSharedPreferences = true ?.also {
sPrefs[context.toString() + prefsName] = it isUsingNewXSharedPreferences = true
} ?: error("YukiHookModulePrefs missing Context instance") sPrefs[context.toString() + currentPrefsName] = it
} ?: error("YukiHookPrefsBridge missing Context instance")
}.getOrElse { }.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 isUsingNewXSharedPreferences = false
sPrefs[context.toString() + prefsName] = it sPrefs[context.toString() + currentPrefsName] = it
} ?: error("YukiHookModulePrefs missing Context instance") } ?: error("YukiHookPrefsBridge missing Context instance")
} }
} }
/** 设置全局可读可写 */ /** 设置全局可读可写 */
private fun makeWorldReadable() = runCatching { 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 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 val isRunInNewXShareMode get() = isPreferencesAvailable
/** /**
* 获取当前 [YukiHookModulePrefs] 的可用状态 * 获取当前 [YukiHookPrefsBridge] 的可用状态
* *
* - (Xposed) 宿主环境中返回 [XSharedPreferences] 可用状态 (可读) * - (Xposed) 宿主环境中返回 [XSharedPreferences] 可用状态 (可读)
* *
@@ -239,10 +247,10 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
/** /**
* 自定义 Sp 存储名称 * 自定义 Sp 存储名称
* @param name 自定义的 Sp 存储名称 * @param name 自定义的 Sp 存储名称
* @return [YukiHookModulePrefs] * @return [YukiHookPrefsBridge]
*/ */
fun name(name: String): YukiHookModulePrefs { fun name(name: String): YukiHookPrefsBridge {
isUsingKeyValueCache = YukiHookAPI.Configs.isEnableModulePrefsCache isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache
prefsName = name prefsName = name
return this return this
} }
@@ -253,13 +261,25 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
* 无论是否开启 [YukiHookAPI.Configs.isEnableModulePrefsCache] * 无论是否开启 [YukiHookAPI.Configs.isEnableModulePrefsCache]
* *
* - 仅在 [XSharedPreferences] 下生效 * - 仅在 [XSharedPreferences] 下生效
* @return [YukiHookModulePrefs] * @return [YukiHookPrefsBridge]
*/ */
fun direct(): YukiHookModulePrefs { fun direct(): YukiHookPrefsBridge {
isUsingKeyValueCache = false isUsingKeyValueCache = false
return this 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] 键值 * 获取 [String] 键值
* *
@@ -271,7 +291,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
* @return [String] * @return [String]
*/ */
fun getString(key: String, value: String = "") = fun getString(key: String, value: String = "") =
(if (isXposedEnvironment) (if (isXposedEnvironment && isUsingNativeStorage.not())
if (isUsingKeyValueCache) if (isUsingKeyValueCache)
XSharedPreferencesCaches.stringData[key].let { XSharedPreferencesCaches.stringData[key].let {
(it ?: currentXsp.getString(key, value) ?: value).let { value -> (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 resetCacheSet { currentXsp.getString(key, value) ?: value }
else currentSp.getString(key, value) ?: value).let { else currentSp.getString(key, value) ?: value).let {
makeWorldReadable() makeWorldReadable()
it resetNativeSet { it }
} }
/** /**
@@ -296,7 +316,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
* @return [Set]<[String]> * @return [Set]<[String]>
*/ */
fun getStringSet(key: String, value: Set<String>) = fun getStringSet(key: String, value: Set<String>) =
(if (isXposedEnvironment) (if (isXposedEnvironment && isUsingNativeStorage.not())
if (isUsingKeyValueCache) if (isUsingKeyValueCache)
XSharedPreferencesCaches.stringSetData[key].let { XSharedPreferencesCaches.stringSetData[key].let {
(it ?: currentXsp.getStringSet(key, value) ?: value).let { value -> (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 resetCacheSet { currentXsp.getStringSet(key, value) ?: value }
else currentSp.getStringSet(key, value) ?: value).let { else currentSp.getStringSet(key, value) ?: value).let {
makeWorldReadable() makeWorldReadable()
it resetNativeSet { it }
} }
/** /**
@@ -321,7 +341,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
* @return [Boolean] * @return [Boolean]
*/ */
fun getBoolean(key: String, value: Boolean = false) = fun getBoolean(key: String, value: Boolean = false) =
(if (isXposedEnvironment) (if (isXposedEnvironment && isUsingNativeStorage.not())
if (isUsingKeyValueCache) if (isUsingKeyValueCache)
XSharedPreferencesCaches.booleanData[key].let { XSharedPreferencesCaches.booleanData[key].let {
it ?: currentXsp.getBoolean(key, value).let { value -> 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 resetCacheSet { currentXsp.getBoolean(key, value) }
else currentSp.getBoolean(key, value)).let { else currentSp.getBoolean(key, value)).let {
makeWorldReadable() makeWorldReadable()
it resetNativeSet { it }
} }
/** /**
@@ -346,7 +366,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
* @return [Int] * @return [Int]
*/ */
fun getInt(key: String, value: Int = 0) = fun getInt(key: String, value: Int = 0) =
(if (isXposedEnvironment) (if (isXposedEnvironment && isUsingNativeStorage.not())
if (isUsingKeyValueCache) if (isUsingKeyValueCache)
XSharedPreferencesCaches.intData[key].let { XSharedPreferencesCaches.intData[key].let {
it ?: currentXsp.getInt(key, value).let { value -> 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 resetCacheSet { currentXsp.getInt(key, value) }
else currentSp.getInt(key, value)).let { else currentSp.getInt(key, value)).let {
makeWorldReadable() makeWorldReadable()
it resetNativeSet { it }
} }
/** /**
@@ -371,7 +391,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
* @return [Float] * @return [Float]
*/ */
fun getFloat(key: String, value: Float = 0f) = fun getFloat(key: String, value: Float = 0f) =
(if (isXposedEnvironment) (if (isXposedEnvironment && isUsingNativeStorage.not())
if (isUsingKeyValueCache) if (isUsingKeyValueCache)
XSharedPreferencesCaches.floatData[key].let { XSharedPreferencesCaches.floatData[key].let {
it ?: currentXsp.getFloat(key, value).let { value -> 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 resetCacheSet { currentXsp.getFloat(key, value) }
else currentSp.getFloat(key, value)).let { else currentSp.getFloat(key, value)).let {
makeWorldReadable() makeWorldReadable()
it resetNativeSet { it }
} }
/** /**
@@ -396,7 +416,7 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
* @return [Long] * @return [Long]
*/ */
fun getLong(key: String, value: Long = 0L) = fun getLong(key: String, value: Long = 0L) =
(if (isXposedEnvironment) (if (isXposedEnvironment && isUsingNativeStorage.not())
if (isUsingKeyValueCache) if (isUsingKeyValueCache)
XSharedPreferencesCaches.longData[key].let { XSharedPreferencesCaches.longData[key].let {
it ?: currentXsp.getLong(key, value).let { value -> 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 resetCacheSet { currentXsp.getLong(key, value) }
else currentSp.getLong(key, value)).let { else currentSp.getLong(key, value)).let {
makeWorldReadable() makeWorldReadable()
it resetNativeSet { it }
} }
/** /**
@@ -617,12 +637,22 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
* @return [T] * @return [T]
*/ */
private inline fun <T> resetCacheSet(result: () -> T): T { private inline fun <T> resetCacheSet(result: () -> T): T {
isUsingKeyValueCache = YukiHookAPI.Configs.isEnableModulePrefsCache isUsingKeyValueCache = YukiHookAPI.Configs.isEnablePrefsBridgeCache
return result() return result()
} }
/** /**
* [YukiHookModulePrefs] 的存储代理类 * 恢复 [isUsingNativeStorage] 为默认状态
* @param result 回调方法体的结果
* @return [T]
*/
private inline fun <T> resetNativeSet(result: () -> T): T {
isUsingNativeStorage = false
return result()
}
/**
* [YukiHookPrefsBridge] 的存储代理类
* *
* - 请使用 [edit] 方法来获取 [Editor] * - 请使用 [edit] 方法来获取 [Editor]
* *
@@ -770,10 +800,10 @@ class YukiHookModulePrefs private constructor(private var context: Context? = nu
* 提交更改 (同步) * 提交更改 (同步)
* @return [Boolean] 是否成功 * @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] * @return [Editor]
*/ */
private inline fun moduleEnvironment(callback: () -> Unit): Editor { private inline fun moduleEnvironment(callback: () -> Unit): Editor {
if (isXposedEnvironment.not()) callback() if (isXposedEnvironment.not() || isUsingNativeStorage) callback()
else yLoggerW(msg = "YukiHookModulePrefs.Editor not allowed in Xposed Environment") else yLoggerW(msg = "YukiHookPrefsBridge.Editor not allowed in Xposed Environment")
return this return this
} }
} }

View File

@@ -27,13 +27,13 @@
*/ */
package com.highcapable.yukihookapi.hook.xposed.prefs.data 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 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) * 详情请参考 [API 文档 - PrefsData](https://fankes.github.io/YukiHookAPI/zh-cn/api/public/com/highcapable/yukihookapi/hook/xposed/prefs/data/PrefsData)
* *

View File

@@ -38,7 +38,7 @@ import androidx.preference.PreferenceManager
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import com.highcapable.yukihookapi.YukiHookAPI import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.utils.unit 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 模块实现中的一个扩展功能 * 这是对使用 [YukiHookAPI] Xposed 模块实现中的一个扩展功能
@@ -105,5 +105,5 @@ abstract class ModulePreferenceFragment : PreferenceFragmentCompat(), SharedPref
private fun makeNewXShareReadableIfPossible() = runCatching { private fun makeNewXShareReadableIfPossible() = runCatching {
@Suppress("DEPRECATION", "WorldReadableFiles") @Suppress("DEPRECATION", "WorldReadableFiles")
currentActivity.getSharedPreferences(prefsName, Context.MODE_WORLD_READABLE) currentActivity.getSharedPreferences(prefsName, Context.MODE_WORLD_READABLE)
}.onFailure { YukiHookModulePrefs.makeWorldReadable(currentActivity, prefsFileName = "$prefsName.xml") }.unit() }.onFailure { YukiHookPrefsBridge.makeWorldReadable(currentActivity, prefsFileName = "$prefsName.xml") }.unit()
} }