当前位置: 首页 > news >正文

Android KMP初探

Android KMP初探

前言:

最近线上听了Kotlin官网举行的KMP会议,感觉听神奇的,于是就把官方demo下载下来尝试了一下,下载插件和所需要的依赖都用了很久,但是发现里面的代码很少,于是尝试自己手写了一下,遇到了不少问题,这里记录一下.

1.定义:

Kotlin Multiplatform 技术可为多种平台创建应用程序并在平台之间高效重用代码,同时保留原生编程的优势。您的应用程序将在 iOS、Android、macOS、Windows、Linux 等平台上运行。

Compose Multiplatform 是 JetBrains 推出的声明式 UI 框架,可让您为 Android、iOS、桌面和 Web 开发共享 UI。将 Compose Multiplatform 集成到 Kotlin Multiplatform 项目中,更快交付应用和功能,而无需维护多个 UI 实现。

在这里插入图片描述

2.适合各类项目:

在这里插入图片描述

3.优点

使用 Compose Multiplatform 只需构建一次 UI

Compose Multiplatform 是一个基于 Kotlin 和 Jetpack Compose 的声明式框架,用于在 Android、iOS、Web 和桌面(通过 JVM)之间共享 UI。

加速 UI 开发

轻松同步多个 UI 实现,让应用更快交付到用户手中。

组件级重用

使用可在所有目标平台上使用的可自定义微件构建您的 UI。使用预设主题快速开始,或自行创建细节可精确至像素的视觉风格。

根据需要使用原生组件

轻松使用原生 UI 微件或将共享 UI 嵌入现有原生应用。

4.需要几个硬性条件:

在使用 KMP + Compose 进行开发时,需要以下条件,由于没有mac设备就暂时不跑ios项目,跑Android项目也是一样的,不用过于纠结.

  • Mac电脑(苹果开发必须mac)
  • Android Studio
  • Xcode
  • 配置 ios 开发环境(cocoapods、开发者账号等)

5.项目结构:

