SlideShare a Scribd company logo
范聖佑
JetBrains
Developer Advocate
打造多平台應⽤程式
以 Compose 及 otlin Multiplatform
DevFest 2023 Kaohsiung
2023/11/25
多平台開發痛點
—
• 各種型式的前端
多平台開發痛點
—
• 各種型式的前端
• 需要適應各種開發語⾔
多平台開發痛點
—
• 各種型式的前端
• 需要適應各種開發語⾔
• 重複實作的業務邏輯
DTO
Validation
Service
HTTP
Kotlin 編譯器設計
—
透過 Kotlin Multiplatform 共⽤業務邏輯
—
Server Web Desktop Android iOS
OS API Browser API OS API Android API iOS API
以 Kotlin Multiplatform 共⽤業務邏輯
共⽤ UI?
從 Jetpack Compose 到 Compose Multiplatform
—
多平台
Jetpack Compose
建立⼿機應⽤程式介⾯
可是缺 iOS 啊?
🙄
Compose for Web
Compose for Desktop
建立桌⾯應⽤程式介⾯ 建立網路應⽤程式介⾯
Compose for iOS 來啦!
—
https://youtu.be/FWVi4aV36d8
• KotlinConf’23 ⼤會發佈 Alpha 版
• 預計 2024 年發佈 Beta 版
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
Kotlin Multiplatform 可上 Production!
—
🧑💻👩💻
實戰 Kotlin Multiplatform
本⽇範例
—
• Android
• iOS
• Desktop
• Backend API
Backend
Desktop
Android iOS
HTTPs Request/Response
JSON
Client
Server
範例畫⾯ - LoginScreen
—
範例畫⾯ - HomeScreen
—
⽰範重點
—
• 多平台共⽤ UI - Compose Multiplatform
• 平台專⽤ API - 偵測平台名稱
• 共享業務邏輯 - ViewModel、HTTP、Data Class
• 整合 Multiplatform 函式庫 - Ktor Client、Voyager、Kamel
• 後端 API 服務 - Ktor Server
建立開發環境
—
• Mac with macOS
• JDK
• Android Studio
• Xcode (+ SDK)
• Cocoapods
透過 Homebrew 安裝 kdoctor,可檢查環境是否符合 KMP 開發需求?
kdoctor 指令⼯具
全新 KMP 開發⼯具
—
JetBrains Fleet
• 開啟 Kotlin Multiplatform Wizard
• 勾選⽬標平台
• 下載 Zip 檔
• 解壓縮
• 以 JetBrains Fleet 開啟專案
建立 Kotlin Multiplatform 專案
—
https:
/
/
kmp.jetbrains.com
專案資料夾結構
—
• composeApp → Compose 多平台主程式
- commonMain → 多平台共⽤實作
- androidMain → Android 平台專⽤實作
- iosMain → iOS 平台專⽤實作
- desktopMain → JVM/Desktop 平台專⽤實作
• iosApp → iOS 主程式進入點
• server → 後端 API 主程式
👈
• Ktor - HTTP Client
• kotlinx.serialization - JSON serialization/deserialization
• kotlinx.coroutines - Coroutine
• Voyager - Navigation、ViewModel
• Kamel - Asynchronous Media Loading
整合 Multiplatform 函式庫
—
安裝相依套件
—
kotlin {
sourceSets {
val desktopMain by getting
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
@OptIn(ExperimentalComposeLibrary
:
:
class)
implementation(compose.components.resources)
implementation("cafe.adriel.voyager:voyager-navigator:$ver")
implementation("media.kamel:kamel-image:$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")
}
androidMain.dependencies {
implementation(libs.compose.ui)
implementation(libs.compose.ui.tooling.preview)
implementation(libs.androidx.activity.compose)
implementation("io.ktor:ktor-client-okhttp:$ver")
}
iosMain.dependencies {
後端 API - Ktor Server
—
• 語法簡單易上⼿
• 輕量級 Web 框架
• ⽀援 Async 功能
共⽤ 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,
)
composeApp
- commonMain
- androidMain
- iosMain
- desktopMain
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,
)
)
}
}
}
多平台共⽤ 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,
) {
/
/
.
.
.
}
}
載入網路圖片
—
KamelImage(
resource = asyncPainterResource(
data = Url(user.profileImageUrl)
),
modifier =
.
.
.
,
contentDescription =
.
.
.
,
)
平台專⽤ API
—
expect/actual 各平台實作
—
偵測平台版本
(expect 部份)
—
expect fun getPlatformName(): String
composeApp
- 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()})"
composeApp
- commonMain
- androidMain
- iosMain
- desktopMain
偵測平台版本
(UI 部份)
— @Composable
fun DemoOnText() {
Text(
text = "Demo on ${getPlatformName()}",
style = TextStyle(
fontSize =
.
.
.
,
fontFamily =
.
.
.
,
color =
.
.
.
,
),
)
}
共享業務邏輯
—
API
發送 HTTP Request 接收 HTTP Response UI 換⾴
載入網路圖片
Ktor Client
—
• HTTP Client
• ⽀援多平台
• 可搭配
- kotlinx.serialization
- kotlinx.coroutines
實作 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))
}
}
}
}
🤓
本⽇回顧
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
• 平台專⽤ API
• 共享業務邏輯
• 整合多平台函式庫
• 後端 API 服務
Kotlin Multiplatform 優勢
—
• ⼀個語⾔跨多個平台
• 原⽣效能
• 可依需求調整共享程式碼的比例
對比其他解決⽅案
—
Place your text here
four columns
maximum
—
採⽤ Kotlin Multiplatform 技術的團隊
—
Kotlin Multiplatform 學習資源
—
Kotlin Multiplatform 官⽅⾴⾯ Compose Multiplatform 官⽅⾴⾯
本⽉ KMP 技術直播活動
—
線上預約提醒
更多 Kotlin Multiplatform 範例集
—
Compose Multiplatform 範例集 Kotlin Multiplatform 範例集
Kotlin Multiplatform ⽣態系
—
Kotlin is Awesome! Kotlin Multiplatform Libraries
Kotlin 爐邊漫談 - 聆聽業界實績案例的最佳來源
—
⼿機開發編年史 (携程)
來⾃阿⾥巴巴及美团的
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

