Giới thiệu Compose Multiplatform
Compose Multiplatform cho phép bạn chia sẻ cả UI lẫn logic giữa các nền tảng bằng Jetpack Compose.
Compose Multiplatform là gì?
┌─────────────────────────────────────────┐
│ Compose Multiplatform UI │
│ (Button, Text, Column, Row, ...) │
├─────────────────────────────────────────┤
│ Kotlin Multiplatform (KMP) │
│ (Business logic, networking, DB) │
├───────────┬───────────┬─────────────────┤
│ Android │ iOS │ Desktop/Web │
└───────────┴───────────┴─────────────────┘Deployment targets
| Platform | Technology | Status |
|---|---|---|
| Android | Jetpack Compose | ✅ Stable |
| iOS | Skiko/UIKit | ✅ Stable |
| Desktop | Skiko/JVM | ✅ Stable |
| Web (Wasm) | Wasm/Canvas | 🧪 Alpha |
So sánh với Flutter và React Native
| Compose Multiplatform | Flutter | React Native | |
|---|---|---|---|
| Language | Kotlin | Dart | JavaScript |
| UI Engine | Skia + Native | Skia | Native bridge |
| Learning curve | Dễ nếu biết Compose | Mới | Dễ nếu biết React |
| Native integration | Excellent | Good | Moderate |
| Performance | Near-native | Excellent | Good |
| Ecosystem | Growing | Large | Very large |
Composable hoạt động như thế nào trên iOS?
1. Compile flow
Kotlin Code
↓
Kotlin/Native Compiler
↓
iOS Framework (.framework)
↓
Swift/Obj-C Integration
↓
iOS App2. Rendering
Compose Multiplatform sử dụng Skia để render UI giống nhau trên mọi platform:
- Skia là graphics library của Google (cũng dùng trong Chrome, Android)
- UI được vẽ pixel-by-pixel, đảm bảo consistency
3. Tích hợp với UIKit
// iOS App có thể wrap Compose UI trong UIViewController
import ComposeApp
struct ContentView: View {
var body: some View {
ComposeView()
}
}Bắt đầu với Compose Multiplatform
Tạo project từ Wizard
- Truy cập https://kmp.jetbrains.com/
- Chọn Compose Multiplatform Application
- Chọn platforms: Android, iOS, Desktop (optional)
- Download và mở trong Android Studio
Cấu trúc UI module
composeApp/src/
├── commonMain/kotlin/
│ ├── App.kt # Root composable
│ ├── theme/
│ │ ├── Theme.kt
│ │ └── Color.kt
│ ├── ui/
│ │ ├── screen/
│ │ │ ├── HomeScreen.kt
│ │ │ └── DetailScreen.kt
│ │ └── component/
│ │ ├── Button.kt
│ │ └── Card.kt
│ └── navigation/
│ └── Navigation.kt
├── androidMain/kotlin/
│ └── MainActivity.kt
└── iosMain/kotlin/
└── MainViewController.ktCompose Multiplatform vs Jetpack Compose
Hầu hết code Jetpack Compose hoạt động ngay trong Compose Multiplatform:
✅ Hoạt động như nhau
// Các composables cơ bản
Text("Hello")
Button(onClick = {}) { Text("Click") }
Column { ... }
Row { ... }
Box { ... }
LazyColumn { ... }
// State management
var count by remember { mutableStateOf(0) }
val state by viewModel.state.collectAsState()
// Material 3
MaterialTheme { ... }
Card { ... }
Scaffold { ... }⚠️ Cần thay đổi nhỏ
// Jetpack Compose (Android only)
import androidx.compose.ui.res.painterResource
// Compose Multiplatform
import org.jetbrains.compose.resources.painterResource
import myapp.composeapp.generated.resources.Res
import myapp.composeapp.generated.resources.my_image
Image(
painter = painterResource(Res.drawable.my_image),
contentDescription = null
)❌ Không có sẵn (cần expect/actual)
- Camera
- Sensors
- Platform-specific APIs
- Some Material 3 components (adaptive)
Ví dụ: App đơn giản
// commonMain/App.kt
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
@Composable
fun App() {
MaterialTheme {
var count by remember { mutableStateOf(0) }
Surface(modifier = Modifier.fillMaxSize()) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "Count: $count",
style = MaterialTheme.typography.headlineLarge
)
Spacer(Modifier.height(16.dp))
Button(onClick = { count++ }) {
Text("Increment")
}
}
}
}
}Code này chạy identical trên Android, iOS, và Desktop!
Platform-specific entry points
Android - MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
App()
}
}
}iOS - MainViewController.kt
fun MainViewController() = ComposeUIViewController { App() }Desktop - main.kt
fun main() = application {
Window(
onCloseRequest = ::exitApplication,
title = "My App"
) {
App()
}
}Resources trong Compose Multiplatform
Setup
// build.gradle.kts
compose.resources {
publicResClass = true
packageOfResClass = "com.example.myapp.resources"
generateResClass = always
}Thêm resources
composeApp/src/commonMain/composeResources/
├── drawable/
│ └── logo.png
├── font/
│ └── roboto.ttf
└── values/
└── strings.xmlSử dụng
import myapp.composeapp.generated.resources.Res
import myapp.composeapp.generated.resources.logo
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
@Composable
fun LogoImage() {
Image(
painter = painterResource(Res.drawable.logo),
contentDescription = "Logo"
)
}📝 Tóm tắt
| Khái niệm | Mô tả |
|---|---|
| Compose Multiplatform | UI framework chung cho các platforms |
| commonMain | Code UI chạy trên tất cả platforms |
| ComposeUIViewController | Entry point cho iOS |
| Res | Type-safe resources |
| Skia | Rendering engine |
Khi nào dùng Compose Multiplatform?
✅ Phù hợp:
- App cần UI giống nhau trên Android/iOS
- Team đã biết Jetpack Compose
- App không cần native UI phức tạp
⚠️ Cân nhắc:
- Cần native UI đặc thù (Maps, Camera UI, …)
- Team chưa biết Kotlin/Compose
Tiếp theo
Học cách Xây dựng UI chung với Compose Multiplatform.
Last updated on