开箱即用的Kotlin Multiplatform 跨平台开发模板:覆盖网络/存储/UI/DI/CI工具链

项目概览

这个 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()
        }
    }
}

未来发展方向

  1. Web 平台支持 - 计划添加 Kotlin/JS 和 Kotlin/Wasm 支持
  2. 更多 UI 组件 - 扩展组件库,提供更丰富的 UI 元素
  3. 数据库集成 - 集成 SQLDelight 实现跨平台数据库操作
  4. 推送通知 - 添加跨平台推送通知支持
  5. 性能监控 - 集成性能监控和崩溃报告

总结

Kotlin Multiplatform 为跨平台开发带来了新的可能性。通过这个项目模板,开发者可以:

  • 快速上手 - 开箱即用的完整解决方案
  • 学习最佳实践 - 现代化的架构设计和代码规范
  • 灵活扩展 - 模块化设计,易于定制和扩展
  • 一次开发,多端部署 - 真正实现代码复用

随着 KMP 生态的不断完善,相信跨平台开发将成为移动应用开发的主流选择。这个项目模板将持续更新,为开发者提供更好的开发体验。

项目地址

GitHub 仓库 : sypw233/KMPTemplate

相关推荐
丶皮蛋菌41 分钟前
关于OC与Swift内存管理的解惑
ios
移动开发者1号1 小时前
ReLinker优化So库加载指南
android·kotlin
杂雾无尘2 小时前
掌握生死时速:苹果应用加急审核全攻略!
ios·swift·apple
HarderCoder2 小时前
Swift 6.2 中的 `@concurrent`
ios·swift
移动开发者1号2 小时前
剖析 Systrace:定位 UI 线程阻塞的终极指南
android·kotlin
移动开发者1号2 小时前
深入解析内存抖动:定位与修复实战(Kotlin版)
android·kotlin
Digitally4 小时前
如何将文件从 iPhone 传输到 Android(新指南)
android·ios·iphone
YungFan5 小时前
iOS26适配指南之通知
ios·swift
Try0215 小时前
Kotlin中Lambda表达式妙用:超越基础语法的力量
kotlin
木叶丸5 小时前
跨平台方案该如何选择?
android·前端·ios