KMM初探

什么是KMM?

在开始使用 KMM 之前,您需要了解 Kotlin。

KMM 全称:Kotlin Multiplatform Mobile)是一个用于跨平台移动开发的 SDK,相比于其他跨平台框架,KMM是原生UI+逻辑共享的理念,由KMM封装成Android(Kotlin/JVM)的aar和iOS(Kotlin/Native)的framework,再提供给View层进行调用。

a45a47064c5aab78124a5e9c53a807bf.jpeg

Kotlin Multiplatform Mobile

KMM使用Kotlin 的多平台功能,您可以使用 Kotlin 语言和技术栈,开发一套可以在多平台之间共享的代码库,用来构建统一的代码逻辑,而不用针对各个平台都去实现自己的一套。

0cd32194d2a9b8be6457fbe39b37ea20.png

Kotlin多平台功能

环境工具准备

为了能够开始使用 KMM,您应该安装以下内容:

  1. Java JDK 版本 11

  2. Ruby and Bundler

  3. Android Studio — 版本 4.2 或更高版本

  4. Xcode — 版本 11.3 或更高版本

  5. Xcode 命令行开发者工具

  6. 适用于 Android Studio 的Kotlin Multiplatform Mobile plugin。在 Android Studio 中,选择 Preferences > Plugins > 在 Marketplace 中搜索插件Kotlin Multiplatform Mobile并安装:

b5cfc9c2bb5da796751fd5890c6e627e.png

kmm plugin

准备就绪,是时候创建您的第一个 KMM 项目了

创建第一个 KMM 项目

使用以下步骤创建您的第一个 KMM 项目:

1、打开Android Studio并点击新建 项目:

95751660f568e7d89d5a1085c4c16a92.png

2、在项目的模板中,向下滚动,您将看到我们现在有了KMM 应用程序。选择它并单击下一步按钮:

1874c9a4cf5af139a558b2db7f3280de.png

3、输入您的项目名称、要使用的最低 SDK,然后单击“下一步”按钮:

5fd471d7cd762217bedcf1dc97927bd5.png

4、更改 Android 和 iOS 的应用程序名称。您还可以更改共享模块名称,这里使用默认值并选择为shared模块添加示例测试:

3eb40819153ddbbc1329a336d68e04cc.png

对于iOS应用程序,可以在regular framework或CocoPods依赖管理器之间切换依赖关系,在环境工具准备中我提到需要为CocoPods安装Ruby 。

  1. 单击“下一步”按钮并等待 Gradle 完成项目设置:

项目加载成功后,现在可以找到项目中所有的app模块:

  • androidApp

  • iosApp

  • shared

3d6dfbc00c1b805e8afe6d2ae447df95.png

image
  1. 配置中选择androidApp 和 iOSApp运行到相应模拟器


434d9c0704e2ede140fc141893745e71.png

image

通过AndroidStudio就可运行iOS,通常使用 Xcode 来开发 iOS 原生应用

KMM 会利用 Gradle 插件,自动调用 Xcode 进行构建,并调起 iOS 模拟器运行

9b965f63f35c13c48a671d3ffc79b35b.png

image

注意:使用 KMM Plugin 建立的工程,会默认使用 Kotlin(.kts 文件)的形式来进行 Gradle 配置,另外,其新建的 iOS 工程,也默认使用 Swift UI 进行开发,且这两项不可以配置,如果需要使用传统的 iOS UI 开发形式,需要以集成的形式来新建 KMM Module

KMM工程结构

KMM 插件建立的 KMM 工程的文件目录结构说明

├── androidApp        # 实际 Android APP Module
├── build.gradle.kts  # 工程根 Gradle 配置
├── gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── iosApp            # 实际的 iOS 工程根目录
├── local.properties
├── settings.gradle.kts
└── shared            # KMM 模块代码目录├── build.gradle.kts  # KMM 模块 Gradle 配置(依赖、插件、构建 Task、cinterop 等配置)└── src # 内部模块形式都为 Gradle 工程 Module├── androidMain    # Android 差异化代码,最终生成 AAR├── commonMain     # 共享模块 API 代码├── iosMain        # iOS 差异化代码,└── nativeInterop  # 默认不会创建,用来存放 *.def 文件,描述与 C/C++ 代码,或 Apple Framework 交互时,构建 klib 的配置

