SlideShare a Scribd company logo
1 of 62
Download to read offline
范聖佑
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

【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All ThingsUnityTechnologiesJapan002
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?Moriharu Ohzu
 
初探 Kotlin Multiplatform
初探 Kotlin Multiplatform初探 Kotlin Multiplatform
初探 Kotlin MultiplatformShengyou Fan
 
[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang)
[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang) [Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang)
[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang) Johnny Sung
 
Quine・難解プログラミングについて
Quine・難解プログラミングについてQuine・難解プログラミングについて
Quine・難解プログラミングについてmametter
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率Shengyou Fan
 
C#とILとネイティブと
C#とILとネイティブとC#とILとネイティブと
C#とILとネイティブと信之 岩永
 
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017Kohei Saito
 
async/await のしくみ
async/await のしくみasync/await のしくみ
async/await のしくみ信之 岩永
 
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹Johnny Sung
 
[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南Shengyou Fan
 
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリームC# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム信之 岩永
 
brainfuckを吐く自作言語bf-reusable
brainfuckを吐く自作言語bf-reusablebrainfuckを吐く自作言語bf-reusable
brainfuckを吐く自作言語bf-reusableroodni
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
Introduction to Initramfs - Initramfs-tools and Dracut
Introduction to Initramfs - Initramfs-tools and DracutIntroduction to Initramfs - Initramfs-tools and Dracut
Introduction to Initramfs - Initramfs-tools and DracutTaisuke Yamada
 
最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!Yuji Nojima
 
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)ShogoOkazaki
 
C#でわかる こわくないMonad
C#でわかる こわくないMonadC#でわかる こわくないMonad
C#でわかる こわくないMonadKouji Matsui
 
Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Scott Wlaschin
 

What's hot (20)

【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
 
初探 Kotlin Multiplatform
初探 Kotlin Multiplatform初探 Kotlin Multiplatform
初探 Kotlin Multiplatform
 
[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang)
[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang) [Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang)
[Golang] 以 Mobile App 工程師視角,帶你進入 Golang 的世界 (Introduction of GoLang)
 
Quine・難解プログラミングについて
Quine・難解プログラミングについてQuine・難解プログラミングについて
Quine・難解プログラミングについて
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
 
C#とILとネイティブと
C#とILとネイティブとC#とILとネイティブと
C#とILとネイティブと
 
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
 
async/await のしくみ
async/await のしくみasync/await のしくみ
async/await のしくみ
 
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
 
