项目概览
这个 KMP 项目模板是一个功能完整的跨平台应用,支持以下平台:
- Android - 原生 Android 应用
- iOS - 原生 iOS 应用
- Desktop - JVM 桌面应用 (Windows/macOS/Linux)
核心功能特性
网络请求 - 基于 Ktor 的 HTTP 客户端,支持 JSON 序列化
文件操作 - 跨平台文件选择、保存和下载功能
图片加载 - 使用 Coil 实现跨平台图片加载
导航系统 - 多页面导航,包含底部导航栏
状态管理 - 基于 KMP ViewModel 的响应式状态管理
依赖注入 - 使用 Koin 实现跨平台依赖注入
本地存储 - Token 存储和跨平台数据持久化
响应式布局 - 自适应不同屏幕尺寸的 UI 设计
截图预览
技术架构
1. 项目结构设计
项目采用标准的 KMP 分层架构:
bash
composeApp/
├── src/
│ ├── commonMain/ # 共享代码层
│ │ └── kotlin/ovo/sypw/kmp/template/
│ │ ├── data/ # 数据层
│ │ │ ├── api/ # API 服务
│ │ │ ├── dto/ # 数据传输对象
│ │ │ └── storage/ # 本地存储
│ │ ├── di/ # 依赖注入模块
│ │ ├── domain/ # 业务逻辑层
│ │ ├── presentation/ # 表现层
│ │ │ ├── navigation/# 导航组件
│ │ │ ├── screens/ # 页面组件
│ │ │ └── viewmodel/ # ViewModel
│ │ └── utils/ # 工具类
│ ├── androidMain/ # Android 平台特定代码
│ ├── iosMain/ # iOS 平台特定代码
│ └── desktopMain/ # Desktop 平台特定代码
2. 核心技术栈
网络层实现
项目使用 Ktor Client 实现跨平台网络请求:
kotlin
/**
* HTTP 客户端配置
* 支持跨平台网络请求,包含超时设置、日志记录和 JSON 序列化
*/
object HttpClientConfig {
const val BASE_URL = "" // 在此配置你的 API 基础 URL
/**
* 创建配置好的 HTTP 客户端实例
*/
fun createHttpClient(): HttpClient {
return HttpClient {
install(HttpTimeout) {
requestTimeoutMillis = 20_000
connectTimeoutMillis = 20_000
socketTimeoutMillis = 20_000
}
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.INFO
}
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
isLenient = true
})
}
}
}
}
API 服务层设计
kotlin
/**
* API 测试服务
* 演示各种 HTTP 请求方法的实现
*/
class ApiTestService(private val httpClient: HttpClient) {
/**
* GET 请求示例
*/
suspend fun testGet(): ApiResponse<String> {
return try {
val response = httpClient.get("${BASE_URL}/api/test")
ApiResponse.Success(response.bodyAsText())
} catch (e: Exception) {
ApiResponse.Error(e.message ?: "Unknown error")
}
}
/**
* POST 请求示例
*/
suspend fun testPost(data: Map<String, Any>): ApiResponse<String> {
return try {
val response = httpClient.post("${BASE_URL}/api/test") {
contentType(ContentType.Application.Json)
setBody(data)
}
ApiResponse.Success(response.bodyAsText())
} catch (e: Exception) {
ApiResponse.Error(e.message ?: "Unknown error")
}
}
}
3. 跨平台存储解决方案
项目实现了跨平台的 Token 存储机制:
kotlin
/**
* Token 存储接口
* 定义跨平台的 Token 存储操作
*/
interface TokenStorage {
suspend fun saveToken(token: String)
suspend fun getToken(): String?
suspend fun clearToken()
}
/**
* Token 存储实现
* 基于平台特定的本地存储实现
*/
class TokenStorageImpl(private val localStorage: LocalStorage) : TokenStorage {
/**
* 保存 Token 到本地存储
*/
override suspend fun saveToken(token: String) {
localStorage.putString(TOKEN_KEY, token)
}
/**
* 从本地存储获取 Token
*/
override suspend fun getToken(): String? {
return localStorage.getString(TOKEN_KEY)
}
/**
* 清除本地存储的 Token
*/
override suspend fun clearToken() {
localStorage.remove(TOKEN_KEY)
}
companion object {
private const val TOKEN_KEY = "auth_token"
}
}
4. 平台特定实现 (expect/actual)
项目使用 KMP 的 expect/actual 机制实现平台特定功能:
kotlin
// commonMain - 共享声明
/**
* 本地存储接口声明
* 各平台需要提供具体实现
*/
expect class LocalStorage {
fun putString(key: String, value: String)
fun getString(key: String): String?
fun remove(key: String)
fun clear()
}
// androidMain - Android 实现
/**
* Android 平台的本地存储实现
* 基于 SharedPreferences
*/
actual class LocalStorage(private val context: Context) {
private val prefs = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
actual fun putString(key: String, value: String) {
prefs.edit().putString(key, value).apply()
}
actual fun getString(key: String): String? {
return prefs.getString(key, null)
}
actual fun remove(key: String) {
prefs.edit().remove(key).apply()
}
actual fun clear() {
prefs.edit().clear().apply()
}
}
// iosMain - iOS 实现
/**
* iOS 平台的本地存储实现
* 基于 UserDefaults
*/
actual class LocalStorage {
actual fun putString(key: String, value: String) {
NSUserDefaults.standardUserDefaults.setObject(value, key)
}
actual fun getString(key: String): String? {
return NSUserDefaults.standardUserDefaults.stringForKey(key)
}
actual fun remove(key: String) {
NSUserDefaults.standardUserDefaults.removeObjectForKey(key)
}
actual fun clear() {
val defaults = NSUserDefaults.standardUserDefaults
defaults.dictionaryRepresentation().keys.forEach { key ->
if (key is String) {
defaults.removeObjectForKey(key)
}
}
}
}
5. 依赖注入配置
使用 Koin 实现跨平台依赖注入:
kotlin
/**
* 应用模块配置
* 定义全局依赖注入规则
*/
val appModule = module {
// HTTP 客户端
single { HttpClientConfig.createHttpClient() }
// API 服务
single<ApiTestService> { ApiTestService(get()) }
// 本地存储
single<LocalStorage> {
if (Platform.isAndroid) {
LocalStorage(androidContext())
} else {
LocalStorage()
}
}
// Token 存储
single<TokenStorage> { TokenStorageImpl(get()) }
}
/**
* ViewModel 模块配置
*/
val viewModelModule = module {
factory { ApiTestViewModel(get()) }
factory { FileTestViewModel() }
factory { ImageTestViewModel() }
}
6. UI 层实现
项目使用 Compose Multiplatform 构建跨平台 UI:
kotlin
/**
* 主应用组件
* 应用的根组件,包含导航和主题配置
*/
@Composable
fun App() {
// 初始化 Koin
KoinApplication(application = {
modules(appModule, viewModelModule)
}) {
MaterialTheme {
val navigationManager = rememberNavigationManager()
// 响应式布局处理
ResponsiveLayout {
NavigationHost(
navigationManager = navigationManager,
startDestination = NavigationScreen.Home
) {
// 页面路由配置
composable<NavigationScreen.Home> {
HomeScreen(navigationManager)
}
composable<NavigationScreen.ApiTest> {
ApiTestScreen(navigationManager)
}
composable<NavigationScreen.FileTest> {
FileTestScreen(navigationManager)
}
composable<NavigationScreen.ImageTest> {
ImageTestScreen(navigationManager)
}
}
}
}
}
}
自动化构建与部署
项目集成了完整的 GitHub Actions 自动构建流程,支持多平台自动编译:
构建平台支持
- Android - 自动构建并签名 APK 文件
- Windows - 生成 MSI 安装包和可执行文件
- macOS - 生成 DMG 安装包
- Linux - 生成 DEB 安装包
自动发布流程
yaml
# .github/workflows/build-all-platforms.yml
name: Build All Platforms
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
build-android:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup JDK
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Build Android APK
run: ./gradlew :composeApp:assembleRelease
- name: Sign APK
run: |
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release-key.keystore
jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \
-keystore release-key.keystore \
-storepass "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" \
-keypass "${{ secrets.ANDROID_KEY_PASSWORD }}" \
composeApp/build/outputs/apk/release/composeApp-release-unsigned.apk \
"${{ secrets.ANDROID_KEY_ALIAS }}"
实际应用场景
1. 企业级应用开发
这个模板特别适合企业级应用开发,提供了:
- 完整的网络请求封装
- 安全的 Token 存储机制
- 跨平台的文件操作能力
- 现代化的 UI 设计
2. 快速原型开发
对于需要快速验证想法的项目,这个模板提供了:
- 开箱即用的基础功能
- 完整的测试页面
- 自动化构建流程
3. 学习 KMP 开发
对于想要学习 KMP 开发的开发者,这个项目提供了:
- 最佳实践示例
- 完整的架构设计
- 详细的代码注释
性能优化与最佳实践
1. 内存管理
kotlin
/**
* ViewModel 基类
* 提供统一的生命周期管理和资源清理
*/
abstract class BaseViewModel : ViewModel() {
protected val viewModelScope = CoroutineScope(
SupervisorJob() + Dispatchers.Main.immediate
)
/**
* 清理资源,防止内存泄漏
*/
override fun onCleared() {
super.onCleared()
viewModelScope.cancel()
}
}
2. 网络请求优化
kotlin
/**
* 网络请求结果封装
* 统一处理成功和错误状态
*/
sealed class ApiResponse<out T> {
data class Success<T>(val data: T) : ApiResponse<T>()
data class Error(val message: String) : ApiResponse<Nothing>()
object Loading : ApiResponse<Nothing>()
}
3. 响应式设计
kotlin
/**
* 响应式布局组件
* 根据屏幕尺寸自动调整布局
*/
@Composable
fun ResponsiveLayout(
content: @Composable () -> Unit
) {
BoxWithConstraints {
val isCompact = maxWidth < 600.dp
CompositionLocalProvider(
LocalResponsiveInfo provides ResponsiveInfo(
isCompact = isCompact,
screenWidth = maxWidth,
screenHeight = maxHeight
)
) {
content()
}
}
}
未来发展方向
- Web 平台支持 - 计划添加 Kotlin/JS 和 Kotlin/Wasm 支持
- 更多 UI 组件 - 扩展组件库,提供更丰富的 UI 元素
- 数据库集成 - 集成 SQLDelight 实现跨平台数据库操作
- 推送通知 - 添加跨平台推送通知支持
- 性能监控 - 集成性能监控和崩溃报告
总结
Kotlin Multiplatform 为跨平台开发带来了新的可能性。通过这个项目模板,开发者可以:
- 快速上手 - 开箱即用的完整解决方案
- 学习最佳实践 - 现代化的架构设计和代码规范
- 灵活扩展 - 模块化设计,易于定制和扩展
- 一次开发,多端部署 - 真正实现代码复用
随着 KMP 生态的不断完善,相信跨平台开发将成为移动应用开发的主流选择。这个项目模板将持续更新,为开发者提供更好的开发体验。
项目地址
GitHub 仓库 : sypw233/KMPTemplate