b3c05c2a2eb68fd4787636a5ac1c39b2.jpeg

image

androidApp和iosApp为Android和iOS这两个平台的工程模块,shared为共享逻辑模块,供androidApp和iosApp调用。

打开根目录的settings.gradle.kts:

pluginManagement {repositories {google()gradlePluginPortal()mavenCentral()}
}dependencyResolutionManagement {repositories {google()mavenCentral()}
}rootProject.name = "wb-kmm-demo"
include(":androidApp")
include(":shared")

会发现主项目只include了androidApp和shared这两个子项目,因为这两个项目是Gradle项目

iOS的项目如何引用呢?

The iOS application is produced from an Xcode project. It's stored in a separate directory within the root project. 
Xcode uses its own build system; thus, the iOS application project isn't connected with other parts of the Multiplatform Mobile project via Gradle. 
Instead, it uses the shared module as an external artifact – framework.

iOS作为Xcode项目,储存在根项目的另一个文件夹。Xcode有自己的编译系统,因此iOS项目并不依靠Gradle去和shared工程建立联系,而是依靠将shared工程打包成framework供iOS项目使用。我们可以看一下shared模块编译后的产物,如下图所示:

f358182a5964ebd699184c88264df427.png

image

特定于平台的API和实现

因为在我们的核心目标即双端共享代码。

什么是共享代码呢?让同一份代码能在 Android & iOS 上运行。

怎么实现这个目标呢?简单来说把全部代码分为两个部分,其中一部分就是与平台无关的代码。

啥是平台无关的代码呢?比如我们要编写一个检验手机号的算法,我们认为这个算法的代码是平台无关的,因为输入就是一个字符串,里面的实现就是根据指定的规则来判断这个输入字符串的合法性,期间不涉及任何平台相关特性的访问,比如系统 API 的访问。

但是光有与平台无关的代码是不够的,一旦涉及到与平台相关的访问,例如获取设备版本号或硬件信息等,我们就需要独立于平台去完成它们,这些独立于平台的代码在哪实现?这就有了 AndroidApp 和 iOSApp 这两个模块。在“shared”模块中,我们包含了核心应用程序逻辑,例如类、函数,并使用 Gradle 作为构建系统。

expect/actual 机制 :

ad6a7e7cf10fafbfaa569e84d68454b9.jpeg

image

KMM 里 expect/actual 机制是非常重要的,因为它提供了一种语法技术来解决平台相关的问题。

拿工程例子来说,工程逻辑中使用设备的 版本 号时,这里需要编写特定平台的代码才能实现。这时,expect 就相当于声明一个协议,它定义了我们期望得到的接口或数据,之后各个平台都需要独立地实现这个协议来满足业务需要。

shared模块的实现形式

进入shared模块,看commonMain文件夹下Greeting的实现:

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

greeting()方法调用platform.name,Platform的实现如下:

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

Platform是个接口,使用expect关键字来声明getPlatform(),再由Android和iOS通过使用actual关键字分别实现:

Android:

class AndroidPlatform : Platform {override val name: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}actual fun getPlatform(): Platform = AndroidPlatform()

iOS:

import platform.UIKit.UIDeviceclass IOSPlatform: Platform {override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}actual fun getPlatform(): Platform = IOSPlatform()

最后是两端调用实现:

Android:

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {MyApplicationTheme {Surface(modifier = Modifier.fillMaxSize(),color = MaterialTheme.colors.background) {GreetingView(Greeting().greet())}}}}
}@Composable
fun GreetingView(text: String) {Text(text = text)
}

iOS:

import SwiftUI
import sharedstruct ContentView: View {let greet = Greeting().greet()var body: some View {Text(greet)}
}struct ContentView_Previews: PreviewProvider {static var previews: some View {ContentView()}
}
KMM vs Flutter vs RN

