Kotlin Multiplatform 嚐鮮
多平臺開發痛點
Kotlin Multiplatform最重要的目標是在多平臺上共享程式碼,現在支援的平臺有JVM,Android,Javascript,iOS、Linux、Windows、Mac等,幾乎覆蓋所有的平臺。設想下現在移動優先的策略,一個公司至少要做Android、iOS、WAP、小程式平臺。其中Data Model,介面呼叫,業務邏輯等這些程式碼各個平臺都需要用不同的語言實現。這樣做了很多重複的工作,而且你需要招更多人,公司需要為更多人支付更多的薪水。

different platform dev
Kotlin Multiplatform簡介

Kotlin multiplatform
Kotlin Multiplatform並不是把你寫的程式碼在各個平臺上翻譯一遍,這樣做會有很多限制。各個平臺會有自己的一些平臺特性的功能。Kotlin Multiplatform能讓你共享盡可能多的程式碼,但是也提供呼叫一些平臺特有的API(expect/actual語法)。這裡我們可以看到我們使用Kotlin/JVM來生成安卓和後端的Java程式碼,使用Kotlin/Native來生成Objective-C程式碼給到iOS,使用Kotin/JS生成javascript程式碼。
Common Module

Common Moudle
你可以把多個平臺通用的程式碼提取到Common Module,比如DTO、API呼叫,一些工具類、還有業務邏輯。當然你也可以直接使用一些已經支援Multiplatform的第三方類庫:
- Kotlin Standard Library
- Ktor client 網路介面呼叫(基於協程)
- Kotlin serialization 序列化
- Mockk Mock類庫
- Kotlinx-io io類庫
- Kotlinx-json json庫
支援多平臺的第三方類庫現在也是迅猛發展,會有越來越多Java、Kotlin類庫會轉成支援Multiplatform。
Demo
官方的demo可以看這裡: ofollow,noindex">http://kotlinlang.org/docs/tutorials/native/mpp-ios-android.html 。怎麼搭建環境建立專案這裡就不詳細說了:

project
Demo還是非常簡單的,就是建立一個字串,然後拼接上平臺返回的一段字串。這裡我們來做一個相對複雜一點的示例,比如我們要呼叫一個網路介面,返回一個天氣資訊的json string,然後我們把json string序列化成物件,然後在android iPhone介面上顯示。
SharedCode專案gradle配置
apply plugin: 'kotlin-multiplatform' apply plugin: 'kotlinx-serialization' kotlin { targets { final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \ ? presets.iosArm64 : presets.iosX64 fromPreset(iOSTarget, 'ios') { compilations.main.outputKinds('FRAMEWORK') } fromPreset(presets.jvm, 'android') } sourceSets { commonMain{ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version" } } androidMain { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version" } } iosMain{ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serialization_version" } } } }
我們在tagets裡面定義了兩種平臺,分別是ios和android,當然預設的還有common模組用來放共享的程式碼。
在sourceSets裡面我們定義了common, android, ios模組的依賴,這裡我們依賴了kotlin標準庫和kotlinx-serialization庫。這裡要注意下,同一個庫在不同平臺下依賴的artifactId可能會不一樣。
Show me code
common.kt
expect fun httpGet(url:String):String fun <T> convertJsonToObject(jsonString: String, serializer:DeserializationStrategy<T>):T { return JSON(strictMode = false).parse(serializer, jsonString) } fun getGuangZhouWeather():CityWeather { val jsonString = httpGet("http://t.weather.sojson.com/api/weather/city/101280101") println("jsonString: $jsonString") return convertJsonToObject(jsonString, CityWeather.serializer()) } @Serializable data class CityWeather( var time: String, var date: String, var message: String, var status: String, var cityInfo:CityInfo, var data: WeatherData ) @Serializable data class WeatherData( var shidu: String, var pm25: String, var pm10: String, var quality: String, var wendu: String, var ganmao: String, var yesterday:DayInfo, var forecast:MutableList<DayInfo> )
這段common.kt的程式碼是在android和ios上共享的,注意第一行:
expect fun httpGet(url:String):String
我們用 expect
關鍵字定義了一個呼叫http請求的方法,傳入一個字串型別的url然後返回http response的字串。這個expect關鍵字表示這個方法是需要每個平臺各自實現的。
convertJsonToObject
方法是呼叫kotlinx-serialization跨平臺庫把json string序列化成物件。
getGuangZhouWeather
方法是先呼叫網路請求,然後把字串序列化成CityWeather物件返回。
最後我們需要做的是在/androidMain/kotlin/actual.kt和/iosMain/kotlin/actual.kt檔案實現在common.kt定義的httpGet方法。
Android實現
actual fun httpGet(url:String):String{ return URI(url).toURL().readText() }
iOS實現
actual fun httpGet(url:String):String{ val urlWithString = NSURL.URLWithString(url) if (urlWithString != null) { val requestWithURL = NSMutableURLRequest.requestWithURL(urlWithString) val response: CPointer<ObjCObjectVar<NSURLResponse?>>? = null val error : CPointer<ObjCObjectVar<NSError?>>? = null val nsData = NSURLConnection.sendSynchronousRequest(requestWithURL, response, error)?.copy() as NSData println("nsData: $nsData, lenght: ${nsData.length}, desc: ${nsData.description}") println("response: $response") val string = NSString.stringWithCString(nsData.bytes() as CPointer<ByteVar>, encoding=NSUTF8StringEncoding) if (string != null) { return string } } return "" }
如果你玩過Objective-c,你一定對上面的iOS實現的程式碼非常熟悉,這裡的每個類都跟Objecttive-c都能對應上。實現專案可以通過寫Kotlin程式碼來Objective-C程式碼。這就是Kotlin/Native的能力。

Kotlin/Native
Build
在專案頂層指定gradlew命令,編譯專案。
./gradlew clean build

image.png
編譯完成之後你可以看到

build
執行Android & iPhone App
呼叫其實也很簡單,android 和 iphone呼叫getGuangZhouWeather方法,然後顯示溫度。

Run app
執行iPhone的時候要注意,因為這裡要呼叫http介面,所以你需要設定一下security settings,如下:

security setting
完整程式碼請看: https://github.com/dengyin2000/mpp-iOS-Android
Reference: