diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/MXKeyValue.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/MXKeyValue.kt index d137814392330c6bd270ca2b70d896ce621725ad..cd4451df50cd719731828562590497bbf4f717bb 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/MXKeyValue.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/MXKeyValue.kt @@ -1,37 +1,51 @@ package com.mx.keyvalue import android.content.Context -import com.mx.keyvalue.secret.IMXCrypt -import com.mx.keyvalue.secret.MXNoCrypt +import com.mx.keyvalue.crypt.IKVCrypt +import com.mx.keyvalue.crypt.KVNoCrypt import com.mx.keyvalue.store.IKVStore -import com.mx.keyvalue.store.sqlite.MXSqliteStore -import com.mx.keyvalue.utils.MXKVObservable -import com.mx.keyvalue.utils.MXKVObserver -import com.mx.keyvalue.utils.MXUtils - -class MXKeyValue( - private val context: Context, - private val name: String, - private val crypt: IMXCrypt = MXNoCrypt() -) { +import com.mx.keyvalue.store.sqlite.KVSqliteStore +import com.mx.keyvalue.utils.KVObservable +import com.mx.keyvalue.utils.KVObserver +import com.mx.keyvalue.utils.KVUtils + +class MXKeyValue private constructor(private val context: Context, private val store: IKVStore) { companion object { fun setDebug(debug: Boolean) { - MXUtils.setDebug(debug) + KVUtils.setDebug(debug) } } - private val observerSet = HashMap() - private val ikvStore: IKVStore by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { - MXSqliteStore(context.applicationContext, name.trim(), crypt) - } + class MXKVBuilder { + private var crypt: IKVCrypt? = null + private var store: IKVStore? = null + + fun setCrypt(crypt: IKVCrypt): MXKVBuilder { + this.crypt = crypt + return this + } + + fun setStore(store: IKVStore): MXKVBuilder { + this.store = store + return this + } + + @Throws(exceptionClasses = [Exception::class]) + fun build(context: Context, name: String): MXKeyValue { + val crypt = crypt ?: KVNoCrypt() + if (!KVUtils.validate(crypt)) {// 验证crypt 工具类解密正确性 + throw Exception("${crypt::class.java.simpleName} ---> IMXSecret Class validate error.") + } - init { - if (!crypt.validate()) { - // 验证Secret 工具类解密正确性 - throw Exception("${crypt::class.java.simpleName} ---> IMXSecret Class validate error.") + val store = store ?: KVSqliteStore() + store.create(context, name, crypt) + + return MXKeyValue(context, store) } } + private val observerSet = HashMap() + /** * 从SharedPreferences拷贝数据 */ @@ -40,7 +54,7 @@ class MXKeyValue( for (entry in sp.all) { val value = entry.value?.toString() if (value != null) { - ikvStore.set(entry.key, value, null) + store.set(entry.key, value, null) } } } @@ -52,9 +66,9 @@ class MXKeyValue( val key_trim = key.trim() if (key_trim.isBlank()) return false val result = if (value != null && value.isNotEmpty()) { - ikvStore.set(key_trim, value, expire_time) + store.set(key_trim, value, expire_time) } else { - ikvStore.delete(key_trim) + store.delete(key_trim) } observerSet[key]?.set(value) return result @@ -66,7 +80,7 @@ class MXKeyValue( fun get(key: String, default: String? = null): String? { val key_trim = key.trim() if (key_trim.isBlank()) return default - return ikvStore.get(key_trim) ?: default + return store.get(key_trim) ?: default } /** @@ -75,45 +89,45 @@ class MXKeyValue( fun delete(key: String): Boolean { val key_trim = key.trim() if (key_trim.isBlank()) return false - val result = ikvStore.delete(key_trim) + val result = store.delete(key_trim) observerSet[key]?.set(null) return result } fun getAll(): Map { - return ikvStore.getAll() + return store.getAll() } /** * 清理过期KV */ fun cleanExpire() { - ikvStore.cleanExpire() + store.cleanExpire() } /** * 清理数据 */ fun cleanAll(): Boolean { - return ikvStore.cleanAll() + return store.cleanAll() } - fun addKeyObserver(key: String, observer: MXKVObserver) { + fun addKeyObserver(key: String, observer: KVObserver) { var observable = observerSet[key] if (observable == null) { - observable = MXKVObservable(key, get(key)) + observable = KVObservable(key, get(key)) observerSet[key] = observable } observable.addObserver(observer) } - fun removeKeyObserver(key: String, observer: MXKVObserver) { + fun removeKeyObserver(key: String, observer: KVObserver) { val observable = observerSet[key] ?: return observable.deleteObserver(observer) } fun release() { observerSet.clear() - ikvStore.release() + store.release() } } \ No newline at end of file diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/secret/IMXCrypt.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/crypt/IKVCrypt.kt similarity index 32% rename from LibKeyValue/src/main/java/com/mx/keyvalue/secret/IMXCrypt.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/crypt/IKVCrypt.kt index 9366131cfe8d0044262cae154004bdd033440c3f..84111bf282af936e152da0bd7baa7de4d171256b 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/secret/IMXCrypt.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/crypt/IKVCrypt.kt @@ -1,9 +1,6 @@ -package com.mx.keyvalue.secret +package com.mx.keyvalue.crypt -import com.mx.keyvalue.utils.MXUtils -import java.util.* - -interface IMXCrypt { +interface IKVCrypt { /** * 生成随机密码 */ @@ -20,22 +17,4 @@ interface IMXCrypt { * @param key 对应的Key */ fun decrypt(key: String, secretValue: String, salt: String): String? - - /** - * 验证当前加密类的正确性 - */ - fun validate(): Boolean { - try { - val key = UUID.randomUUID().toString().replace("-", "") - val value = UUID.randomUUID().toString().replace("-", "") + System.currentTimeMillis() - val salt = generalSalt() - val secretKey = encrypt(key, value, salt)!! - val desValue = decrypt(key, secretKey, salt) - MXUtils.log("IMXSecret validate => $value --- $desValue") - return value == desValue - } catch (e: Exception) { - e.printStackTrace() - } - return false - } } \ No newline at end of file diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/secret/MXAESCrypt.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/crypt/KVAESCrypt.kt similarity index 93% rename from LibKeyValue/src/main/java/com/mx/keyvalue/secret/MXAESCrypt.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/crypt/KVAESCrypt.kt index e18ba5ea91523ce7d6e3e7c18add84cc4fe20d43..fc8606b3096829a6fc31dac7be9d00be6707d1ce 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/secret/MXAESCrypt.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/crypt/KVAESCrypt.kt @@ -1,7 +1,7 @@ -package com.mx.keyvalue.secret +package com.mx.keyvalue.crypt import android.util.Base64 -import com.mx.keyvalue.utils.MXUtils +import com.mx.keyvalue.utils.KVUtils import java.util.* import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec @@ -12,7 +12,7 @@ import kotlin.random.Random * AES对称加密 * @param key 加密用的Key */ -open class MXAESCrypt(private val key: String) : IMXCrypt { +open class KVAESCrypt(private val key: String) : IKVCrypt { companion object { private val salt_key = arrayOf( 65, 110, 123, 56, 3, 115, 73, 29, 108, 117, 98, 47, 93, 10, 71, @@ -54,7 +54,7 @@ open class MXAESCrypt(private val key: String) : IMXCrypt { keys.append(source[i % source.size]) } keys.append(list) - return MXUtils.md5(keys.toString().toByteArray(), 16).toByteArray() + return KVUtils.md5(keys.toString().toByteArray(), 16).toByteArray() } private fun generalMixIv(): ByteArray { @@ -67,7 +67,7 @@ open class MXAESCrypt(private val key: String) : IMXCrypt { keys.append(source[i % source.size]) } keys.append(list) - return MXUtils.md5(keys.toString().toByteArray(), 16).toByteArray() + return KVUtils.md5(keys.toString().toByteArray(), 16).toByteArray() } private val keySpec = SecretKeySpec(generalMixKey(), "AES") @@ -82,7 +82,7 @@ open class MXAESCrypt(private val key: String) : IMXCrypt { } override fun generalSalt(): String { - val length = Random.nextInt(15, 30) + val length = Random.nextInt(25, 30) return UUID.randomUUID().toString().replace("-", "").substring(0, length) } diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/secret/MXNoCrypt.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/crypt/KVNoCrypt.kt similarity index 82% rename from LibKeyValue/src/main/java/com/mx/keyvalue/secret/MXNoCrypt.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/crypt/KVNoCrypt.kt index a597a3aeb34fe3fcd39f81602d47b4e6f4329e10..86044dc28374e5b63acb6a4657657d08c6787ccd 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/secret/MXNoCrypt.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/crypt/KVNoCrypt.kt @@ -1,9 +1,9 @@ -package com.mx.keyvalue.secret +package com.mx.keyvalue.crypt /** * 不加密 */ -open class MXNoCrypt : IMXCrypt { +open class KVNoCrypt : IKVCrypt { override fun generalSalt(): String { return "" } diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXBaseDelegate.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVBaseDelegate.kt similarity index 74% rename from LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXBaseDelegate.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVBaseDelegate.kt index c0d96c36de6e39384ec8172b2bf306b6fb8bd10c..ceaa3fceb5bdedfb398604bfd97aef92fe1e892f 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXBaseDelegate.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVBaseDelegate.kt @@ -3,18 +3,18 @@ package com.mx.keyvalue.delegate import com.mx.keyvalue.MXKeyValue import kotlin.reflect.KProperty -abstract class MXBaseDelegate( +abstract class KVBaseDelegate( protected val kv: MXKeyValue, - protected val name: String, + protected val key: String, protected val default: T ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): T { - val value = kv.get(name) ?: return default + val value = kv.get(key) ?: return default return stringToObject(value) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { - kv.set(name, objectToString(value)) + kv.set(key, objectToString(value)) } abstract fun stringToObject(value: String): T diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXBoolDelegate.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVBoolDelegate.kt similarity index 66% rename from LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXBoolDelegate.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVBoolDelegate.kt index 12cc2e73b115e2ccd1f22964040abf3f9c72ac67..e1670386013c10f57d28a73bee25823b1c7034f5 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXBoolDelegate.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVBoolDelegate.kt @@ -2,8 +2,8 @@ package com.mx.keyvalue.delegate import com.mx.keyvalue.MXKeyValue -open class MXBoolDelegate(kv: MXKeyValue, name: String, default: Boolean = false) : - MXBaseDelegate(kv, name, default) { +open class KVBoolDelegate(kv: MXKeyValue, key: String, default: Boolean = false) : + KVBaseDelegate(kv, key, default) { override fun stringToObject(value: String): Boolean { return value.toBoolean() } diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXDoubleDelegate.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVDoubleDelegate.kt similarity index 67% rename from LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXDoubleDelegate.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVDoubleDelegate.kt index f0d8592011d6bcbb796724ee63c46b386c0d2c46..9fcfaa4820379a0068fef235c752e9912819c4d9 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXDoubleDelegate.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVDoubleDelegate.kt @@ -2,8 +2,8 @@ package com.mx.keyvalue.delegate import com.mx.keyvalue.MXKeyValue -open class MXDoubleDelegate(kv: MXKeyValue, name: String, default: Double = 0.0) : - MXBaseDelegate(kv, name, default) { +open class KVDoubleDelegate(kv: MXKeyValue, key: String, default: Double = 0.0) : + KVBaseDelegate(kv, key, default) { override fun stringToObject(value: String): Double { return value.toDoubleOrNull() ?: default } diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXFloatDelegate.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVFloatDelegate.kt similarity index 68% rename from LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXFloatDelegate.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVFloatDelegate.kt index 07029b127da2ae03d5391011e15bca110896b52a..a4968c2c6887c48cd91ddd72ef0b79b713622eca 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXFloatDelegate.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVFloatDelegate.kt @@ -2,8 +2,8 @@ package com.mx.keyvalue.delegate import com.mx.keyvalue.MXKeyValue -open class MXFloatDelegate(kv: MXKeyValue, name: String, default: Float = 0f) : - MXBaseDelegate(kv, name, default) { +open class KVFloatDelegate(kv: MXKeyValue, key: String, default: Float = 0f) : + KVBaseDelegate(kv, key, default) { override fun stringToObject(value: String): Float { return value.toFloatOrNull() ?: default } diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXIntDelegate.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVIntDelegate.kt similarity index 68% rename from LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXIntDelegate.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVIntDelegate.kt index 017099adf07d55c64ffbfc302f2bcee0f9831f2b..14314c9a810dd3efa48fefc772233f2dc90f7965 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXIntDelegate.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVIntDelegate.kt @@ -2,8 +2,8 @@ package com.mx.keyvalue.delegate import com.mx.keyvalue.MXKeyValue -open class MXIntDelegate(kv: MXKeyValue, name: String, default: Int = 0) : - MXBaseDelegate(kv, name, default) { +open class KVIntDelegate(kv: MXKeyValue, key: String, default: Int = 0) : + KVBaseDelegate(kv, key, default) { override fun stringToObject(value: String): Int { return value.toIntOrNull() ?: default } diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXLongDelegate.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVLongDelegate.kt similarity index 68% rename from LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXLongDelegate.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVLongDelegate.kt index d925662ac28377698371c91f32ab562054fb29c9..484c836737af34631b042c8033307760a774d636 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXLongDelegate.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVLongDelegate.kt @@ -2,8 +2,8 @@ package com.mx.keyvalue.delegate import com.mx.keyvalue.MXKeyValue -open class MXLongDelegate(kv: MXKeyValue, name: String, default: Long = 0) : - MXBaseDelegate(kv, name, default) { +open class KVLongDelegate(kv: MXKeyValue, key: String, default: Long = 0) : + KVBaseDelegate(kv, key, default) { override fun stringToObject(value: String): Long { return value.toLongOrNull() ?: default } diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXStringDelegate.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVStringDelegate.kt similarity index 64% rename from LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXStringDelegate.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVStringDelegate.kt index ce403c90409e459a66823db33bf02afcd887cce4..4ef240ddf7fd99857daecefee4834be43a6eeba6 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/MXStringDelegate.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/delegate/KVStringDelegate.kt @@ -2,8 +2,8 @@ package com.mx.keyvalue.delegate import com.mx.keyvalue.MXKeyValue -open class MXStringDelegate(kv: MXKeyValue, name: String, default: String = "") : - MXBaseDelegate(kv, name, default) { +open class KVStringDelegate(kv: MXKeyValue, key: String, default: String = "") : + KVBaseDelegate(kv, key, default) { override fun stringToObject(value: String): String { return value } diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/store/IKVStore.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/store/IKVStore.kt index 09d4a8b6ec0eb74ab028acc5fde4b59b6d18e6b2..35d4289ff36271c77baed1676393d64f930af38b 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/store/IKVStore.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/store/IKVStore.kt @@ -1,14 +1,53 @@ package com.mx.keyvalue.store -internal interface IKVStore { +import android.content.Context +import com.mx.keyvalue.crypt.IKVCrypt + +interface IKVStore { + /** + * 初始化 + * @param context 上下文,一般需要传入applicationContext + * @param name 存储库名字 + * @param crypt 加密方式 + */ + fun create(context: Context, name: String, crypt: IKVCrypt) + + /** + * 获取Value + */ fun get(key: String): String? + + /** + * 设置Value + * @param key 键 + * @param value 值 + * @param dead_time 过期时间,超过这个时间后读取Key会返回 NULL + */ fun set(key: String, value: String, dead_time: Long?): Boolean + + /** + * 删除键值对 + * @param key 键 + */ fun delete(key: String): Boolean + /** + * 获取所有键值对 + */ fun getAll(): Map + /** + * 清理所有超时的键值对 + */ fun cleanExpire(): Boolean + + /** + * 删除所有数据 + */ fun cleanAll(): Boolean + /** + * 释放资源 + */ fun release() } \ No newline at end of file diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/MXSQLiteHelper.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/KVSQLiteHelper.kt similarity index 88% rename from LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/MXSQLiteHelper.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/KVSQLiteHelper.kt index 0cd248635f7611d3b37a462006068a2200e8c06d..609358519c5ca51e394af0f3bfcded5d2a4372b2 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/MXSQLiteHelper.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/KVSQLiteHelper.kt @@ -4,8 +4,8 @@ import android.content.Context import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper -internal class MXSQLiteHelper(context: Context, dbName: String) : - SQLiteOpenHelper(context, dbName, null, 4) { +internal class KVSQLiteHelper(context: Context, dbName: String) : + SQLiteOpenHelper(context.applicationContext, dbName, null, 4) { companion object { const val DB_KEY_NAME = "kv_name" const val DB_KEY_VALUE = "kv_value" diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/MXSqliteStore.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/KVSqliteStore.kt similarity index 69% rename from LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/MXSqliteStore.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/KVSqliteStore.kt index 76874e56e01af901d5d113a1e812c0f1b8ba2ede..4cfcd7eccba2289b425f0de0e7572880b37dde54 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/MXSqliteStore.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/store/sqlite/KVSqliteStore.kt @@ -5,46 +5,57 @@ import android.content.Context import android.database.Cursor import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper -import com.mx.keyvalue.secret.IMXCrypt +import com.mx.keyvalue.crypt.IKVCrypt +import com.mx.keyvalue.crypt.KVNoCrypt import com.mx.keyvalue.store.IKVStore -import com.mx.keyvalue.utils.MXUtils +import com.mx.keyvalue.utils.KVUtils import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.read import kotlin.concurrent.write -internal class MXSqliteStore( - private val context: Context, - private val dbName: String, - private val crypt: IMXCrypt -) : IKVStore { +/** + * sqlite实现的存储 + */ +class KVSqliteStore : IKVStore { private val lock = ReentrantReadWriteLock(true) + private var context: Context? = null + private var name: String = "" + private var crypt: IKVCrypt = KVNoCrypt() private var sqliteHelper: SQLiteOpenHelper? = null private fun getDatabase(): SQLiteDatabase { if (sqliteHelper == null) { synchronized(this) { if (sqliteHelper == null) { - sqliteHelper = MXSQLiteHelper(context, dbName) + sqliteHelper = KVSQLiteHelper(context!!, name) } } } return sqliteHelper!!.writableDatabase } + override fun create(context: Context, name: String, crypt: IKVCrypt) { + this.context = context + this.name = name + this.crypt = crypt + + this.sqliteHelper = KVSQLiteHelper(context, name) + } + override fun get(key: String): String? { lock.read { var cursor: Cursor? = null try { val database = getDatabase() cursor = database.query( - dbName, + name, arrayOf( - MXSQLiteHelper.DB_KEY_NAME, - MXSQLiteHelper.DB_KEY_VALUE, - MXSQLiteHelper.DB_KEY_SALT, - MXSQLiteHelper.DB_KEY_DEAD_TIME + KVSQLiteHelper.DB_KEY_NAME, + KVSQLiteHelper.DB_KEY_VALUE, + KVSQLiteHelper.DB_KEY_SALT, + KVSQLiteHelper.DB_KEY_DEAD_TIME ), - "${MXSQLiteHelper.DB_KEY_NAME}=?", + "${KVSQLiteHelper.DB_KEY_NAME}=?", arrayOf(key), null, null, @@ -58,7 +69,7 @@ internal class MXSqliteStore( } } catch (e: Exception) { e.printStackTrace() - MXUtils.log("get错误 -> $key -- ${e.message}") + KVUtils.log("get错误 -> $key -- ${e.message}") } finally { try { cursor?.close() @@ -78,17 +89,17 @@ internal class MXSqliteStore( val value_encrypt = crypt.encrypt(key, value, salt) val values = ContentValues() - values.put(MXSQLiteHelper.DB_KEY_NAME, key) - values.put(MXSQLiteHelper.DB_KEY_VALUE, value_encrypt) - values.put(MXSQLiteHelper.DB_KEY_SALT, salt) - values.put(MXSQLiteHelper.DB_KEY_UPDATE_TIME, System.currentTimeMillis()) - values.put(MXSQLiteHelper.DB_KEY_DEAD_TIME, dead_time ?: 0L) - val result = database.replace(dbName, null, values) >= 0 + values.put(KVSQLiteHelper.DB_KEY_NAME, key) + values.put(KVSQLiteHelper.DB_KEY_VALUE, value_encrypt) + values.put(KVSQLiteHelper.DB_KEY_SALT, salt) + values.put(KVSQLiteHelper.DB_KEY_UPDATE_TIME, System.currentTimeMillis()) + values.put(KVSQLiteHelper.DB_KEY_DEAD_TIME, dead_time ?: 0L) + val result = database.replace(name, null, values) >= 0 database.setTransactionSuccessful() return result } catch (e: Exception) { e.printStackTrace() - MXUtils.log("set错误 -> $key = $value ; $dead_time -- ${e.message}") + KVUtils.log("set错误 -> $key = $value ; $dead_time -- ${e.message}") } finally { database.endTransaction() } @@ -102,15 +113,15 @@ internal class MXSqliteStore( try { database.beginTransaction() val result = database.delete( - dbName, - "${MXSQLiteHelper.DB_KEY_NAME}=?", + name, + "${KVSQLiteHelper.DB_KEY_NAME}=?", arrayOf(key) ) > 0 database.setTransactionSuccessful() return result } catch (e: Exception) { e.printStackTrace() - MXUtils.log("delete错误 -> $key -- ${e.message}") + KVUtils.log("delete错误 -> $key -- ${e.message}") } finally { database.endTransaction() } @@ -125,12 +136,12 @@ internal class MXSqliteStore( var cursor: Cursor? = null try { cursor = database.query( - dbName, + name, arrayOf( - MXSQLiteHelper.DB_KEY_NAME, - MXSQLiteHelper.DB_KEY_VALUE, - MXSQLiteHelper.DB_KEY_SALT, - MXSQLiteHelper.DB_KEY_DEAD_TIME + KVSQLiteHelper.DB_KEY_NAME, + KVSQLiteHelper.DB_KEY_VALUE, + KVSQLiteHelper.DB_KEY_SALT, + KVSQLiteHelper.DB_KEY_DEAD_TIME ), null, null, null, null, null ) while (cursor.moveToNext()) { @@ -141,7 +152,7 @@ internal class MXSqliteStore( } } catch (e: Exception) { e.printStackTrace() - MXUtils.log("getAll错误 -> ${e.message}") + KVUtils.log("getAll错误 -> ${e.message}") } finally { try { cursor?.close() @@ -158,15 +169,15 @@ internal class MXSqliteStore( try { database.beginTransaction() val result = database.delete( - dbName, - "${MXSQLiteHelper.DB_KEY_DEAD_TIME}>0 and ${MXSQLiteHelper.DB_KEY_DEAD_TIME}0 and ${KVSQLiteHelper.DB_KEY_DEAD_TIME} 0 database.setTransactionSuccessful() return result } catch (e: Exception) { e.printStackTrace() - MXUtils.log("cleanExpire错误 -> ${e.message}") + KVUtils.log("cleanExpire错误 -> ${e.message}") } finally { database.endTransaction() } @@ -179,12 +190,12 @@ internal class MXSqliteStore( val database = getDatabase() try { database.beginTransaction() - val result = database.delete(dbName, null, null) > 0 + val result = database.delete(name, null, null) > 0 database.setTransactionSuccessful() return result } catch (e: Exception) { e.printStackTrace() - MXUtils.log("cleanAll错误 -> ${e.message}") + KVUtils.log("cleanAll错误 -> ${e.message}") } finally { database.endTransaction() } @@ -195,16 +206,16 @@ internal class MXSqliteStore( private fun cursorToEntry(cursor: Cursor): Pair? { try { val key = cursor.getString( - cursor.getColumnIndexOrThrow(MXSQLiteHelper.DB_KEY_NAME) + cursor.getColumnIndexOrThrow(KVSQLiteHelper.DB_KEY_NAME) ) var value = cursor.getString( - cursor.getColumnIndexOrThrow(MXSQLiteHelper.DB_KEY_VALUE) + cursor.getColumnIndexOrThrow(KVSQLiteHelper.DB_KEY_VALUE) ) val salt = cursor.getString( - cursor.getColumnIndexOrThrow(MXSQLiteHelper.DB_KEY_SALT) + cursor.getColumnIndexOrThrow(KVSQLiteHelper.DB_KEY_SALT) ) val dead_time = cursor.getLong( - cursor.getColumnIndexOrThrow(MXSQLiteHelper.DB_KEY_DEAD_TIME) + cursor.getColumnIndexOrThrow(KVSQLiteHelper.DB_KEY_DEAD_TIME) ) if (dead_time > 0 && dead_time < System.currentTimeMillis()) { return null diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/utils/MXKVObservable.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/utils/KVObservable.kt similarity index 84% rename from LibKeyValue/src/main/java/com/mx/keyvalue/utils/MXKVObservable.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/utils/KVObservable.kt index 8f339a52836f0fe4b05d2cf758185aeae0f29a64..faadff86689d601953a666e1baa8babd70fe5cbe 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/utils/MXKVObservable.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/utils/KVObservable.kt @@ -3,10 +3,10 @@ package com.mx.keyvalue.utils import android.os.Handler import android.os.Looper -internal class MXKVObservable(val key: String, defaultValue: String?) { +internal class KVObservable(val key: String, defaultValue: String?) { private val mHandler = Handler(Looper.getMainLooper()) private val lock = Object() - private val observerList = HashSet() + private val observerList = HashSet() private var _value: String? = defaultValue @@ -30,7 +30,7 @@ internal class MXKVObservable(val key: String, defaultValue: String?) { fun get() = _value - fun addObserver(o: MXKVObserver?) { + fun addObserver(o: KVObserver?) { o ?: return synchronized(lock) { observerList.add(o) @@ -38,7 +38,7 @@ internal class MXKVObservable(val key: String, defaultValue: String?) { mHandler.post { o.onChange(key, _value) } } - fun deleteObserver(o: MXKVObserver?) { + fun deleteObserver(o: KVObserver?) { o ?: return synchronized(lock) { observerList.remove(o) diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/utils/MXKVObserver.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/utils/KVObserver.kt similarity index 75% rename from LibKeyValue/src/main/java/com/mx/keyvalue/utils/MXKVObserver.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/utils/KVObserver.kt index 55936e8330bb358149557df6e396b4aa1aa5eecb..392c5bfb42851d7b0562cb7946dbdf53fc131fd8 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/utils/MXKVObserver.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/utils/KVObserver.kt @@ -1,5 +1,5 @@ package com.mx.keyvalue.utils -interface MXKVObserver { +interface KVObserver { fun onChange(key: String, value: String?) } \ No newline at end of file diff --git a/LibKeyValue/src/main/java/com/mx/keyvalue/utils/MXUtils.kt b/LibKeyValue/src/main/java/com/mx/keyvalue/utils/KVUtils.kt similarity index 52% rename from LibKeyValue/src/main/java/com/mx/keyvalue/utils/MXUtils.kt rename to LibKeyValue/src/main/java/com/mx/keyvalue/utils/KVUtils.kt index b838d51978c3471414b9610be137fab7e1158d4d..5c54106fc588cda9a78c7121bfcd78c530a0a82c 100644 --- a/LibKeyValue/src/main/java/com/mx/keyvalue/utils/MXUtils.kt +++ b/LibKeyValue/src/main/java/com/mx/keyvalue/utils/KVUtils.kt @@ -1,9 +1,11 @@ package com.mx.keyvalue.utils import com.mx.keyvalue.BuildConfig +import com.mx.keyvalue.crypt.IKVCrypt import java.security.MessageDigest +import java.util.* -internal object MXUtils { +internal object KVUtils { private var debug = BuildConfig.DEBUG fun setDebug(debug: Boolean) { this.debug = debug @@ -27,4 +29,19 @@ internal object MXUtils { } return builder.toString().substring(0, size).lowercase() } + + fun validate(crypt: IKVCrypt): Boolean { + try { + val key = UUID.randomUUID().toString().replace("-", "") + val value = UUID.randomUUID().toString().replace("-", "") + System.currentTimeMillis() + val salt = crypt.generalSalt() + val secretKey = crypt.encrypt(key, value, salt)!! + val desValue = crypt.decrypt(key, secretKey, salt) + log("IMXSecret validate => $value --- $desValue") + return value == desValue + } catch (e: Exception) { + e.printStackTrace() + } + return false + } } \ No newline at end of file diff --git a/README.md b/README.md index 8623da21037c19142b1b24d8eb3dc2fcf94e2382..449e76ec3e9978a5345209bbc6e6dec976df420e 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,18 @@ ## 介绍 基于Sqlite的,支持加密、自定义加密方式的KV数据库 [![](https://jitpack.io/v/com.gitee.zhangmengxiong/MXKeyValue.svg)](https://jitpack.io/#com.gitee.zhangmengxiong/MXKeyValue) -库引用: 替换1.0.9 为最新版本 +库引用: 替换1.1.1 为最新版本 ```gradle - implementation 'com.gitee.zhangmengxiong:MXKeyValue:1.0.9' + implementation 'com.gitee.zhangmengxiong:MXKeyValue:1.1.1' ``` ## 使用方法 ```kotlin -val KV = MXKeyValue( - application, // context - name = "mx_kv_test", // 存储数据库名称 - secret = MXNoCrypt() // 加密方式 -) +val KV = MXKeyValue.MXKVBuilder() + .setCrypt(KVAESCrypt("27e2125d0a11a9aa65b9c9773673bc2a")) + .setStore(KVSqliteStore()) + .build(MyApp.appContext, "kvdb_kv_v1") // 清理所有KV KV.cleanAll() @@ -46,18 +45,18 @@ KV.cloneFromSharedPreferences("sp_name") ## 加密相关 MXKeyValue内置两种加密方式: -- MXNoCrypt() -- MXAESCrypt("加密字符") +- KVNoCrypt() +- KVAESCrypt("加密字符") ### MXNoSecret -MXNoCrypt = 不加密,存储Value=设置的Value +KVNoCrypt = 不加密,存储Value=设置的Value ### MXAESSecret -MXAESCrypt = AES对称加密 +KVAESCrypt = AES对称加密 - 存储的value=encrypt(设置的Value) - 读取的Value=decrypt(存储的Value) -注意:MXAESSecret初始化的加密字符在app上线后不能修改,否则会导致数据读取错误! +注意:KVAESCrypt初始化的加密字符在app上线后不能修改,否则会导致数据读取错误! ### 自定义加密方式 - 需要实现IMXCrypt接口 @@ -65,7 +64,7 @@ MXAESCrypt = AES对称加密 - encrypt方法 = 源数据Value->存储Value - decrypt方法 = 存储Value->源数据Value ```kotlin -class MyCrypt : IMXCrypt { +class MyCrypt : IKVCrypt { private val divider = "$$$$$$$$$$$$" override fun generalSalt(): String { return UUID.randomUUID().toString().replace("-", "") @@ -82,9 +81,8 @@ class MyCrypt : IMXCrypt { ``` 使用方法: ```kotlin -val KV = MXKeyValue( - application, - name = "mx_kv_test", - secret = MyCrypt() // 加密方式 -) +val KV = MXKeyValue.MXKVBuilder() + .setCrypt(MyCrypt()) + .setStore(KVSqliteStore()) + .build(MyApp.appContext, "kvdb_kv_v1") ``` \ No newline at end of file diff --git a/app/src/main/java/com/mx/example/app/DelegateTestActivity.kt b/app/src/main/java/com/mx/example/app/DelegateTestActivity.kt index 006c537ff2aadb472660441ba8691101a9692399..07cfdf0b082980a51f22765b454af43cbf4068f2 100644 --- a/app/src/main/java/com/mx/example/app/DelegateTestActivity.kt +++ b/app/src/main/java/com/mx/example/app/DelegateTestActivity.kt @@ -18,43 +18,43 @@ class DelegateTestActivity : AppCompatActivity() { setContentView(R.layout.activity_delegate_test) testBtn.setOnClickListener { - var boolDelegate by MXBoolDelegate(SPUtils.KV, "bool_test", true) + var boolDelegate by KVBoolDelegate(SPUtils.KV, "bool_test", true) println("测试 MXBoolDelegate -> $boolDelegate") boolDelegate = false println("测试 MXBoolDelegate -> $boolDelegate") - var doubleDelegate by MXDoubleDelegate(SPUtils.KV, "double_test", 1.0) + var doubleDelegate by KVDoubleDelegate(SPUtils.KV, "double_test", 1.0) println("测试 MXDoubleDelegate -> $doubleDelegate") doubleDelegate = 2.0 println("测试 MXDoubleDelegate -> $doubleDelegate") - var floatDelegate by MXFloatDelegate(SPUtils.KV, "float_test", 1f) + var floatDelegate by KVFloatDelegate(SPUtils.KV, "float_test", 1f) println("测试 MXFloatDelegate -> $floatDelegate") floatDelegate = 2f println("测试 MXFloatDelegate -> $floatDelegate") - var intDelegate by MXIntDelegate(SPUtils.KV, "int_test", 1) + var intDelegate by KVIntDelegate(SPUtils.KV, "int_test", 1) println("测试 MXIntDelegate -> $intDelegate") intDelegate = 2 println("测试 MXIntDelegate -> $intDelegate") - var longDelegate by MXLongDelegate(SPUtils.KV, "long_test", 1) + var longDelegate by KVLongDelegate(SPUtils.KV, "long_test", 1) println("测试 MXLongDelegate -> $longDelegate") longDelegate = 2 println("测试 MXLongDelegate -> $longDelegate") - var stringDelegate by MXStringDelegate(SPUtils.KV, "string_test", "testdef") + var stringDelegate by KVStringDelegate(SPUtils.KV, "string_test", "testdef") println("测试 MXStringDelegate -> $stringDelegate") stringDelegate = "2" println("测试 MXStringDelegate -> $stringDelegate") - var beanDelegate by MXBeanDelegate( + var beanDelegate by KVBeanDelegate( SPUtils.KV, TestBean::class.java, "bean_test", @@ -70,12 +70,12 @@ class DelegateTestActivity : AppCompatActivity() { @JsonIgnoreProperties(ignoreUnknown = true) data class TestBean constructor(val id: String, val name: String) - class MXBeanDelegate( + class KVBeanDelegate( kv: MXKeyValue, private val clazz: Class, name: String, default: T - ) : MXBaseDelegate(kv, name, default) { + ) : KVBaseDelegate(kv, name, default) { override fun stringToObject(value: String): T { try { val mapper = ObjectMapper() diff --git a/app/src/main/java/com/mx/example/app/MainActivity.kt b/app/src/main/java/com/mx/example/app/MainActivity.kt index 4c29fecf5a88b6c02027f3837b16429c17a9894f..4ae376e2796af18dc5aeebbef54b655243180169 100644 --- a/app/src/main/java/com/mx/example/app/MainActivity.kt +++ b/app/src/main/java/com/mx/example/app/MainActivity.kt @@ -2,20 +2,9 @@ package com.mx.example.app import android.content.Intent import android.os.Bundle -import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import com.fasterxml.jackson.annotation.JsonIgnoreProperties -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.registerKotlinModule import com.mx.example.R -import com.mx.example.utils.SPUtils -import com.mx.keyvalue.MXKeyValue -import com.mx.keyvalue.delegate.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.StringBuilder -import java.util.concurrent.TimeUnit -import kotlin.concurrent.thread -import kotlin.random.Random class MainActivity : AppCompatActivity() { diff --git a/app/src/main/java/com/mx/example/app/MultThreadTestActivity.kt b/app/src/main/java/com/mx/example/app/MultThreadTestActivity.kt index 76cd369593b63850889d90dc023880c2ff04d9f3..965914b4e8f528b9362cfac7ec9e151e3c59e6bb 100644 --- a/app/src/main/java/com/mx/example/app/MultThreadTestActivity.kt +++ b/app/src/main/java/com/mx/example/app/MultThreadTestActivity.kt @@ -4,7 +4,6 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.mx.example.R import com.mx.example.utils.SPUtils -import com.mx.example.utils.StringUtils import kotlinx.android.synthetic.main.activity_mult_thread_test.* import kotlin.concurrent.thread import kotlin.random.Random diff --git a/app/src/main/java/com/mx/example/utils/MyCrypt.kt b/app/src/main/java/com/mx/example/utils/MyCrypt.kt index 2a8789c4110e950abf2980e9b71e6ac7c42ef023..1c866f4da747dda195ba76cb5499e1dd668debaa 100644 --- a/app/src/main/java/com/mx/example/utils/MyCrypt.kt +++ b/app/src/main/java/com/mx/example/utils/MyCrypt.kt @@ -1,9 +1,9 @@ package com.mx.example.utils -import com.mx.keyvalue.secret.IMXCrypt +import com.mx.keyvalue.crypt.IKVCrypt import java.util.* -class MyCrypt : IMXCrypt { +class MyCrypt : IKVCrypt { private val divider = "$$$$$$$$$$$$" override fun generalSalt(): String { return UUID.randomUUID().toString().replace("-", "") diff --git a/app/src/main/java/com/mx/example/utils/SPUtils.kt b/app/src/main/java/com/mx/example/utils/SPUtils.kt index 5d03926d952edc0d72eebe63582303ff3735a877..ebe734bd8bcd7508fd293b49b550094c8cadd474 100644 --- a/app/src/main/java/com/mx/example/utils/SPUtils.kt +++ b/app/src/main/java/com/mx/example/utils/SPUtils.kt @@ -4,14 +4,19 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.registerKotlinModule import com.mx.example.MyApp import com.mx.keyvalue.MXKeyValue -import com.mx.keyvalue.delegate.MXBaseDelegate -import com.mx.keyvalue.secret.MXAESCrypt +import com.mx.keyvalue.crypt.KVAESCrypt +import com.mx.keyvalue.delegate.KVBaseDelegate +import com.mx.keyvalue.store.sqlite.KVSqliteStore // 缓存类 object SPUtils { val KV by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { - MXKeyValue(MyApp.appContext, "kvdb_kv_v1", MXAESCrypt("27e2125d0a11a9aa65b9c9773673bc2a")) + MXKeyValue.MXKVBuilder() + .setCrypt(KVAESCrypt("27e2125d0a11a9aa65b9c9773673bc2a")) + .setStore(KVSqliteStore()) + .build(MyApp.appContext, "kvdb_kv_v1") } + fun get(key: String, def: String? = null): String? { return KV.get(key, def) } @@ -28,12 +33,12 @@ object SPUtils { return KV.delete(key) } - class MXBeanDelegate( + class KVBeanDelegate( kv: MXKeyValue, private val clazz: Class, name: String, default: T? - ) : MXBaseDelegate(kv, name, default) { + ) : KVBaseDelegate(kv, name, default) { override fun stringToObject(value: String): T? { try { val mapper = ObjectMapper() diff --git a/app/src/main/java/com/mx/example/utils/StringUtils.kt b/app/src/main/java/com/mx/example/utils/StringUtils.kt index 871b6c7ee045c3ca2bf82b58ce616411b048ee95..5cf876c4895d7530de6219f106c586cee00c863a 100644 --- a/app/src/main/java/com/mx/example/utils/StringUtils.kt +++ b/app/src/main/java/com/mx/example/utils/StringUtils.kt @@ -1,6 +1,5 @@ package com.mx.example.utils -import java.lang.StringBuilder import java.security.MessageDigest import java.util.*