与 Flutter 这种框架的思想相反,KMM 是用一套语言生成多个平台特定的字节码,所有的翻译工作由 kotlinc 或 kotlin-nativec 编译器来执行,从某种角度来讲,是『从上到下』;

而 Flutter 的思想是『从下到上』,这也决定了两种框架适用的场景,Flutter 就适合绘制 UI,而 KMM 则是更适合与 UI 无关的逻辑代码,比如:Model 层,网络请求、数据解析、建模等

  • 体积:

  1. 使用 Flutter 需要在 App 包内部增加两个引擎:

  • 一个是 Flutter 的渲染引擎,该引擎使用 C/C++ 开发,直接调用 OpenGL/Skia 的 API 进行绘制,从而摆脱 iOS 的 UIKit 以及 Android 的 View 组件直接渲染成需要的样式,保证样式高度统一

  • 另一个是 Dart 语言的 Runtime,用于解析并运行 Dart 语言编译的 Bundle

这两者减小了开发者的适配成本,但增大了 APP 的包体积(其他类似的跨平台框架,如:React Native 等,也会内置 JavaScript Core 或 V8 引擎)

  1. KMM 针对不同平台生成不同的二进制依赖包,根本上还是调用了 Android、iOS 的原生 API,并不会内置引擎这类文件,对 App 的体积影响相对较小

  • 技术栈:

    • Flutter-->Dart

    • KMM-->Kotlin

    • RN-->JavaScript

  • 适用场景:

    • 由于 Flutter 采用类似 3D 游戏的渲染理念,统一了界面渲染引擎,利用 Dart 可以高度保证双端样式和交互逻辑一致,且几乎不存在界面适配问题,完全抹平了 TextView 和 UILabel 这类控件之间的差异,所以 Flutter 适合于界面构建

    • 而 KMM 并不适合 UI,双端的组件,生命周期、API 差异都比较大,KMM 在技术上可以实现功能,但相当于写了两份代码,失去了意义

Flutter和RN这两者虽然在设计及原理上区别很大,但设计思想上都是采用非原生开发语言在 Android 与 iOS 系统框架之上搭建的“阁楼”上运行,每个采用这些框架的 App 在打包时需要集成语言的 Runtime、框架的底层组件等许多重量级的包与库。并且 JavaScript 或 Dart 与原生开发语言(Java/Kotlin、Objective-C/Swift)之间的交互需要通过“桥接通讯”实现

KMM提出了不同于 RN 与 Flutter 的跨端解决方案,即使用不同的编译器编译同一份代码生成各端的不同产物来达到跨平台的目的,这就是 Kotlin Multiplatform

Kotlin Multiplatform

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

27c016ec58560938bb22782af63cddff.png

image

Kotlin 官方开发的多平台框架分为以下几种:

  • 标准 Kotlin(Kotlin Stdlib)

    • 即 Kotlin JVM,由于 Kotlin 最初是基于 JVM 运行的,所以可以使用 Java  的全部功能

  • Kotlin Native

    • 简称 KN,内部对各平台(如:Windows、Linux、macOS、iOS、Android)Native API(不使用 Runtime 的)进行封装,底层使用 LLVM 进行编译,可以使用 Kotlin 调用各平台特定的 API 或基于一些 C/C++ 库的能力,如:OpenGL、OpenCV 等,使多平台共享一套 Kotlin 代码

  • Kotlin JS

    • 基本原理是将 Kotlin 代码翻译成 JavaScript,同时可以调用一些 JavaScript 特定的接口,从而进行 Web 开发

f8f6aa80a24457ff4eb23d5b28dae684.png

image

Compose Multiplatform,一个由JetBrains开发的基于kotlin的声明式UI框架,实现了在Android和iOS之间共享UI,实现了完全跨平台的应用程序:

c7a29c3acbe6d6ad62ba9c6752003e64.jpeg

image

Kotlin Multiplatform Wizard

我们可以使用Kotlin Multiplatform Wizard创建跨平台应用程序。

f847df6b83880cc09ab12265817c86f2.png

image

这里可以选择运行它的平台,如果我们选择与compose多平台共享UI为iOS项目,我们可以创建UI与compose多平台,并运行与iOS和android不使用Swift UI。我们也可以用它创建服务器和桌面项目。