################## 目录结构说明 ##################
```
.
├── README.md
├── app - 主应用
│   ├── build.gradle.kts
│   ├── MainActivity
│   ├── libs
│   └── src
├── commonMain -公共组件
│   ├── app
│   ├── Greeting
│   ├── Platform
├── appleMain - ios平台
│   ├── getPlatform
├── iosMain - ios业务代码
│   ├── MainViewController
│   └── IOSPlatform
├── gradle
│   └── wrapper
├── gradle.properties
├── gradlew
├── gradlew.bat
├── build.gradle.kts
├── local.properties
└── settings.gradle.kts
################## 目录结构说明 ##################

6.App目录下的build.gradle.kts配置:

import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.kotlin.gradle.idea.tcs.extras.isCommonizedKey
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {alias(libs.plugins.kotlinMultiplatform)alias(libs.plugins.androidApplication)alias(libs.plugins.composeMultiplatform)alias(libs.plugins.composeCompiler)
}
kotlin {androidTarget {@OptIn(ExperimentalKotlinGradlePluginApi::class)compilerOptions {jvmTarget.set(JvmTarget.JVM_11)}}listOf(iosX64(),iosArm64(),iosSimulatorArm64()).forEach { iosTarget ->iosTarget.binaries.framework {baseName = "ComposeApp"isStatic = true}}sourceSets {androidMain.dependencies {implementation(compose.preview)implementation(libs.androidx.activity.compose)}commonMain.dependencies {implementation(compose.runtime)implementation(compose.foundation)implementation(compose.material)implementation(compose.ui)implementation(compose.components.resources)implementation(compose.components.uiToolingPreview)implementation(libs.androidx.lifecycle.viewmodel)implementation(libs.androidx.lifecycle.runtime.compose)implementation(libs.androidx.constraintlayout)}}
}android {namespace = "com.cloud.androidkmpdemo"compileSdk = libs.versions.android.compileSdk.get().toInt()defaultConfig {applicationId = "com.cloud.androidkmpdemo"minSdk = libs.versions.android.minSdk.get().toInt()targetSdk = libs.versions.android.targetSdk.get().toInt()versionCode = 1versionName = "1.0"}packaging {resources {excludes += "/META-INF/{AL2.0,LGPL2.1}"}}buildTypes {getByName("release") {isMinifyEnabled = false}}compileOptions {sourceCompatibility = JavaVersion.VERSION_11targetCompatibility = JavaVersion.VERSION_11}compose.desktop {application {mainClass = "com.example.composeApp.MainKt"nativeDistributions {targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)packageName = "com.cloud.kmpdemo"packageVersion = "1.0.0"// 描述应用程序description = "A simple demo for KMP"// 版权信息copyright = "© 2024 My Name. All rights reserved."// 厂商信息vendor = "Example vendor"// 设置许可证文件licenseFile.set(project.file("LICENSE.txt"))}}}
}
dependencies {debugImplementation(compose.uiTooling)
}

7.项目的build.gradle.kts配置:

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {alias(libs.plugins.androidApplication) apply falsealias(libs.plugins.androidLibrary) apply falsealias(libs.plugins.composeMultiplatform) apply falsealias(libs.plugins.composeCompiler) apply falsealias(libs.plugins.kotlinMultiplatform) apply falsealias(libs.plugins.jetbrainsKotlinAndroid) apply false
}

8.统一的依赖配置:

[versions]
agp = "8.5.2"
android-compileSdk = "34"
android-minSdk = "24"
android-targetSdk = "34"
androidx-activityCompose = "1.9.3"
androidx-appcompat = "1.7.0"
androidx-constraintlayout = "2.2.0"
androidx-core-ktx = "1.15.0"
androidx-espresso-core = "3.6.1"
androidx-lifecycle = "2.8.4"
androidx-material = "1.12.0"
androidx-test-junit = "1.2.1"
compose-multiplatform = "1.7.0"
junit = "4.13.2"
kotlin = "2.1.0"
kotlinVersion = "1.9.0"[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" }
androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-espresso-core" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" }
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
androidLibrary = { id = "com.android.library", version.ref = "agp" }
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" }

9.公共组件:

9.1 Platform接口:

interface Platform {val name: String
}expect fun getPlatform(): Platform

9.2 Greeting类:

class Greeting {private val platform = getPlatform()fun greet(): String {return "Hello, ${platform.name}!"}
}

9.3 App类:

package com.cloud.kmpdemoimport androidkmpdemo.app.generated.resources.Res
import androidkmpdemo.app.generated.resources.compose_multiplatform
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.AlertDialog
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.ui.tooling.preview.Preview@Composable
@Preview
fun App() {MaterialTheme {var showContent by remember { mutableStateOf(false) }var showDialog by remember { mutableStateOf(false) }Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {Button(onClick = { showContent = !showContent }) {Text("Click me")}Button(onClick = { showDialog = !showDialog }) {Text("show Dialog")}AnimatedVisibility(showContent) {val greeting = remember { Greeting().greet() }Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {Image(painterResource(Res.drawable.compose_multiplatform), null)Text("Compose: $greeting")}}AnimatedVisibility(showDialog) {Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {AlertDialogSample()}}}}
}@Composable
@Preview
fun AlertDialogSample(){val dialog = remember { mutableStateOf(true) }if(dialog.value){AlertDialog(onDismissRequest = { dialog.value = false},title = { Text(text = "开启位置服务")},text = { Text(text = "这将意味着,我们会给您提供精准的位置服务,并且您将接受关于您订阅的位置信息。") },confirmButton = {TextButton(onClick = { dialog.value = false}){Text(text = "同意")}},dismissButton = {TextButton(onClick = {dialog.value = false}){Text(text = "取消")}})}
}

10.Android代码:

本文我在原来的基础上加入了一个弹框示例AlertDialogSample()

package com.cloud.kmpdemoimport android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Previewclass MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent(){App()}}
}@Preview
@Composable
fun AppAndroidPreview() {App()
}@Preview
@Composable
fun DialogAndroidPreview() {//显示dialogAlertDialogSample()
}
package com.cloud.kmpdemoimport android.os.Build/*** 获取平台版本信息*/
class AndroidPlatform : Platform {override val name: String = "Android ${Build.VERSION.SDK_INT}"
}actual fun getPlatform(): Platform = AndroidPlatform()

11.ios平台代码:

package org.example.kmpdemoimport androidx.compose.ui.window.ComposeUIViewController
import com.cloud.kmpdemo.Appfun MainViewController() = ComposeUIViewController { App() }
package org.example.kmpdemoimport com.cloud.kmpdemo.Platform
import platform.UIKit.UIDeviceclass IOSPlatform: Platform {override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}actual fun getPlatform(): Platform = IOSPlatform()

12.ios业务代码:

import UIKit
import SwiftUI
import ComposeAppstruct ComposeView: UIViewControllerRepresentable {func makeUIViewController(context: Context) -> UIViewController {MainViewControllerKt.MainViewController()}func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}struct ContentView: View {var body: some View {ComposeView().ignoresSafeArea(.keyboard) // Compose has own keyboard handler}
}
import SwiftUI@main
struct iOSApp: App {var body: some Scene {WindowGroup {ContentView()}}
}

info.plist:

和Android的build.gradle配置文件一样,都是管理依赖和第三方库的.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict><key>CFBundleDevelopmentRegion</key><string>$(DEVELOPMENT_LANGUAGE)</string><key>CFBundleExecutable</key><string>$(EXECUTABLE_NAME)</string><key>CFBundleIdentifier</key><string>$(PRODUCT_BUNDLE_IDENTIFIER)</string><key>CFBundleInfoDictionaryVersion</key><string>6.0</string><key>CFBundleName</key><string>$(PRODUCT_NAME)</string><key>CFBundlePackageType</key><string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string><key>CFBundleShortVersionString</key><string>1.0</string><key>CFBundleVersion</key><string>1</string><key>LSRequiresIPhoneOS</key><true/><key>CADisableMinimumFrameDurationOnPhone</key><true/><key>UIApplicationSceneManifest</key><dict><key>UIApplicationSupportsMultipleScenes</key><false/></dict><key>UILaunchScreen</key><dict/><key>UIRequiredDeviceCapabilities</key><array><string>armv7</string></array><key>UISupportedInterfaceOrientations</key><array><string>UIInterfaceOrientationPortrait</string><string>UIInterfaceOrientationLandscapeLeft</string><string>UIInterfaceOrientationLandscapeRight</string></array><key>UISupportedInterfaceOrientations~ipad</key><array><string>UIInterfaceOrientationPortrait</string><string>UIInterfaceOrientationPortraitUpsideDown</string><string>UIInterfaceOrientationLandscapeLeft</string><string>UIInterfaceOrientationLandscapeRight</string></array>
</dict>
</plist>

13.运行效果如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

14.总结:

以上就是今天的内容,KMP初探,根据不同平台的设备显示不同类型和版本号,代码非常少,再也没有创建xml的烦恼,MainActivity也不需要加载activity_main布局,简直不要太爽,当然KMP如果不熟悉的话跑起来很费劲,我是从0到1自己全部重新撸了一遍,包含Android和IOS两个平台,build插件配置等等,这里我没有Mac环境就不演示iOS的效果了.如果只是单纯写代码看效果没有太大的意义,需要搞清楚整个运行过程和实现原理,在后面进行学习和开发过程中就会事半功倍。

15.项目源码地址:

https://gitee.com/jackning_admin/android-kmpdemo


http://www.mrgr.cn/news/92110.html

相关文章:

  • Java 大视界 -- 总结与展望:Java 大数据领域的新征程与无限可能(96)
  • 【大模型系列篇】DeepSeek-R1如何通过强化学习有效提升大型语言模型的推理能力?
  • Spring Boot 日志管理(官网文档解读)
  • VSCode自定义快捷键和添加自定义快捷键按键到状态栏
  • 低功耗设计:(3)架构级优化
  • 被裁20240927 --- WSL-Ubuntu20.04安装cuda、cuDNN、tensorRT
  • RoCEv2 高性能传输协议与 Lossless 无损网络
  • Deepseek快速做PPT
  • 【前端】react大全一本通
  • 第9章:LangChain让大模型结构化输出
  • 计算机网络————(一)HTTP讲解
  • Spring Boot 应用(官网文档解读)
  • 本地部署AI模型 --- DeepSeek(二)---更新中
  • 【数据结构】快指针和慢指针
  • 第1章:LangChain4j的聊天与语言模型
  • Orange 单体架构 - 快速启动
  • 什么是向量化?ElasticSearch如何存储向量?
  • Python爬虫-破解字体加密技术
  • STM32基础篇(二)------GPIO
  • 前端面试真题 2025最新版