KMM初探

news2025/2/24 21:21:58

什么是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.UIDevice


class 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 shared


struct 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.coloradmin.cn/o/1529080.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第四百一十一回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"给geolocator插件提交问题的结果"相关的内容,本章回中将介绍自定义标题栏.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我…

第四百一十二回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"给geolocator插件提交问题的结果"相关的内容,本章回中将介绍自定义标题栏.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我…

我的自建博客之旅04之Halo

我的自建博客之旅04之Halo Halo是我无意间发现的一款博客框架,如果你讨厌Hexo,Vuepress等静态框架本地编辑,构建部署等方式,如果你想要一款一次搭建,前台是博客,后台是文章维护,并且支持各种定制化折腾的博客框架,可能Halo会比较适合你。 因为我个人还是比较偏技术,…

八节【DBA从入门到实践】课程,带你快速掌握OceanBase运维管理核心技能

为帮助用户及开发者更好、更快地掌握OceanBase DBA核心技能,OceanBase社区设计了配套教程——“DBA从入门到实践”。8期教程带大家循序渐进掌握OceanBase运维管理核心技能。搭配随堂习题和OceanBase技术专家在线答疑,快速掌握重要知识点,并轻…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Refresh)

可以进行页面下拉操作并显示刷新动效的容器组件。 说明: 该组件从API Version 8开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 子组件 支持单个子组件。 从API version 11开始,Refresh子组件会跟随手势下拉而下移…

【数据结构】链表力扣刷题详解

前言 题目链接 移除链表元素 链表的中间结点 反转链表 分割链表 环形链表的约瑟夫问题 ​ 欢迎关注个人主页:逸狼 创造不易,可以点点赞吗~ 如有错误,欢迎指出~ 移除链表元素 题述 给你一个链表的头节点 head 和一个整数 val ,请…

搜维尔科技:OptiTrack提供了一个通用、精确、灵活和可监控的系统!

MELS集成OptiTrack与最前沿的虚拟生产阶段 在加拿大蒙特利尔,MELS Studios and Postproduction设有20个工作室,以满足各种规模的电影和电视项目的需求。凭借先进的技术设施和专业的技术团队,梅尔斯为电影行业的合作伙伴提供从摄影棚和设备租…

应用开发技术巩固指南

前言 起初毕业前夕,个人已经开始自学Android开发,由于没有指导,所以起步很难,写的代码也规范,逻辑不清,技术止步于皮毛,很多东西都不理解。 后来步入工作,逐渐熟悉了这个方向&…

Zustand极简的状态管理工具

介绍 一个小型、快速且可扩展的 Bearbones 状态管理解决方案。 Zustand 有一个基于 hooks 的舒适 API。它不是样板文件或固执己见,但有足够的惯例来明确和类似通量。 zustand官网 zustand使用方法及调试工具的安装使用 安装包 npm install zustand2.创建store仓…

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零

🍁你好,我是 RO-BERRY 📗 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 目录 前言1. 移动零&#xff0…

多线程(部分)

Day28下2 多线程 一、什么是进程 进程是系统进行资源分配和调用的独立单元,每一个进程都有它的独立内存空间和系统资源。 二、单进程操作系统和多进程操作系统的区别 单进程操作系统:dos(一瞬间只能执行一个任务) 多进程单用户操…

想第一时间接收API变更信息?用Apipost这样做

Apipost致力于为开发者提供更全面的API管理功能。而最近,Apipost又新增了一个非常实用的功能:第三方消息推送。这个功能可以帮助开发人员及时了解API的变更情况,从而更好地管理和优化自己的API。 具体来说,Apipost的第三方消息推…

Linux操作系统——多线程

1.线程特性 1.1线程优点 创建一个新线程的代价要比创建一个新进程小得多与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多线程占用的资源要比进程少很多能充分利用多处理器的可并行数量在等待慢速I/O操作结束的同时,程序可执行其他的计…

2024.3.9|第十五届蓝桥杯模拟赛(第三期)

2024.3.9|十五届蓝桥杯模拟赛(第三期) 第一题 第二题 第三题 第四题 第五题 第六题 第七题 第八题 第九题 第十题 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C学习笔记,常言道,不积跬步无以至千里&…

sql-bypass通关笔记(作业)

靶场环境的搭建: 首先安装dvwa靶场;因为要用到dvwa的数据库然后将该靶场放到phpstudy的www目录下创建一个网站指向该文件夹通过访问文件夹中php文件的形式进行闯关具体压缩包我放到最后的资料里了 index1.php通关笔记 知识点: 空格过滤 #…

51单片机—直流电机

1.元件介绍 2.驱动电路 3.电机调速 一般会保证一个周期的时间是一样的 应用&#xff1a; 1.LED呼吸灯 #include <REGX52.H>sbit LEDP2^0;void Delay(unsigned int t) {while(t--); } void main() {unsigned char Time,i;while(1){for(Time0;Time<100;Time){for(i0;…

MateBook 14s 2023款 集显 触屏(HKFG-16)原厂Win11系统

HUAWEI华为MateBook14s笔记本电脑2023款原装Windows11&#xff0c;恢复出厂开箱状态系统下载 适用型号&#xff1a;HKFG-XX、HKFG-16、HKFG-32 链接&#xff1a;https://pan.baidu.com/s/1GBPLwucRiIup539Ms2ue0w?pwdfm41 提取码&#xff1a;fm41 原厂系统自带所有驱动、…

python失物招领系统-安卓-flask-django-nodejs-php

对于本失物招领 的设计来说&#xff0c; 它是应用mysql数据库、安卓等技术动态编程以及数据库进行努力学习和大量实践&#xff0c;并运用到了 建设中在整个系统的设计当中&#xff0c;具体根据网上失物招领的现状来进行开发的&#xff0c;具体根据用户需求实现网上失物招领网络…

基于python的在线学习与推荐系统

技术&#xff1a;pythonmysqlvue 一、系统背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理。这样的大…

【计算机视觉】三、图像处理——实验:图像去模糊和去噪、提取边缘特征

文章目录 0. 实验环境1. 理论基础1.1 滤波器&#xff08;卷积核&#xff09;1.2 PyTorch:卷积操作 2. 图像处理2.1 图像读取2.2 查看通道2.3 图像处理 3. 图像去模糊4. 图像去噪4.1 添加随机噪点4.2 图像去噪 0. 实验环境 本实验使用了PyTorch深度学习框架&#xff0c;相关操作…