More Related Content

What's hot (20)

PDF
Git training v10
Skander Hamza
 
PDF
CI/CD with Github Actions
Md. Minhazul Haque
 
ODP
Qt 5 - C++ and Widgets
Juha Peltomäki
 
PDF
A Separation of Concerns: Clean Architecture on Android
Outware Mobile
 
PPT
Version Control
Kivanc Kanturk
 
PPTX
Présentation de git
Julien Blin
 
PPTX
20080311 - Paris Vi Master STL TA - Initiation Maven
Arnaud Héritier
 
PDF
[PHP 也有 Day #64] PHP 升級指南
Shengyou Fan
 
PDF
Jenkins
Roger Xia
 
PDF
Git-flow workflow and pull-requests
Bartosz Kosarzycki
 
PDF
Git - An Introduction
Behzad Altaf
 
PPTX
Jenkins for java world
Ashok Kumar
 
PDF
Spring boot introduction
Rasheed Waraich
 
PDF
Introduction to Git and GitHub
Vikram SV
 
PPTX
CICD Pipeline Using Github Actions
Kumar Shìvam
 
PPTX
Unit testing JavaScript: Jasmine & karma intro
Maurice De Beijer [MVP]
 
PDF
Create an architecture for web test automation
Elias Nogueira
 
PPTX
Write microservice in golang
Bo-Yi Wu
 
PDF
Angular.pdf
Jaouad Assabbour
 
PDF
Behavior-Driven Development and Automation Testing Using Cucumber Framework W...
KMS Technology
 
Git training v10
Skander Hamza
 
CI/CD with Github Actions
Md. Minhazul Haque
 
Qt 5 - C++ and Widgets
Juha Peltomäki
 
A Separation of Concerns: Clean Architecture on Android
Outware Mobile
 
Version Control
Kivanc Kanturk
 
Présentation de git
Julien Blin
 
20080311 - Paris Vi Master STL TA - Initiation Maven
Arnaud Héritier
 
[PHP 也有 Day #64] PHP 升級指南
Shengyou Fan
 
Jenkins
Roger Xia
 
Git-flow workflow and pull-requests
Bartosz Kosarzycki
 
Git - An Introduction
Behzad Altaf
 
Jenkins for java world
Ashok Kumar
 
Spring boot introduction
Rasheed Waraich
 
Introduction to Git and GitHub
Vikram SV
 
CICD Pipeline Using Github Actions
Kumar Shìvam
 
Unit testing JavaScript: Jasmine & karma intro
Maurice De Beijer [MVP]
 
Create an architecture for web test automation
Elias Nogueira
 
Write microservice in golang
Bo-Yi Wu
 
Angular.pdf
Jaouad Assabbour
 
Behavior-Driven Development and Automation Testing Using Cucumber Framework W...
KMS Technology
 

Similar to [GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式 (20)

PDF
ASP.NET Core 2.1設計新思維與新發展
江華 奚
 
PPTX
利用Signalr打造即時通訊@Tech day geek
Johnson Gau
 
PPTX
Script with engine
Webrebuild
 
PDF
透過 Windows Azure Mobile Services 開發各平台 Apps
Eric ShangKuan
 
PDF
HTML+COIMOTION 開發跨平台 app
Ben Lue
 
PDF
ASP.NET Core MVC 2.2從開發到測試 - Development & Unit Testing
江華 奚
 
PDF
I os 16
信嘉 陳
 
PDF
Uliweb cheat sheet_0.1
modou li
 
PPTX
一步一步开发Html5 mobile apps
Adam Lu
 
PDF
使用NodeJS构建静态资源管理系统
Frank Xu
 
PDF
Arduino Yún使用Http restful api控制io
吳錫修 (ShyiShiou Wu)
 
PPTX
2023-netconf-deploy-azure-function-with-KEDA-on-aks
Roberson Liou
 
PDF
Berserk js
taobao.com
 
PPTX
微软Bot framework简介
Zhichao Liang
 
PDF
廖雪峰 Saa s ovp
drewz lin
 
PDF
以HTML5和COIMOTION打造跨平台App
Ben Lue
 
ODP
RESTful
PingLun Liao
 
PDF
Entity framework 入門第一課
Sean Lu
 
PDF
Node getting-started
lylijincheng
 
PDF
Kind editor设计思路
taobao.com
 
ASP.NET Core 2.1設計新思維與新發展
江華 奚
 
利用Signalr打造即時通訊@Tech day geek
Johnson Gau
 
Script with engine
Webrebuild
 
透過 Windows Azure Mobile Services 開發各平台 Apps
Eric ShangKuan
 
HTML+COIMOTION 開發跨平台 app
Ben Lue
 
ASP.NET Core MVC 2.2從開發到測試 - Development & Unit Testing
江華 奚
 
I os 16
信嘉 陳
 
Uliweb cheat sheet_0.1
modou li
 
一步一步开发Html5 mobile apps
Adam Lu
 
使用NodeJS构建静态资源管理系统
Frank Xu
 
Arduino Yún使用Http restful api控制io
吳錫修 (ShyiShiou Wu)
 
2023-netconf-deploy-azure-function-with-KEDA-on-aks
Roberson Liou
 
Berserk js
taobao.com
 
微软Bot framework简介
Zhichao Liang
 
廖雪峰 Saa s ovp
drewz lin
 
以HTML5和COIMOTION打造跨平台App
Ben Lue
 
RESTful
PingLun Liao
 
Entity framework 入門第一課
Sean Lu
 
Node getting-started
lylijincheng
 
Kind editor设计思路
taobao.com
 
Ad

More from Shengyou Fan (20)

PDF
[JCConf 2024] Kotlin/Wasm:為 Kotlin 多平台帶來更多可能性
Shengyou Fan
 
PDF
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
Shengyou Fan
 
PDF
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
Shengyou Fan
 
PDF
How I make a podcast website using serverless technology in 2023
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
[COSCUP 2022] Kotlin Collection 遊樂園
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
 
[JCConf 2024] Kotlin/Wasm:為 Kotlin 多平台帶來更多可能性
Shengyou Fan
 
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
Shengyou Fan
 
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
Shengyou Fan
 
How I make a podcast website using serverless technology in 2023
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
 
[COSCUP 2022] Kotlin Collection 遊樂園
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
 
Ad

[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式