開源|攜程機票 App KMM 跨端 KV 存儲庫 MMKV-Kotlin

作者簡介

禹昂,攜程移動端資深工程師,專注於 Kotlin 移動端跨平臺領域,Kotlin 中文社區核心成員,圖書《Kotlin 編程實踐》譯者。

一、背景

攜程機票移動端研發團隊自 2021 年始就一直在移動端實踐 Kotlin Multiplatform 技術(請見參考鏈接 1)。由於目前 Kotlin Multiplatform 生態尚處於起步階段,大部分 Kotlin 開源庫都是 JVM only 的,因此在我們團隊的日常開發過程中迫切需要一些能夠支持 KMM(Kotlin Multiplatform Mobile)的基礎庫或框架。

在原生移動端開發中,Android SDK 提供了 SharedPreferences,iOS 提供了 NSUserDefaults 用於 KV 存儲功能,但這二者在性能要求較高的情況下不能滿足需求。後來雖然 Google 推出了 Jetpack Datastore 用於替換 SharedPreferences,但它僅僅支持 Android 平臺。

攜程的基礎框架團隊經過一系列評估後決定使用騰訊的開源庫 MMKV (參考鏈接 2)用於滿足攜程 App 的 KV 存儲需求。相較於 SharedPreferences 與 NSUserDefaults,MMKV 擁有更強大的性能;相較於 Jetpack Datastore,MMKV 同時支持多個平臺,雙端業務邏輯一致性會更好;此外,MMKV 的優勢還包括:支持多進程訪問、進程被突然殺死時存儲依然可以生效等。因此,攜程機票移動端研發團隊決定基於 MMKV 二次開發,使 MMKV 支持 Kotlin Multiplatform 技術棧。

MMKV-Kotlin 因此應運而生,它擁有極爲便捷的集成方式,與 MMKV 高度相似的 API 等諸多特點。對於有 MMKV 使用經驗的原移動端開發人員來說,學習遷移成本很低。在經過了大半年的線上實驗證明了其穩定性與功能的完整性後,攜程機票研發團隊決定將其開源,爲 Kotlin Multiplatform 開源生態添磚加瓦。MMKV-Kotlin Github 地址詳見參考鏈接 3。

二、簡單使用

我們先來簡單介紹一下 MMKV-Kotlin 的用法,便於讀者對其有個較爲直觀的認識,也便於後文討論其內部設計。

2.1 安裝與導入

對於 KMM 開發者,在 common source set 中導入 MMKV-Kotlin,在 Gradle 腳本(kts)中添加:

dependencies {     
    implementation("com.ctrip.flight.mmkv:mmkv-kotlin:1.0.0")
}

如果您是使用 Kotlin 編寫純 Android 程序的用戶,則導入方式爲在 Gradle 腳本(kts)中添加:

dependencies {     
    implementation("com.ctrip.flight.mmkv:mmkv-kotlin-android:1.0.0")
}

對於純 Android 開發者來說,雖然沒有跨平臺的需求,但 MMKV-Kotlin 的 API 有針對 Kotlin 語法作出的優化。

注意,截至文章發佈前,MMKV-Kotlin 的最新版本是 1.2.0,基於 Kotlin 1.7.0,MMKV 1.2.13。

2.2 初始化

MMKV 在使用前需要進行初始化,由於 MMKV-Android 強依賴於 Context 類型,因此 MMKV-Kotlin 的初始化 API 在兩端有所區別,需要在 Android 與 iOS 的主工程或 KMM 的平臺相關 source set 中分別初始化:

Android:

import com.ctrip.flight.mmkv.initialize

// In Android source set
fun initializeMMKV(context: Context) {
    val rootDir = initialize(context)
    Log.d("MMKV Path", rootDir)
}

iOS:

import com.ctrip.flight.mmkv.initialize

// In iOS source set
fun initializeMMKV(rootDir: String) {
    initialize(rootDir)
    Log.d("MMKV Path", rootDir)
}

2.3 簡單的讀寫操作

import com.ctrip.flight.mmkv.defaultMMKV

fun demo() {
    val kv = defaultMMKV()

    kv.set("Boolean"true)
    kv.set("Int", Int.MIN_VALUE)
    kv.set("String""Hello from mmkv")
    
    println("Boolean: ${kv.takeBoolean("Boolean")}")
    println("Int: ${kv.takeInt("Int")}")
    println("String: ${kv.takeString("String")}")
}

使用方式與 MMKV 的 Java 及 Objective-C API 高度相似。

三、架構設計

