Added new "PrefsData" function

This commit is contained in:
2022-03-27 12:31:10 +08:00
parent 5b7f5e0e2a
commit 99b6f041f0
5 changed files with 177 additions and 33 deletions

View File

@@ -0,0 +1,35 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/3/27.
*/
package com.highcapable.yukihookapi.demo_module.data
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
object DataConst {
val TEST_KV_DATA = PrefsData("test_data", "Test data is nothing")
}

View File

@@ -30,6 +30,7 @@ package com.highcapable.yukihookapi.demo_module.hook
import android.app.AlertDialog
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.demo_module.data.DataConst
import com.highcapable.yukihookapi.hook.type.android.BundleClass
import com.highcapable.yukihookapi.hook.type.java.StringType
import com.highcapable.yukihookapi.hook.type.java.UnitType
@@ -121,7 +122,7 @@ class HookEntry : YukiHookXposedInitProxy {
returnType = StringType
}
// 执行替换 Hook
replaceTo(prefs.getString(key = "test_data", default = "Test data is nothing"))
replaceTo(prefs.get(DataConst.TEST_KV_DATA))
}
}
// 得到需要 Hook 的 Class

View File

@@ -36,6 +36,7 @@ import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.highcapable.yukihookapi.demo_module.R
import com.highcapable.yukihookapi.demo_module.data.DataConst
import com.highcapable.yukihookapi.hook.factory.isModuleActive
import com.highcapable.yukihookapi.hook.factory.modulePrefs
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
@@ -49,10 +50,10 @@ class MainActivity : AppCompatActivity() {
"Hook Framework -> ${YukiHookModuleStatus.executorName}\n" +
"API Version -> ${YukiHookModuleStatus.executorVersion}"
findViewById<EditText>(R.id.module_demo_edit_text).also {
it.setText(modulePrefs.getString(key = "test_data"))
it.setText(modulePrefs.get(DataConst.TEST_KV_DATA))
findViewById<Button>(R.id.module_demo_button).setOnClickListener { _ ->
if (it.text.toString().isNotEmpty()) {
modulePrefs.putString(key = "test_data", value = it.text.toString())
modulePrefs.put(DataConst.TEST_KV_DATA, it.text.toString())
Toast.makeText(applicationContext, "Saved", Toast.LENGTH_SHORT).show()
} else Toast.makeText(applicationContext, "Please enter the text", Toast.LENGTH_SHORT).show()
}

View File

@@ -35,6 +35,7 @@ package com.highcapable.yukihookapi.hook.xposed.prefs
import android.content.Context
import android.content.SharedPreferences
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
import de.robv.android.xposed.XSharedPreferences
import java.io.File
@@ -64,19 +65,19 @@ class YukiHookModulePrefs(private val context: Context? = null) {
/** 是否为 Xposed 环境 */
private val isXposedEnvironment = YukiHookAPI.hasXposedBridge
/** 缓存数据 */
/** [XSharedPreferences] 缓存的 [String] 键值数据 */
private var xPrefCacheKeyValueStrings = HashMap<String, String>()
/** 缓存数据 */
/** [XSharedPreferences] 缓存的 [Boolean] 键值数据 */
private var xPrefCacheKeyValueBooleans = HashMap<String, Boolean>()
/** 缓存数据 */
/** [XSharedPreferences] 缓存的 [Int] 键值数据 */
private var xPrefCacheKeyValueInts = HashMap<String, Int>()
/** 缓存数据 */
/** [XSharedPreferences] 缓存的 [Long] 键值数据 */
private var xPrefCacheKeyValueLongs = HashMap<String, Long>()
/** 缓存数据 */
/** [XSharedPreferences] 缓存的 [Float] 键值数据 */
private var xPrefCacheKeyValueFloats = HashMap<String, Float>()
/** 是否使用键值缓存 */
@@ -149,21 +150,23 @@ class YukiHookModulePrefs(private val context: Context? = null) {
* 获取 [String] 键值
*
* - 智能识别对应环境读取键值数据
*
* - 建议使用 [PrefsData] 创建模板并使用 [get] 获取数据
* @param key 键值名称
* @param default 默认数据 - ""
* @param value 默认数据 - ""
* @return [String]
*/
fun getString(key: String, default: String = "") =
fun getString(key: String, value: String = "") =
(if (isXposedEnvironment)
if (isUsingKeyValueCache)
xPrefCacheKeyValueStrings[key].let {
(it ?: xPref.getString(key, default) ?: default).let { value ->
(it ?: xPref.getString(key, value) ?: value).let { value ->
xPrefCacheKeyValueStrings[key] = value
value
}
}
else resetCacheSet { xPref.getString(key, default) ?: default }
else sPref.getString(key, default) ?: default).let {
else resetCacheSet { xPref.getString(key, value) ?: value }
else sPref.getString(key, value) ?: value).let {
makeWorldReadable()
it
}
@@ -172,21 +175,23 @@ class YukiHookModulePrefs(private val context: Context? = null) {
* 获取 [Boolean] 键值
*
* - 智能识别对应环境读取键值数据
*
* - 建议使用 [PrefsData] 创建模板并使用 [get] 获取数据
* @param key 键值名称
* @param default 默认数据 - false
* @param value 默认数据 - false
* @return [Boolean]
*/
fun getBoolean(key: String, default: Boolean = false) =
fun getBoolean(key: String, value: Boolean = false) =
(if (isXposedEnvironment)
if (isUsingKeyValueCache)
xPrefCacheKeyValueBooleans[key].let {
it ?: xPref.getBoolean(key, default).let { value ->
it ?: xPref.getBoolean(key, value).let { value ->
xPrefCacheKeyValueBooleans[key] = value
value
}
}
else resetCacheSet { xPref.getBoolean(key, default) }
else sPref.getBoolean(key, default)).let {
else resetCacheSet { xPref.getBoolean(key, value) }
else sPref.getBoolean(key, value)).let {
makeWorldReadable()
it
}
@@ -195,21 +200,23 @@ class YukiHookModulePrefs(private val context: Context? = null) {
* 获取 [Int] 键值
*
* - 智能识别对应环境读取键值数据
*
* - 建议使用 [PrefsData] 创建模板并使用 [get] 获取数据
* @param key 键值名称
* @param default 默认数据 - 0
* @param value 默认数据 - 0
* @return [Int]
*/
fun getInt(key: String, default: Int = 0) =
fun getInt(key: String, value: Int = 0) =
(if (isXposedEnvironment)
if (isUsingKeyValueCache)
xPrefCacheKeyValueInts[key].let {
it ?: xPref.getInt(key, default).let { value ->
it ?: xPref.getInt(key, value).let { value ->
xPrefCacheKeyValueInts[key] = value
value
}
}
else resetCacheSet { xPref.getInt(key, default) }
else sPref.getInt(key, default)).let {
else resetCacheSet { xPref.getInt(key, value) }
else sPref.getInt(key, value)).let {
makeWorldReadable()
it
}
@@ -218,21 +225,23 @@ class YukiHookModulePrefs(private val context: Context? = null) {
* 获取 [Float] 键值
*
* - 智能识别对应环境读取键值数据
*
* - 建议使用 [PrefsData] 创建模板并使用 [get] 获取数据
* @param key 键值名称
* @param default 默认数据 - 0f
* @param value 默认数据 - 0f
* @return [Float]
*/
fun getFloat(key: String, default: Float = 0f) =
fun getFloat(key: String, value: Float = 0f) =
(if (isXposedEnvironment)
if (isUsingKeyValueCache)
xPrefCacheKeyValueFloats[key].let {
it ?: xPref.getFloat(key, default).let { value ->
it ?: xPref.getFloat(key, value).let { value ->
xPrefCacheKeyValueFloats[key] = value
value
}
}
else resetCacheSet { xPref.getFloat(key, default) }
else sPref.getFloat(key, default)).let {
else resetCacheSet { xPref.getFloat(key, value) }
else sPref.getFloat(key, value)).let {
makeWorldReadable()
it
}
@@ -241,21 +250,23 @@ class YukiHookModulePrefs(private val context: Context? = null) {
* 获取 [Long] 键值
*
* - 智能识别对应环境读取键值数据
*
* - 建议使用 [PrefsData] 创建模板并使用 [get] 获取数据
* @param key 键值名称
* @param default 默认数据 - 0L
* @param value 默认数据 - 0L
* @return [Long]
*/
fun getLong(key: String, default: Long = 0L) =
fun getLong(key: String, value: Long = 0L) =
(if (isXposedEnvironment)
if (isUsingKeyValueCache)
xPrefCacheKeyValueLongs[key].let {
it ?: xPref.getLong(key, default).let { value ->
it ?: xPref.getLong(key, value).let { value ->
xPrefCacheKeyValueLongs[key] = value
value
}
}
else resetCacheSet { xPref.getLong(key, default) }
else sPref.getLong(key, default)).let {
else resetCacheSet { xPref.getLong(key, value) }
else sPref.getLong(key, value)).let {
makeWorldReadable()
it
}
@@ -274,9 +285,21 @@ class YukiHookModulePrefs(private val context: Context? = null) {
makeWorldReadable()
}
/**
* 移除 [PrefsData.key] 的存储数据
*
* - 在模块 [Context] 环境中使用
*
* - ❗在 [XSharedPreferences] 环境下只读 - 无法使用
* @param prefs 键值实例
*/
inline fun <reified T> remove(prefs: PrefsData<T>) = remove(prefs.key)
/**
* 存储 [String] 键值
*
* - 建议使用 [PrefsData] 创建模板并使用 [put] 存储数据
*
* - 在模块 [Context] 环境中使用
*
* - ❗在 [XSharedPreferences] 环境下只读 - 无法使用
@@ -292,6 +315,8 @@ class YukiHookModulePrefs(private val context: Context? = null) {
/**
* 存储 [Boolean] 键值
*
* - 建议使用 [PrefsData] 创建模板并使用 [put] 存储数据
*
* - 在模块 [Context] 环境中使用
*
* - ❗在 [XSharedPreferences] 环境下只读 - 无法使用
@@ -307,6 +332,8 @@ class YukiHookModulePrefs(private val context: Context? = null) {
/**
* 存储 [Int] 键值
*
* - 建议使用 [PrefsData] 创建模板并使用 [put] 存储数据
*
* - 在模块 [Context] 环境中使用
*
* - ❗在 [XSharedPreferences] 环境下只读 - 无法使用
@@ -322,6 +349,8 @@ class YukiHookModulePrefs(private val context: Context? = null) {
/**
* 存储 [Float] 键值
*
* - 建议使用 [PrefsData] 创建模板并使用 [put] 存储数据
*
* - 在模块 [Context] 环境中使用
*
* - ❗在 [XSharedPreferences] 环境下只读 - 无法使用
@@ -337,6 +366,8 @@ class YukiHookModulePrefs(private val context: Context? = null) {
/**
* 存储 [Long] 键值
*
* - 建议使用 [PrefsData] 创建模板并使用 [put] 存储数据
*
* - 在模块 [Context] 环境中使用
*
* - ❗在 [XSharedPreferences] 环境下只读 - 无法使用
@@ -350,6 +381,41 @@ class YukiHookModulePrefs(private val context: Context? = null) {
}
/**
* 智能获取指定类型的键值
* @param prefs 键值实例
* @param value 默认值 - 未指定默认为 [prefs] 中的 [PrefsData.value]
* @return [T] 只能是 [String]、[Int]、[Float]、[Long]、[Boolean]
*/
inline fun <reified T> get(prefs: PrefsData<T>, value: T = prefs.value): T = when (prefs.value) {
is String -> getString(prefs.key, value as String) as T
is Int -> getInt(prefs.key, value as Int) as T
is Float -> getFloat(prefs.key, value as Float) as T
is Long -> getLong(prefs.key, value as Long) as T
is Boolean -> getBoolean(prefs.key, value as Boolean) as T
else -> error("Key-Value type ${T::class.java.name} is not allowed")
}
/**
* 智能存储指定类型的键值
*
* - 在模块 [Context] 环境中使用
*
* - ❗在 [XSharedPreferences] 环境下只读 - 无法使用
* @param prefs 键值实例
* @param value 要存储的值 - 只能是 [String]、[Int]、[Float]、[Long]、[Boolean]
*/
inline fun <reified T> put(prefs: PrefsData<T>, value: T) = when (prefs.value) {
is String -> putString(prefs.key, value as String)
is Int -> putInt(prefs.key, value as Int)
is Float -> putFloat(prefs.key, value as Float)
is Long -> putLong(prefs.key, value as Long)
is Boolean -> putBoolean(prefs.key, value as Boolean)
else -> error("Key-Value type ${T::class.java.name} is not allowed")
}
/**
* 清除 [XSharedPreferences] 中缓存的键值数据
*
* 无论是否开启 [YukiHookAPI.Configs.isEnableModulePrefsCache]
*
* 调用此方法将清除当前存储的全部键值缓存

View File

@@ -0,0 +1,41 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/3/27.
*/
package com.highcapable.yukihookapi.hook.xposed.prefs.data
import com.highcapable.yukihookapi.hook.xposed.prefs.YukiHookModulePrefs
/**
* 键值对存储构造类
*
* 这个类是对 [YukiHookModulePrefs] 的一个扩展用法
*
* - 详情请参考 [API 文档 - PrefsData](https://github.com/fankes/YukiHookAPI/wiki/API-%E6%96%87%E6%A1%A3#prefsdata-class)
* @param key 键值
* @param value 默认值
*/
data class PrefsData<T>(var key: String, var value: T)