SlideShare a Scribd company logo
范聖佑
JetBrains Developer Advocate
JCConf Taiwan 2023
2023/10/06
在多平台間輕鬆共⽤業務邏輯與 UI 介⾯
從 otlin Multiplatform 到 Compose Multiplatform
範例程式碼
—
https://github.com/shengyou/kotlin-multiplatform-with-compose-demo
多平台開發痛點
—
• 各種型式的前端
多平台開發痛點
—
• 各種型式的前端
• 需要適應各種開發語⾔
多平台開發痛點
—
• 各種型式的前端
• 需要適應各種開發語⾔
• 重複實作的業務邏輯
DTO
Validation
Service
HTTP
Kotlin 編譯器設計
—
透過 Kotlin Multiplatform 共⽤業務邏輯
—
Server Web Desktop Android iOS
OS API Browser API OS API Android API iOS API
以 Kotlin Multiplatform 共⽤業務邏輯
使⽤ Kotlin Multiplatform 技術開發雙平台 Mobile App
—
Server Web Desktop Android iOS
OS API Browser API OS API Android API iOS API
以 Kotlin Multiplatform 共⽤業務邏輯
Android View SwiftUI
使⽤ Kotlin Multiplatform 技術開發雙平台 Mobile App
—
Kotlin Multiplatform Mobile
JCConf 2021 年的分享主題
—
https://youtu.be/SZGqMJXgOJg
🤔
有沒有辦法也共⽤ UI 呢?
Compose Multiplatform
—
多平台
Jetpack Compose
建立⼿機應⽤程式介⾯
Compose for Web
Compose for Desktop
建立桌⾯應⽤程式介⾯ 建立網路應⽤程式介⾯
透過 Compose Multiplatform 共⽤ UI
—
Server Web Desktop Android iOS
OS API Browser API OS API Android API iOS API
以 Kotlin Multiplatform 共⽤業務邏輯
以 Compose Multiplatform 共⽤ UI
Android View
Swing SwiftUI
Compose Multiplatform
JCConf 2022 年的分享主題
—
https://youtu.be/Ysh5CLkPiyE
🙄
可是我想要的是 iOS 啊…
KotlinConf’23 公佈⽀援 iOS!
—
https://youtu.be/FWVi4aV36d8
擴⼤ Compose Multiplatform 版圖
—
Server Web Desktop Android iOS
OS API Browser API OS API Android API iOS API
以 Kotlin Multiplatform 共⽤業務邏輯
Android View
Swing SwiftUI
Compose Multiplatform
以 Compose Multiplatform 共⽤ UI
以 Compose Multiplatform 共⽤ UI
實作範例 - LoginScreen
—
實作範例 - HomeScreen
—
實作平台
—
• Android
• iOS
• Desktop
• Backend API
Backend
Desktop
Android
iOS
HTTPs Request/Response
JSON
Client
Server
🍿
實作成果展⽰
Demo TIME
⽰範重點
—
• 多平台共⽤ UI - Compose Multiplatform
• 平台專⽤ API - 偵測平台名稱
• 共享業務邏輯 - ViewModel、HTTP、Data Class
• 整合 Multiplatform 函式庫 - Ktor Client、Voyager、Kamel
• 後端 API 服務 - Ktor Server
🧑💻👩💻
實戰 Kotlin Multiplatform
建立開發環境
—
• Mac with macOS
• JDK
• Android Studio
• Kotlin Multiplatform Mobile Plugin
• Xcode + SDK
• Cocoapods
kdoctor 指令⼯具
—
透過 Homebrew 安裝的指令⼯
具,可⽤於檢查開發環境是否符
合 Kotlin Multiplatform Mobile 的
要求?
建立 Compose Multiplatform 專案
—
專案資料夾結構
—
• androidApp → Android 主程式
• iosApp → iOS 主程式
• desktopApp → Desktop 主程式
• shared → 共⽤程式碼
- commonMain → 多平台共⽤實作
- androidMain → Android 平台專⽤實作
- iosMain → iOS 平台專⽤實作
- desktopMain → Desktop 平台專⽤實作
• server → 後端 API 實作
👈
多平台共⽤ UI
—
實作⾴⾯
—
object LoginScreen : Screen {
@Composable
override fun Content() {
/
/
.
.
.
}
}
各區塊元件化
—
Logo()
DemoOnText()
Spacer()
LoginForm(
/
*
.
.
.
*
/
)
Spacer()
PasswordForgetLink()
SignUpLink()
TextField(
value =
.
.
.
,
label = { Text(text = "Username") },
onValueChange = {
/
*
.
.
.
*
/
},
modifier =
.
.
.
,
)
TextField(
value =
.
.
.
,
label = { Text(text = "Password") },
visualTransformation =,
keyboardOptions =,
onValueChange = {
/
*
.
.
.
*
/
},
modifier =
.
.
.
,
)
Button(
onClick = {
/
*
.
.
.
*
/
},
shape = RoundedCornerShape(50.dp),
modifier =
.
.
.
,
) {
Text(text = "Login")
}
排版差異化 (Mobile)
—
Column(
modifier =
.
.
.
,
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
/
/
.
.
.
Column(
modifier =
.
.
.
,
) {
/
/
.
.
.
}
/
/
.
.
.
}
Box(
modifier =
.
.
.
,
) {
/
/
.
.
.
}
排版差異化 (Desktop)
—
Row(
modifier =
.
.
.
,
horizontalArrangement = Arrangement.Center
) {
Column(
modifier =
.
.
.
,
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
/
/
.
.
.
}
Column(
modifier =
.
.
.
,
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
/
/
.
.
.
}
}
平台專⽤ API
—
expect/actual 各平台實作
—
偵測平台版本
(expect 部份)
—
expect fun getPlatformName(): String
shared
- commonMain
- androidMain
- iosMain
- desktopMain
偵測平台版本
(actual 部份)
—
// androidMain
actual fun getPlatformName(): String =
"Andriod (API ${android.os.Build.VERSION.SDK_INT})"
// iosMain
actual fun getPlatformName(): String =
"iOS (${UIDevice.currentDevice.systemVersion})"
// desktopMain
actual fun getPlatformName(): String =
"Desktop (JVM ${Runtime.version()})"
shared
- commonMain
- androidMain
- iosMain
- desktopMain
偵測平台版本
(UI 部份)
— @Composable
fun DemoOnText() {
Text(
text = "Demo on ${getPlatformName()}",
style = TextStyle(
fontSize =
.
.
.
,
fontFamily =
.
.
.
,
color =
.
.
.
,
),
)
}
共享業務邏輯
—
API
發送 HTTP Request 接收 HTTP Response UI 換⾴
載入網路圖片
整合 Multiplatform 函式庫
—
• Ktor - HTTP Client
• kotlinx.serialization - JSON serialization/deserialization
• kotlinx.coroutines - Coroutine
• Voyager - Navigation、ViewModel
• Kamel - Asynchronous Media Loading
安裝相依套件
—
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation("io.ktor:ktor-client-core:$ver")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$ver")
implementation("io.ktor:ktor-client-content-negotiation:$ver")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ver")
implementation("cafe.adriel.voyager:voyager-navigator:$ver")
implementation("io.ktor:ktor-client-core:$ver")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$ver")
implementation("io.ktor:ktor-client-content-negotiation:$ver")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ver")
implementation("media.kamel:kamel-image:$ver")
}
}
val androidMain by getting {
dependencies {
implementation("io.ktor:ktor-client-okhttp:$ver")
}
}
val iosMain by creating {
載入⾴⾯
—
@Composable
fun MainApplication() {
val screen = when (getTarget()) {
Target.DESKTOP
-
>
DesktopLoginScreen
else
-
>
MobileLoginScreen
}
Navigator(screen)
}
實作 ViewModel
—
class LoginScreenModel :
StateScreenModel<LoginScreenModel.State>(State.Init) {
private val httpClient = HttpClient {
install(ContentNegotiation) {
json()
}
defaultRequest {
url(apiBaseUrl)
}
expectSuccess = true
}
sealed class State {
data object Init : State()
data class LoggedIn(val user: User) : State()
}
fun login(username: String, password: String) {
coroutineScope.launch {
val loginResponse: LoginResponse = httpClient.post("
.
.
.
") {
setBody(LoginRequest(username, password))
contentType(ContentType.Application.Json)
• 設定 HTTP Client
• 設定 State
• 發送 HTTP Req/Res
• 關閉 HTTP Client
使⽤ ViewModel
—
object LoginScreen : Screen {
@Composable
override fun Content() {
val screenModel = rememberScreenModel { LoginScreenModel() }
val username = remember { mutableStateOf(TextFieldValue()) }
val password = remember { mutableStateOf(TextFieldValue()) }
Button(
onClick = {
screenModel.login(
username.value.text, password.value.text
)
},
shape = RoundedCornerShape(50.dp),
modifier =
.
.
.
,
) {
Text(text = "Login")
}
}
}
依狀態換⾴
—
object LoginScreen : Screen {
@Composable
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
val screenModel = rememberScreenModel { LoginScreenModel() }
val state by screenModel.state.collectAsState()
val username = remember { mutableStateOf(TextFieldValue()) }
val password = remember { mutableStateOf(TextFieldValue()) }
when (val loggedInState = state) {
is LoginScreenModel.State.Init
-
>
{}
is LoginScreenModel.State.LoggedIn
-
>
{
navigator.push(HomeScreen(loggedInState.user))
}
}
}
}
載入網路圖片
—
KamelImage(
resource = asyncPainterResource(
data = Url(user.profileImageUrl)
),
modifier =
.
.
.
,
contentDescription =
.
.
.
,
)
後端 API 服務
—
Server Client
語法簡單
輕量
適合做微服務
HTTP Client
⽀援多平台
搭配 kotlinx.serialization 做 SDK
共⽤ Data Class
—
@Serializable
data class LoginRequest(
val username: String,
val password: String,
)
@Serializable
data class LoginResponse(
val result: Boolean,
val message: String,
val user: User? = null,
)
@Serializable
data class User(
val id: Int,
val username: String,
val password: String,
val email: String,
val displayName: String,
val profileImageUrl: String,
)
Ktor Server
—
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
install(ContentNegotiation) {
json()
}
// Ktor plugins
configureLogin()
}.start(wait = true)
}
實作 API Service
—
fun Application.configureLogin() {
routing {
post("...") {
// 接收 HTTP Request
// 反序列化成 Data Class
val req = call.receive<LoginRequest>()
// 登入驗證程式碼
// 回傳 HTTP Response
call.respond(
LoginResponse(
result = ...,
message = "...",
user = loggedInUser,
)
)
}
}
}
🤓
本⽇回顧
Kotlin Multiplatform 全版圖
—
Server Web Desktop Android iOS
OS API Browser API OS API Android API iOS API
以 Kotlin Multiplatform 共⽤業務邏輯
以 Compose Multiplatform 共⽤ UI
Android View
Swing SwiftUI
實作範例
—
⽰範內容包括…
—
• 多平台共⽤ UI - Compose Multiplatform
• 平台專⽤ API - 偵測平台名稱
• 共享業務邏輯 - ViewModel、HTTP、Data Class
• 整合 Multiplatform 函式庫 - Ktor Client、Voyager、Kamel
• 後端 API 服務 - Ktor Server
Kotlin Multiplatform 優勢
—
• ⼀個語⾔跨多個平台
• 原⽣效能
• 可依需求調整共享程式碼的比例
對比其他解決⽅案
—
Kotlin Multiplatform ⽣態系
—
• 各平台設定檔
• Mobile 螢幕旋轉
• Network Retry
• Error Handling
• 前後端共⽤驗證邏輯
• 整合資料庫
• 導入更多的 Clean Architecture
可進⼀步完善的實作⽅向
—
Kotlin Multiplatform 學習資源
—
Kotlin Multiplatform 官⽅⾴⾯ Compose Multiplatform 官⽅⾴⾯
Compose Multiplatform 官⽅範例
—
實務案例
—
⼿機開發編年史 (攜程)
來⾃阿⾥巴巴及美團的
Kotlin Multiplatform 應⽤案例
#8
Kotlin 爐邊漫談 Podcast
https:
/
/
podcast.kotlin.tips/
#5
歡迎參加 Kotlin 社群
—
Line 群 Telegram 群
加入討論群取得最新資訊
tw.kotlin.tips
shengyou.fan@jetbrains.com
fb.me/shengyoufan
shengyoufan
@shengyou
在多平台間輕鬆共⽤業務邏輯與 UI 介⾯
從 otlin Multiplatform 到 Compose Multiplatform

More Related Content

What's hot (20)

PDF
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
Johnny Sung
 
PDF
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
Shengyou Fan
 
PDF
Railway Oriented Programming
Scott Wlaschin
 
PDF
KMM survival guide: how to tackle struggles between Kotlin and Swift
Commit University
 
PDF
Jetpack compose
LutasLin
 
PDF
How I make a podcast website using serverless technology in 2023
Shengyou Fan
 
PDF
Easy tests with Selenide and Easyb
Iakiv Kramarenko
 
PDF
Introduction to Coroutines @ KotlinConf 2017
Roman Elizarov
 
PDF
Introduction to Kotlin coroutines
Roman Elizarov
 
PDF
Swift in SwiftUI
Bongwon Lee
 
PPTX
Event-sourced systems with Kafka, Clojure, and Jackdaw
Bryce Covert
 
PDF
Try Jetpack Compose
LutasLin
 
PDF
Android Jetpack Compose - Turkey 2021
Nelson Glauber Leal
 
PDF
Kotlin 2.0을 통해 알아보는 코틀린의 미래
Leonardo YongUk Kim
 
PPTX
Javascript this keyword
Pham Huy Tung
 
PDF
Deep dive into Coroutines on JVM @ KotlinConf 2017
Roman Elizarov
 
PPT
Advanced JavaScript
Fu Cheng
 
PDF
Declarative UIs with Jetpack Compose
Ramon Ribeiro Rabello
 
PDF
Unit Testing Oracle PL/SQL Code: utPLSQL, Excel and More
Steven Feuerstein
 
PPT
Spock Framework
Леонид Ставила
 
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
Johnny Sung
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
Shengyou Fan
 
Railway Oriented Programming
Scott Wlaschin
 
KMM survival guide: how to tackle struggles between Kotlin and Swift
Commit University
 
Jetpack compose
LutasLin
 
How I make a podcast website using serverless technology in 2023
Shengyou Fan
 
Easy tests with Selenide and Easyb
Iakiv Kramarenko
 
Introduction to Coroutines @ KotlinConf 2017
Roman Elizarov
 
Introduction to Kotlin coroutines
Roman Elizarov
 
Swift in SwiftUI
Bongwon Lee
 
Event-sourced systems with Kafka, Clojure, and Jackdaw
Bryce Covert
 
Try Jetpack Compose
LutasLin
 
Android Jetpack Compose - Turkey 2021
Nelson Glauber Leal
 
Kotlin 2.0을 통해 알아보는 코틀린의 미래
Leonardo YongUk Kim
 
Javascript this keyword
Pham Huy Tung
 
Deep dive into Coroutines on JVM @ KotlinConf 2017
Roman Elizarov
 
Advanced JavaScript
Fu Cheng
 
Declarative UIs with Jetpack Compose
Ramon Ribeiro Rabello
 
Unit Testing Oracle PL/SQL Code: utPLSQL, Excel and More
Steven Feuerstein
 

Similar to [JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 UI 介面 (20)

PPTX
2016輕鬆開發自有網路地圖工作坊 進階班 0701
family
 
PDF
HTML+COIMOTION 開發跨平台 app
Ben Lue
 
PDF
透過 Windows Azure Mobile Services 開發各平台 Apps
Eric ShangKuan
 
PPTX
利用Signalr打造即時通訊@Tech day geek
Johnson Gau
 
PPTX
Flutter Forward Extended in Google Developer Taipei
abc873693
 
PPTX
前端MVC之backbone
Jerry Xie
 
PPTX
Script with engine
Webrebuild
 
PDF
ASP.NET Core 2.1設計新思維與新發展
江華 奚
 
PDF
20250422 從零開始的 Angular 網頁應用程式 Part II: Service & Routing & Form
Kun-Neng Hung
 
PDF
Arduino Yún使用Http restful api控制io
吳錫修 (ShyiShiou Wu)
 
PPTX
Windows Mobile Widget 開發
Chui-Wen Chiu
 
PDF
Introduction to Parse JavaScript SDK
維佋 唐
 
PDF
Behind Tetris5
Junwen Sun
 
PPT
Silverlight 2.0 完全新手學堂,基礎入門 10 大招
Chui-Wen Chiu
 
PPTX
唐俊开-Html5 mobile web app浅谈
Webrebuild
 
PPTX
Html5 mobile web app浅谈
sankyu Tang
 
PPTX
HTML5 介绍
S S
 
PDF
使用NodeJS构建静态资源管理系统
Frank Xu
 
PDF
Page Object in XCUITest
Jz Chang
 
PDF
怎樣在 Flutter app 中使用 Google Maps
Weizhong Yang
 
2016輕鬆開發自有網路地圖工作坊 進階班 0701
family
 
HTML+COIMOTION 開發跨平台 app
Ben Lue
 
透過 Windows Azure Mobile Services 開發各平台 Apps
Eric ShangKuan
 
利用Signalr打造即時通訊@Tech day geek
Johnson Gau
 
Flutter Forward Extended in Google Developer Taipei
abc873693
 
前端MVC之backbone
Jerry Xie
 
Script with engine
Webrebuild
 
ASP.NET Core 2.1設計新思維與新發展
江華 奚
 
20250422 從零開始的 Angular 網頁應用程式 Part II: Service & Routing & Form
Kun-Neng Hung
 
Arduino Yún使用Http restful api控制io
吳錫修 (ShyiShiou Wu)
 
Windows Mobile Widget 開發
Chui-Wen Chiu
 
Introduction to Parse JavaScript SDK
維佋 唐
 
Behind Tetris5
Junwen Sun
 
Silverlight 2.0 完全新手學堂,基礎入門 10 大招
Chui-Wen Chiu
 
唐俊开-Html5 mobile web app浅谈
Webrebuild
 
Html5 mobile web app浅谈
sankyu Tang
 
HTML5 介绍
S S
 
使用NodeJS构建静态资源管理系统
Frank Xu
 
Page Object in XCUITest
Jz Chang
 
怎樣在 Flutter app 中使用 Google Maps
Weizhong Yang
 
Ad

More from Shengyou Fan (20)

PDF
[JCConf 2024] Kotlin/Wasm:為 Kotlin 多平台帶來更多可能性
Shengyou Fan
 
PDF
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
Shengyou Fan
 
PDF
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
Shengyou Fan
 
PDF
Using the Exposed SQL Framework to Manage Your Database
Shengyou Fan
 
PDF
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
Shengyou Fan
 
PDF
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
Shengyou Fan
 
PDF
Composer 經典食譜
Shengyou Fan
 
PDF
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
Shengyou Fan
 
PDF
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
Shengyou Fan
 
PDF
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
Shengyou Fan
 
PDF
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
Shengyou Fan
 
PDF
用 Kotlin 打造讀書會小幫手
Shengyou Fan
 
PDF
Kotlin 讀書會第三梯次第一章
Shengyou Fan
 
PDF
用 OPENRNDR 將 Chatbot 訊息視覺化
Shengyou Fan
 
PDF
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
Shengyou Fan
 
PDF
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
Shengyou Fan
 
PDF
Ktor 部署攻略 - 老派 Fat Jar 大法
Shengyou Fan
 
PDF
以 Kotlin 快速打造 Mobile Backend
Shengyou Fan
 
PDF
Kotlin 一條龍 - 打造全平台應用
Shengyou Fan
 
PDF
[HKOSCon 2020] Build an api service using ktor rapidly
Shengyou Fan
 
[JCConf 2024] Kotlin/Wasm:為 Kotlin 多平台帶來更多可能性
Shengyou Fan
 
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
Shengyou Fan
 
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
Shengyou Fan
 
Using the Exposed SQL Framework to Manage Your Database
Shengyou Fan
 
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
Shengyou Fan
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
Shengyou Fan
 
Composer 經典食譜
Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
Shengyou Fan
 
用 Kotlin 打造讀書會小幫手
Shengyou Fan
 
Kotlin 讀書會第三梯次第一章
Shengyou Fan
 
用 OPENRNDR 將 Chatbot 訊息視覺化
Shengyou Fan
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
Shengyou Fan
 
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
Shengyou Fan
 
Ktor 部署攻略 - 老派 Fat Jar 大法
Shengyou Fan
 
以 Kotlin 快速打造 Mobile Backend
Shengyou Fan
 
Kotlin 一條龍 - 打造全平台應用
Shengyou Fan
 
[HKOSCon 2020] Build an api service using ktor rapidly
Shengyou Fan
 
Ad

[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 UI 介面