MMKV core 採用 C++ 編寫,其絕大部分功能都在 core 實現。例如 mmap 提供的內存 - 文件映射、數據根據 protobuf 協議序列化與反序列化、多進程實現等等。core 直接對外暴露 C++ API,在 Win32、POSIX 等系統上可由開發者直接使用。在 core 的外層 MMKV 提供了多種語言的包裝,用於支持多種技術棧。例如:Java(Android)、Objective-C(iOS/macOS)、Dart(Flutter)、 JavaScript(React-Native,非騰訊開發與維護)。

MMKV-Kotlin 在底層需要依賴並調用 MMKV,對上希望暴露與 MMKV 類似的 API 並做一些符合語言特性的封裝。

MMKV-Kotlin 需要在兩個平臺相關的 source set 分別集成 MMKV。在 Android source set 中,如果直接集成 MMKV core 需要手動編寫 JNI 來做 JVM 層與 C++ 的交互,投入產出比太小, 因此我們選擇直接在 Gradle 腳本中通過 Maven 依賴 MMKV-Android,在 Android source set 中直接調用其 Java API。而在 iOS source set 中,由於 Kotlin 目前只與 C 和 Objective-C 有較爲完整的互操作能力,因此直接依賴提供 C++ API 的 MMKV core 也並不合適,我們選擇在 Gradle 腳本中通過 CocoaPods 依賴 MMKV-iOS,在 iOS source set 中通過其 Objective-C API 完成對 MMKV 的調用。

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 操作委託給它們。我們的實現方式有兩種可選:

最終我們選擇了方案二,原因在於:在平臺相關的 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()
    
    // More other functions and properties
}

雙平臺的實現如下,Android:

import com.tencent.mmkv.MMKV

class MMKVImpl internal constructor(internal val platformMMKV: MMKV) : MMKV_KMP {

    override operator fun set(key: String, value: String)Boolean = platformMMKV.encode(key, value)
    override operator fun set(key: String, value: Boolean)Boolean = platformMMKV.encode(key, value)
    
    override fun takeString(key: String, default: String)String = platformMMKV.decodeString(key, default) ?: default
    override fun takeBoolean(key: String, default: Boolean)Boolean = platformMMKV.decodeBool(key ,default)

    override fun close() = platformMMKV.close()
    
    // More other functions and properties

iOS:

import cocoapods.MMKV.MMKV
import platform.Foundation.NSSet

@Suppress("UNCHECKED_CAST")
class MMKVImpl internal constructor(internal val platformMMKV: MMKV) : MMKV_KMP {

    override operator fun set(key: String, value: Int)Boolean = platformMMKV.setInt32(value, key)
    override operator fun set(key: String, value: Boolean)Boolean = platformMMKV.setBool(value, key)

    override fun takeString(key: String, default: String)String = platformMMKV.getStringForKey(key, default) ?: default
    override fun takeBoolean(key: String, default: Boolean)Boolean = platformMMKV.getBoolForKey(key, default)

    override fun close() = platformMMKV.close()
    
    // More other functions and properties
}

最後是創建 MMKV_KMP 類型的工廠函數,我們只需通過 expect-actual 機制實現即可,這些工廠函數的返回類型都指定爲 MMKV_KMP,在平臺 source set 中調用 Java 與 Objective-C 的對應工廠函數,得到 MMKV 實例後通過構造函數構建出 MMKVImpl 實例並返回即可。具體代碼在此省略,可在 Github 中查看。

4.3 平臺專屬 API

在 Kotlin/Native 中,Kotlin 基本類型以及 String 還有部分集合類型都可以映射到 Objective-C 中的對應類型。例如 Kotlin 的 String 可以與 Objective-C 的 NSString 互相映射,在編寫代碼時被認爲是同一種類型。因此 common source set 中支持 CURD 的數據類型就是 MMKV-Android 與 MMKV-iOS 支持 CURD 類型的交集,包括:

其中要注意的點是,Kotlin 的 ByteArray 並不能與 Objective-C 的 NSData 直接映射,但二者可以通過手寫代碼轉換,因此在 iOS 中實現讀寫 ByteArray 也是基於這樣的手動轉換實現, 最終讀寫的還是 NSData。而 Set<String> 類型是 MMKV-Android 原本就支持的,但在 iOS source set 中則是通過讀寫 NSCoding 來實現的,Set<String> 可直接映射爲 NSSet,而 NSSet 又是 NSCoding 協議的實現者。

除此之外,MMKV-Android 與 MMKV-iOS 還支持一些平臺特有的類型,例如 Android 額外支持 Parcelable 接口的實現者,而 iOS 額外支持 NSCoding 協議的實現者及 NSDate ,這些額外支持的類型都在平臺 source set 中通過擴展函數的方式提供,以便儘量完整保留 MMKV 原有的功能,並讓開發者可以在平臺 source set 中使用它們。

五、單元測試

單元測試是開源項目必不可少的組成部分,鑑於 MMKV-Kotlin 的 API 與 MMKV 本身大體相同,因此單元測試的設計也參考了 MMKV 的單元測試。

5.1 API 功能測試

Kotlin 提供了一套 kotlin-test 單元測試框架,可以在 common 與 iOS source set 中使用。而在 Android source set 我們仍使用 JUnit。通常情況下我們只需要在 common source set 編寫一套單元測試代碼,而平臺相關 source set 中甚至無需添加任何代碼即可完成單元測試的構建。框架在運行後會針對已添加的平臺分別運行測試。但在 MMKV-Kotlin 中 initialize 函數是分不同平臺實現的,因此我們採取將 API 測試的核心代碼放在 common,在 Android/iOS source set 初始化 MMKV 並構建測試。

Common 層的測試代碼就是針對 MMKV-Kotlin API 的測試,參考了 MMKV 的設計,簡單舉例如下:

class MMKVKotlinTest {