[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南[PHP 也有 Day #64] PHP 升級指南
[PHP 也有 Day #64] PHP 升級指南
 
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリームC# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム
 
brainfuckを吐く自作言語bf-reusable
brainfuckを吐く自作言語bf-reusablebrainfuckを吐く自作言語bf-reusable
brainfuckを吐く自作言語bf-reusable
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
Introduction to Initramfs - Initramfs-tools and Dracut
Introduction to Initramfs - Initramfs-tools and DracutIntroduction to Initramfs - Initramfs-tools and Dracut
Introduction to Initramfs - Initramfs-tools and Dracut
 
最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!
 
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
 
Docker Compose 徹底解説
Docker Compose 徹底解説Docker Compose 徹底解説
Docker Compose 徹底解説
 
C#でわかる こわくないMonad
C#でわかる こわくないMonadC#でわかる こわくないMonad
C#でわかる こわくないMonad
 
Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)
 

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

2016輕鬆開發自有網路地圖工作坊 進階班 0701
2016輕鬆開發自有網路地圖工作坊 進階班 07012016輕鬆開發自有網路地圖工作坊 進階班 0701
2016輕鬆開發自有網路地圖工作坊 進階班 0701family
 
HTML+COIMOTION 開發跨平台 app
HTML+COIMOTION 開發跨平台 appHTML+COIMOTION 開發跨平台 app
HTML+COIMOTION 開發跨平台 appBen Lue
 
透過 Windows Azure Mobile Services 開發各平台 Apps
透過 Windows Azure Mobile Services 開發各平台 Apps透過 Windows Azure Mobile Services 開發各平台 Apps
透過 Windows Azure Mobile Services 開發各平台 AppsEric ShangKuan
 
利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geekJohnson Gau
 
前端MVC之backbone
前端MVC之backbone前端MVC之backbone
前端MVC之backboneJerry Xie
 
Script with engine
Script with engineScript with engine
Script with engineWebrebuild
 
ASP.NET Core 2.1設計新思維與新發展
ASP.NET  Core 2.1設計新思維與新發展ASP.NET  Core 2.1設計新思維與新發展
ASP.NET Core 2.1設計新思維與新發展江華 奚
 
Arduino Yún使用Http restful api控制io
Arduino Yún使用Http restful api控制ioArduino Yún使用Http restful api控制io
Arduino Yún使用Http restful api控制io吳錫修 (ShyiShiou Wu)
 
Windows Mobile Widget 開發
Windows Mobile Widget 開發Windows Mobile Widget 開發
Windows Mobile Widget 開發Chui-Wen Chiu
 
Introduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDKIntroduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDK維佋 唐
 
Behind Tetris5
Behind Tetris5Behind Tetris5
Behind Tetris5Junwen Sun
 
Silverlight 2.0 完全新手學堂,基礎入門 10 大招
Silverlight 2.0 完全新手學堂,基礎入門 10 大招Silverlight 2.0 完全新手學堂,基礎入門 10 大招
Silverlight 2.0 完全新手學堂,基礎入門 10 大招Chui-Wen Chiu
 
唐俊开-Html5 mobile web app浅谈
唐俊开-Html5 mobile web app浅谈唐俊开-Html5 mobile web app浅谈
唐俊开-Html5 mobile web app浅谈Webrebuild
 
Html5 mobile web app浅谈
Html5 mobile web app浅谈Html5 mobile web app浅谈
Html5 mobile web app浅谈sankyu Tang
 
HTML5 介绍
HTML5 介绍HTML5 介绍
HTML5 介绍S S
 
使用NodeJS构建静态资源管理系统
使用NodeJS构建静态资源管理系统使用NodeJS构建静态资源管理系统
使用NodeJS构建静态资源管理系统Frank Xu
 
Page Object in XCUITest
Page Object in XCUITestPage Object in XCUITest
Page Object in XCUITestJz Chang
 
怎樣在 Flutter app 中使用 Google Maps
怎樣在 Flutter app 中使用 Google Maps怎樣在 Flutter app 中使用 Google Maps
怎樣在 Flutter app 中使用 Google MapsWeizhong Yang
 
javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当裕波 周
 
JavaScript Advanced Skill
JavaScript Advanced SkillJavaScript Advanced Skill
JavaScript Advanced Skillfirestoke
 

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

2016輕鬆開發自有網路地圖工作坊 進階班 0701
2016輕鬆開發自有網路地圖工作坊 進階班 07012016輕鬆開發自有網路地圖工作坊 進階班 0701
2016輕鬆開發自有網路地圖工作坊 進階班 0701
 
HTML+COIMOTION 開發跨平台 app
HTML+COIMOTION 開發跨平台 appHTML+COIMOTION 開發跨平台 app
HTML+COIMOTION 開發跨平台 app
 
透過 Windows Azure Mobile Services 開發各平台 Apps
透過 Windows Azure Mobile Services 開發各平台 Apps透過 Windows Azure Mobile Services 開發各平台 Apps
透過 Windows Azure Mobile Services 開發各平台 Apps
 
利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek
 
前端MVC之backbone
前端MVC之backbone前端MVC之backbone
前端MVC之backbone
 
Script with engine
Script with engineScript with engine
Script with engine
 
ASP.NET Core 2.1設計新思維與新發展
ASP.NET  Core 2.1設計新思維與新發展ASP.NET  Core 2.1設計新思維與新發展
ASP.NET Core 2.1設計新思維與新發展
 
Arduino Yún使用Http restful api控制io
Arduino Yún使用Http restful api控制ioArduino Yún使用Http restful api控制io
Arduino Yún使用Http restful api控制io
 
Windows Mobile Widget 開發
Windows Mobile Widget 開發Windows Mobile Widget 開發
Windows Mobile Widget 開發
 
Introduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDKIntroduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDK
 
Behind Tetris5
Behind Tetris5Behind Tetris5
Behind Tetris5
 
Silverlight 2.0 完全新手學堂,基礎入門 10 大招
Silverlight 2.0 完全新手學堂,基礎入門 10 大招Silverlight 2.0 完全新手學堂,基礎入門 10 大招
Silverlight 2.0 完全新手學堂,基礎入門 10 大招
 
唐俊开-Html5 mobile web app浅谈
唐俊开-Html5 mobile web app浅谈唐俊开-Html5 mobile web app浅谈
唐俊开-Html5 mobile web app浅谈
 
Html5 mobile web app浅谈
Html5 mobile web app浅谈Html5 mobile web app浅谈
Html5 mobile web app浅谈
 
HTML5 介绍
HTML5 介绍HTML5 介绍
HTML5 介绍
 
使用NodeJS构建静态资源管理系统
使用NodeJS构建静态资源管理系统使用NodeJS构建静态资源管理系统
使用NodeJS构建静态资源管理系统
 
Page Object in XCUITest
Page Object in XCUITestPage Object in XCUITest
Page Object in XCUITest
 
怎樣在 Flutter app 中使用 Google Maps
怎樣在 Flutter app 中使用 Google Maps怎樣在 Flutter app 中使用 Google Maps
怎樣在 Flutter app 中使用 Google Maps
 
javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当
 
JavaScript Advanced Skill
JavaScript Advanced SkillJavaScript Advanced Skill
JavaScript Advanced Skill
 

More from Shengyou Fan

[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能Shengyou Fan
 
How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023Shengyou Fan
 
Using the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseUsing the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseShengyou Fan
 
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具Shengyou Fan
 
Composer 經典食譜
Composer 經典食譜Composer 經典食譜
Composer 經典食譜Shengyou Fan
 
老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS AggregatorShengyou Fan
 
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON APIShengyou Fan
 
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin ServerlessShengyou Fan
 
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置Shengyou Fan
 
用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手Shengyou Fan
 
Kotlin 讀書會第三梯次第一章
Kotlin 讀書會第三梯次第一章Kotlin 讀書會第三梯次第一章
Kotlin 讀書會第三梯次第一章Shengyou Fan
 
用 OPENRNDR 將 Chatbot 訊息視覺化
用 OPENRNDR 將 Chatbot 訊息視覺化用 OPENRNDR 將 Chatbot 訊息視覺化
用 OPENRNDR 將 Chatbot 訊息視覺化Shengyou Fan
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代Shengyou Fan
 
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史Shengyou Fan
 
Ktor 部署攻略 - 老派 Fat Jar 大法
Ktor 部署攻略 - 老派 Fat Jar 大法Ktor 部署攻略 - 老派 Fat Jar 大法
Ktor 部署攻略 - 老派 Fat Jar 大法Shengyou Fan
 
以 Kotlin 快速打造 Mobile Backend
以 Kotlin 快速打造 Mobile Backend以 Kotlin 快速打造 Mobile Backend
以 Kotlin 快速打造 Mobile BackendShengyou Fan
 
Kotlin 一條龍 - 打造全平台應用
Kotlin 一條龍 - 打造全平台應用Kotlin 一條龍 - 打造全平台應用
Kotlin 一條龍 - 打造全平台應用Shengyou Fan
 
[HKOSCon 2020] Build an api service using ktor rapidly
[HKOSCon 2020] Build an api service using ktor rapidly[HKOSCon 2020] Build an api service using ktor rapidly
[HKOSCon 2020] Build an api service using ktor rapidlyShengyou Fan
 
用 Kotlin 做自動化工具
用 Kotlin 做自動化工具用 Kotlin 做自動化工具
用 Kotlin 做自動化工具Shengyou Fan
 

More from Shengyou Fan (20)

[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
 
How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023
 
Using the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseUsing the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your Database
 
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
[COSCUP 2022] 讓黑畫面再次偉大 - 用 PHP 寫 CLI 工具
 
Composer 經典食譜
Composer 經典食譜Composer 經典食譜
Composer 經典食譜
 
老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具
 
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
 
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
 
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
 
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
 
用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手
 
Kotlin 讀書會第三梯次第一章
Kotlin 讀書會第三梯次第一章Kotlin 讀書會第三梯次第一章
Kotlin 讀書會第三梯次第一章
 
用 OPENRNDR 將 Chatbot 訊息視覺化
用 OPENRNDR 將 Chatbot 訊息視覺化用 OPENRNDR 將 Chatbot 訊息視覺化
用 OPENRNDR 將 Chatbot 訊息視覺化
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
 
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
[PHP 也有 Day] 垃圾留言守城記 - 用 Laravel 阻擋 SPAM 留言的奮鬥史
 
Ktor 部署攻略 - 老派 Fat Jar 大法
Ktor 部署攻略 - 老派 Fat Jar 大法Ktor 部署攻略 - 老派 Fat Jar 大法
Ktor 部署攻略 - 老派 Fat Jar 大法
 
以 Kotlin 快速打造 Mobile Backend
以 Kotlin 快速打造 Mobile Backend以 Kotlin 快速打造 Mobile Backend
以 Kotlin 快速打造 Mobile Backend
 
Kotlin 一條龍 - 打造全平台應用
Kotlin 一條龍 - 打造全平台應用Kotlin 一條龍 - 打造全平台應用
Kotlin 一條龍 - 打造全平台應用
 
[HKOSCon 2020] Build an api service using ktor rapidly
[HKOSCon 2020] Build an api service using ktor rapidly[HKOSCon 2020] Build an api service using ktor rapidly
[HKOSCon 2020] Build an api service using ktor rapidly
 
用 Kotlin 做自動化工具
用 Kotlin 做自動化工具用 Kotlin 做自動化工具
用 Kotlin 做自動化工具
 

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