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可以看这里: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:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,472评论 2 59
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,566评论 25 707
  • 挑战 我曾经设计了一个移动APP的UI,里面集合各种有关UI设计作品的风格、主题,有各种高逼格的图片,提供给特定的...
    Nicebook阅读 4,740评论 0 25
  • 【今日阅读】64-78 【思维导图】 阅读心得:在表达感受后,需要清晰准确的语言表达需求,越具体越好,这样才能让对...
    袅绕2011阅读 297评论 0 2
  • 关于这几本书的印象,献给那个总与诺奖失之交臂的倒霉作家。(估计这次依旧中不了奖吧) ---------------...
    梦游三万里阅读 663评论 2 4