    companion object {
        const val KEY_NOT_EXIST = "Key_Not_Exist"
    }

    lateinit var mmkv: MMKV_KMP
        private set

    fun setUp() {
        mmkv = mmkvWithID("unitTest"cryptKey = "UnitTestCryptKey")
    }

    fun testDown() {
        mmkv.clearAll()
    }

    fun testBoolean() {
        val result = mmkv.set("Boolean"true)
        assertEquals(result, true)
        val value0 = mmkv.takeBoolean("Boolean")
        assertEquals(value0, true)
        val value1 = mmkv.takeBoolean(KEY_NOT_EXIST)
        assertEquals(value1, false)
        val value2 = mmkv.takeBoolean(KEY_NOT_EXIST, true)
        assertEquals(value2, true)
    }
    
    // Other type test......
}

setUptestDown 分別負責 MMKV_KMP 的對象實例化及測試結束後的清理工作。針對每種具體數據類型的測試都獨立在 testXXX 函數內,針對正常寫讀、讀空值以及讀空值時默認值是否生效三種情況進行了測試。

我們在平臺 source set 中構建具體測試,並通過調用 common 層的測試代碼來完成測試,iOS 平臺的代碼簡單示例如下:

class MMKVKotlinTestIos {

    private lateinit var mmkvTest: MMKVKotlinTest

    @BeforeTest
    fun setUp() {
        initialize()
        mmkvTest = MMKVKotlinTest().apply {
            setUp()
        }
    }

    @AfterTest
    fun setDown() {
        mmkvTest.testDown()
    }

    @Test
    fun testCommon() = with(mmkvTest) {
        testBoolean()
        // Call other test functions
    }
    
    // Test NSDate and NSCoding......
}

我們通過註解構建測試,並調用 common 層的代碼執行具體測試,最後還需要編寫僅 iOS 平臺支持的 NSDate 與 NSCoding 類型的測試(代碼在上面的示例中省略),單元測試即構建完成。

5.2 Android 插樁測試

MMKV-Kotlin 純粹的單元測試在 Android 平臺是無法正常運行的,原因在於 Android 的單元測試並不支持包含原生二進制代碼的測試。前文提到過,MMKV core 是 C++ 編寫的,在 Android 平臺的構建產物爲 so 庫。MMKV-Android 構建出的 aar 以及 MMKV-Kotlin 構建出的 aar 都包含了這個 so 庫。但該 so 庫是針對 Android 平臺的二進制程序,並不能在開發者常用的 Windows 或 Mac 電腦上運行。因此我們需要構建插樁測試(instrumented test)將我們的測試代碼打包成測試 APK 在真機上運行,測試類的代碼如下:

@RunWith(AndroidJUnit4ClassRunner::class)
@SmallTest
class MMKVKotlinTestAndroid {

    private lateinit var mmkvTest: MMKVKotlinTest

    @Before
    fun setUp() {
        val context = ApplicationProvider.getApplicationContext<Context>()
        initialize(context)
        mmkvTest = MMKVKotlinTest().apply {
            setUp()
        }
    }

    @After
    fun setDown() {
        mmkvTest.testDown()
    }

    @Test
    fun testCommon() = with(mmkvTest) {
        testBoolean()
        // Call other test functions
    }
    
    // Test Parcelable......
    
    @Test
    fun testIPCUpdateInt() { ... }
    
    @Test
    fun testIPCLock() { ... }
}

測試的構建方式與 5.1 小節中 iOS 的構建方式並無二致。我們除了測試了通用類型及 Android 平臺特定的 Parcelable 外,還添加了對 Android 平臺跨進程訪問的測試,即 testIPCUpdateInt 與 testIPCLock 函數。爲了完善跨進程測試,我們還需額外定義一個運行在其他進程的 Service(代碼見參考鏈接 4)。跨進程訪問測試的設計也完全參考了 MMKV,見參考鏈接 5。

在 Android Studio 中點擊 “Make Project”(圖標爲一個小錘子)右邊的下拉選項欄,然後點擊“Edit Configurations...” 選項,在彈窗中點擊左上角的 “+” 然後選擇“Android Instrumented Test”,即可開始配置插樁測試。配置的截圖如下:

連接真機,然後運行即可。

六、Maven Central 發佈

Maven Central 可謂是 Android 與 Java 技術領域內分發項目的關鍵一環,開源作者除了要將代碼開源到 Github 以外,通常還要將項目的構建產物發佈至 Maven Central,以便於用戶以最便捷的方式集成開源庫。使用 Gradle 進行發佈的常見流程如下:

發佈成功後,用戶即可在 Gradle 以及 Maven 等構建工具中通過一行代碼導入你的開源庫。

我相信這個過程對於有 Maven 發佈經驗的 Android 及 Java 開發者來說並不陌生。但對於 Kotlin Multiplatform 開發者來說,部分細節有所不同,且網上資料較少,這裏會記錄一下踩坑記錄。

Kotlin Multiplatform 工程通常的發佈方式是將所有構建產物統一發布,這其中包括 Android 平臺的 aar 文件,JVM 平臺的 jar 文件,Kotlin/Native 的構建產物 klib 文件等。例如一次 publish 後,Nexus 上發佈的內容目錄結構如下:

我們可以看到共有 5 個目錄,其中 mmkv-kotlin 代表 common 層,通常 Multiplatform 工程只需要在 common source set 中對它添加依賴,即可在各平臺 source set 中自動獲取依賴。

而 mmkv-kotlin-android 代表 Android 平臺的產物,其內部的核心是個 aar 文件,與任何純粹的 Android 庫的結構沒有任何區別。由於 Android 在 Gradle 中本身就有完整的構建發佈體系, 所以 Android aar 的發佈需要手動配置發佈的變體,例如(kts):

kotlin {
    android {
        publishLibraryVariants("release")
    }
    // ......
}

我們配置了只發布 release 變體,也可以同時傳入 "debug" 參數,將 debug 變體一同發佈。

另外三個是 iOS 構建產物,分別對應:iphone 真機(iosarm64)、M1 & M2 芯片的 Mac 上的 iOS 模擬器(iossimulatorarm64)、Intel 芯片的 Mac 上的 iOS 模擬器(iosx64)。它們的核心都是 klib 文件,klib 是純 Kotlin 工程間互相引用的專用格式,例如 target 爲 iOS 系統的純 Kotlin/Native 工程可以單獨添加對這幾個 iOS klib 的依賴,從而使用 MMKV-Kotlin。但考慮到 Kotlin/Native 在 iOS 單平臺開發中好像並不存在實際使用場景和需求,因此 MMKV-Kotlin 的文檔中並沒有將這幾個 klib 的依賴代碼列出。

最後看一下 Gradle 發佈腳本(kts):

publishing {
    publications.withType<MavenPublication> {
        artifact(javadocJar)
        with(pom) {
            // pom setting......
        }
    }
    repositories {
        maven {
            credentials {
                username = NEXUS_USERNAME
                password = NEXUS_PASSWORD
            }
            url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2")
        }
    }
    signing {
        sign(publishing.publications)
    }
}

在腳本中我們依次配置了 javadoc、pom 信息、倉庫信息(用戶名、密碼、上傳的地址)以及簽名。上述 kts 代碼添加到 gradle.build.kts 文件後,sync 項目,然後運行 publish Gradle task,即可完成發佈。

最後有一個坑點需要注意,如果你不想將你的工程名稱作爲 artifact id,則可以在 publications.withType<MavenPublication> { ... } 內進行配置並覆蓋,只需給 artifactId 屬性重新賦值即可。但目前實測,覆蓋該屬性後只有 multiplatform 與 iOS 的 artifact id 會發生改變,對 Android 無效(Gradle 7.2,Kotlin 1.6.10、1.6.21),Android 會始終使用工程名作爲 artifact id。這個坑需要尤爲注意,避免 Android 的 artifact id 與其他平臺皆不相同的情況出現。

七、總結與未來計劃

MMKV-Kotlin 利用了 Kotlin 在各原生平臺能夠與 “土著語言”(Java、C、Objective-C,與 Swift 的交互正在開發中)直接交互的特性,將原本支持在多個平臺運行的 MMKV 移植到了 Kotlin Multiplatform 技術棧。爲了讓原本 MMKV 用戶有較小的遷移學習成本,MMKV-Kotlin 的 API 與 MMKV 保持了高度一致性,但從避免重名等因素考量,部分 API 的命名做了一些改變。例如:MMKV 之於 MMKV_KMP, encode 之於 set 等等。MMKV-Kotlin 也儘量完整保留了 MMKV 平臺特有的特性,可以方便 Kotlin Multiplatform 開發者在平臺相關的 source set 中使用。此外,MMKV-Kotlin 也設計了與 MMKV 類似的單元測試,覆蓋了絕大部分核心 API,並在 Android 平臺上設計了插樁測試用以檢測多進程訪問的正確性。

Kotlin Multiplaform 與 MMKV 都不僅僅支持 Android/iOS 兩個平臺。起初,MMKV-Kotlin 只支持 Android 與 iOS 兩個移動端平臺,但在 1.1.1 版本中已經添加了對 macOS(包括 Intel 與 M1&M2 芯片架構)的支持。導入的方式爲在 Kotlin/Native 工程的 Gradle 腳本(kts)中添加:

dependencies { 
    // Intel 芯片
    implementation("com.ctrip.flight.mmkv:mmkv-kotlin-macosx64:1.1.1")
    
    // M1&M2 芯片
    implementation("com.ctrip.flight.mmkv:mmkv-kotlin-macosarm64:1.1.1")
}

如果你的 Kotln/Native 工程是可執行程序,記得在 CocoaPods 中添加對 MMKV 的依賴,並添加對 MMKV 及 MMKVCore 的 link 配置,具體方式可參見 MMKV-Kotlin 的 README(參考鏈接 7)。

由於 macOS 版本的 MMKV 也通過 Objective-C 暴露 API,且也可以通過 CocoaPods 集成,因此添加 macOS 的支持只需在 Gradle 構建腳本中添加對應的 source set 即可,實現起來並不困難。其他 Apple 操作系統( watchOS、tvOS)MMKV 暫未直接支持,因此 MMKV-Kotlin 對它們的支持還在論證之中,如果可行,後續會將所有 Apple 平臺列入支持計劃之中。

由於 Win32、Linux 等平臺的 MMKV 通過 C++ 暴露 API,鑑於 Kotlin/Native 與 C++ 的互操作性不完善,以及 JetBrains 官方未來對 C++ 互操作性開發持消極態度(已經移出了 Kotlin roadmap),且目前 Kotlin 開發者對這兩個平臺的開發需求沒有那麼迫切,因此暫不考慮列入支持計劃。

由於 MMKV 與 Kotlin 會時常更新版本,因此 MMKV-Kotlin 會緊隨二者進行迭代。若 MMKV 或 Kotlin 進行了升級,MMKV-Kotlin 未來都會進行跟進升級,請使用者確保 MMKV-Kotlin 依賴的 MMKV 或 Kotlin 版本與您使用的版本兼容。

後續攜程機票移動端研發團隊也會繼續深耕 Kotlin Multiplatform 技術領域,爲整個技術社區帶來更多的乾貨與貢獻。

八、參考鏈接

https://mp.weixin.qq.com/s/gQNPO5iNFH1OQ-ygqjNfTA

https://github.com/Tencent/MMKV

https://github.com/ctripcorp/mmkv-kotlin

https://github.com/ctripcorp/mmkv-kotlin/blob/main/mmkv-kotlin/src/androidTest/kotlin/com/ctrip/flight/mmkv/MMKVTestService.kt

https://github.com/Tencent/MMKV/blob/master/Android/MMKV/mmkv/src/androidTest/java/com/tencent/mmkv/MMKVTestService.java

https://oss.sonatype.org/

https://github.com/ctripcorp/mmkvkotlin/blob/main/README_CN.md

“攜程技術” 公衆號

分享,交流,成長

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/aM0k8jBcqqWfxfyOPOqb0g