10dea5514932dd13f9939e574a36861a.png


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/543121.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何配置IDEA中的JavaWeb环境(2023最新版)

创建项目 中文版:【文件】-【新建】-【项目】 点击【新建项目】,改好【名称】点击【创建】 右键自己建立的项目-【添加框架支持】(英文版是Add Framework Support...) 勾选【Web应用程序】-【确定】 配置tomcat 点击编辑配置 点…

RabbitMQ学习总结-延迟消息

1.死信交换机 一致不被消费的信息/过期的信息/被标记nack/reject的信息,这些消息都可以进入死信交换机,但是首先要配置的有私信交换机。私信交换机可以再RabbitMQ的客户端上选定配置-dead-letter-exchange。 2.延迟消息 像我们买车票,外卖…

第十四届蓝桥杯省赛真题 Java A 组【原卷】

文章目录 发现宝藏【考生须知】试题 A \mathrm{A} A : 特殊日期试题 B: 与或异或试题 C : \mathrm{C}: C: 平均试题 D: 棋盘试题 E : \mathrm{E}: E: 互质数的个数试题 F: 阶乘的和试题 G: 小蓝的旅行计划试题 H: 太阳试题 I: 高塔试题 J \mathrm{J} J : 反异或 01 串 发现…

大规模自动化重构框架--OpenRewrite浅析

目录 1. OpenRewrite是什么?定位? 2. OpenWrite具体如何做? 3. 核心概念释义 3.1 Lossless Semantic Trees (LST) 无损语义树 3.2 访问器(Visitors) 3.3 配方(Recipes) 4. 参考链接 Open…

【数据结构】二叉树OJ题(C语言实现)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ 🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿&#x1…

个人网站制作 Part 9 | Web开发项目

文章目录 个人网站制作 Part 9 | Web开发项目👩‍💻 基础Web开发练手项目系列:个人网站制作🚀 添加博客功能🔨使用Express和MongoDB🔧步骤 1: 创建博客模型🔧步骤 2: 创建博客路由 &#x1f528…

PCM和I2S区别

I2S和PCM接口都是数字音频接口,而所见的蓝牙到cpu以及codec的音频接口都是用PCM接口,是不是两个接口有各自不同的应用呢?先来看下概念。 PCM(PCM-clock、PCM-sync、PCM-in、PCM-out)脉冲编码调制,模拟语音信…

BitMap位图理解及典型应用案例

基本介绍 本质上是哈希表的一种应用实现,原理简单,以 bit 为单位构建数组的方案,就叫作 Bitmap,翻译为位图。即bit 的集合;使用一个bit表示状态, 两种状态 (0不存在和1存在) 使用最少字节的类型…

【蓝桥杯嵌入式】四、各种外设驱动(六)生成PWM波——呼吸灯

温馨提示:本文不会重复之前提到的内容,如需查看,请参考附录 【蓝桥杯嵌入式】附录 目录 理论知识: 一、需求分析 1、需要的外设资源分析: 2、外设具体分析: 3、软件分析: 二、软件配置 …

Windows11企业版安装WSL2和Ubuntu发布版(避坑)

背景 win10企业版升级win11企业版后,安装WSL2,最后安装WSL的Ubuntu发布版,尝试网上各种方法,还是出现文章第三节所写的问题,差点被这问题搞放弃了,全网少有针对这个问题的答案,有也不顶用&…

开源漏扫工具:DependencyCheck

开源漏扫工具:DependencyCheck Dependency-Check 是 OWASP(Open Web Application Security Project)的一个实用开源程序,用于识别项目依赖项并检查是否存在任何已知的,公开披露的漏洞。 DependencyCheck是一个开源的…

景联文科技:提供通用多模态数据,助力AI多模态领域实现飞跃式发展

回顾2023年,以ChatGPT为代表的通用人工智能大模型在全球范围内掀起了新一轮人工智能产业发展浪潮,我国人工智能大模型市场呈现百“模”争鸣、日新月异的迅猛发展态势。 根据大模型之家、钛媒体数据,2023年中国大模型市场规模达到147亿人民币&…