专栏名称: 携程技术
携程技术官方账号,分享交流成长。
目录
相关文章推荐
学长小谭考研  ·  关于「考研博主终将消亡」 ·  昨天  
学长小谭考研  ·  关于「考研博主终将消亡」 ·  昨天  
51好读  ›  专栏  ›  携程技术

开源|携程机票 App KMM 跨端 KV 存储库 MMKV-Kotlin

携程技术  · 公众号  ·  · 2022-06-16 17:52

正文

请到「今天看啥」查看全文


MMKV-Kotlin 的总体设计见下图:


四、实现简介

在《 携程机票 App KMM 跨端生产实践 》(参考链接 1)一文的 2.2 小节中我们曾以 MMKV 作为 demo 来介绍 KMM 的 expect-actual 技术。但本次开源的版本为了代码的健壮性与实用性, 调整了具体的实现方式,本节将会进行详细的探讨。

4.1 初始化函数

2.2 小节演示了 MMKV-Kotlin 的初始化,因此其初始化函数是在 Android、iOS 两个 source set 中分别定义与实现的。

先看看 Android:

import android.content.Context
import com.tencent.mmkv.MMKV

fun initialize(context: Context): String = MMKV.initialize(context)
fun initialize(context: Context, rootDir: String): String = MMKV.initialize(context, rootDir)
fun initialize(context: Context, loader: MMKV.LibLoader): String = MMKV.initialize(context, loader)
fun initialize(context: Context, logLevel: MMKVLogLevel): String = MMKV.initialize(context, logLevel.rawValue)
fun initialize(context: Context, rootDir: String, loader: MMKV.LibLoader): String = MMKV.initialize(context, rootDir, loader)
fun initialize(context: Context, rootDir: String, logLevel: MMKVLogLevel): String = MMKV.initialize(context, rootDir, logLevel.rawValue)
fun initialize(context: Context, loader: MMKV.LibLoader, logLevel: MMKVLogLevel): String = MMKV.initialize(context, loader, logLevel.rawValue)
fun initialize(context: Context, rootDir: String, loader: MMKV.LibLoader, logLevel: MMKVLogLevel): String = MMKV.initialize(context, rootDir, loader, logLevel.rawValue)

初始化函数的实现仅仅是调用 MMKV Java API 中的 initialize 函数。Android 平台的初始化强依赖 Context 类型,还提供了 LibLoader 类型作为参数,用于在初始化时加载 so 库。我们希望尽可能满足 Android 平台的各种需求,因此将 MMKV-Android 中的初始化 API 全部暴露出来。

再看看 iOS:

import cocoapods.MMKV.MMKV

fun initialize() = MMKV.initialize()
fun initialize(rootDir: String): String = MMKV.initializeMMKV(rootDir)
fun initialize(rootDir: String, logLevel: MMKVLogLevel): String = MMKV.initializeMMKV(rootDir, logLevel.rawValue)
fun initialize(rootDir: String, groupDir: String, logLevel: MMKVLogLevel): String = MMKV.initializeMMKV(rootDir, groupDir, logLevel.rawValue)

相比之下 iOS 平台少了 Context 类型与 LibLoader 类型,因此初始化函数的重载要少很多。

4.2 MMKV 类型

在 MMKV 的 Java 与 Objective-C 版本中, MMKV 类型是具体 CRUD 功能的实现类。在 Java 版本中,写函数为一系列 encode 重载函数或统一命名为 putXXX ,其中 putXXX 内部调用了 encode 函数,二者只是返回类型不同,读函数为统一命名为 decodeXXX getXXX 的函数,二者行为一致 。而 Objective-C 版本中,写函数统一命名为 setXXX 函数,读函数统一命名为 getXXX 函数。虽然平台不同,但是具有相同功能的函数的参数数量、类型,以及返回类型都高度统一。因此这给我们定义 common source set 中的 MMKV 类型带来了便利。

我们需要在 common 层声明 MMKV 类型(为避免同名带来的混淆,我们将 common 层的 MMKV 类型命名为 MMKV_KMP ),并且具体实现在各平台的 source set 中, MMKV 类型的实例需要持有 Java 或 Objective-C 的 MMKV 类型的实例,并将 CURD 操作委托给它们。我们的实现方式有两种可选:

  • MMKV_KMP 声明为 class,通过 expect-actual 机制在平台相关层编写其实现。

  • MMKV_KMP 声明为 interface,在平台相关层编写其实现类。

最终我们选择了方案二,原因在于:在平台相关的 source set 中编写的具体实现 class 需要实例化时需要同时构建 Java/Objective-C 的 MMKV 实例,且最好的方式是在其构造函数作为参数传入。而 Java 与 Objective-C 的 MMKV 是两个完全没有任何关系的独立类型,因此我们在 common source set 中统一 MMKV_KMP 的构造函数非常不便。其次,在 MMKV 原本的设计中, MMKV 的实例本身也不是通过构造函数创建,而是通过一系列工厂方法创建,因此我们没有必要在 common 层定义其构造函数。

确定基本设计后,我们看看 MMKV_KMP 的定义:

interface MMKV_KMP {

    operator fun set(key: String, value: String): Boolean
    operator fun set(key: String, value: Boolean): Boolean

    fun takeString(key: String, default: String = ""): String
    fun takeBoolean(key: String, default: Boolean = false): Boolean
    
    fun close






请到「今天看啥」查看全文