KMM(Kotlin Multiplatform Mobile)入门(二)在现有工程中集成 KMM

为什么要在现有工程中集成?

直接用 KMM 插件生成的工程不香嘛?为什么还要讲在原有的工程中集成?

不香,确实不香!

  • 默认工程结构局限性高

    1. 由 KMM 插件建立的工程,默认使用 Kotlin(*.kts 文件)进行 Gradle 配置,虽然用 Android Studio 新建一个 Android 工程会默认使用 kts,但很多项目现在都还在使用 Groovy,要改回去也需要一定工作量和学习成本
    2. 默认建立的 iOS 工程使用 Swift UI,目前大多数 iOS App 都会使用代码开发 UI,并没有使用 Storyboard、IB、Swift UI,而且国内很多公司都还在使用 Objective-C,同时 Swift 与 Objective-C 的交互并不像 Kotlin 和 Java 那样简单,所以彻底迁移到 Swift,还需要一定时间
  • 工程目录不易维护

    默认的工程类似一个独立的 Android App 工程,KMM 模块以 Gradle 模块形式依赖在 Android 主 App Module 当中,而 iOS 工程则是直接放在一个目录下,iOS 工程往往规模都比较庞大,且缺少像 Gradle 这样的工程管理框架,且 Xcode 工程索引文件在多人开发时,经常需要解决冲突,如果将 iOS 工程也放在整个 Android 工程目录中,后续将十分难以维护

如何在现有工程中集成 KMM

  • 推荐的依赖项版本:

    • Kotlin 基础库及 Gradle 插件:1.5.0(KMM 版本和它一致)
    • Gradle 版本:6.8 及以上
    • Android Gradle Plugin:4.2.1

我们以一个普通的 Android 和 iOS App 工程为例,一步一步完成 KMM 模块的建立和双端的接入

Android 集成流程

Gradle 基本配置

1
2
3
4
5
6
7
8
9
// 首先在 settings.gradle 文件头部,新增以下配置项

pluginManagement {
repositories {
google()
gradlePluginPortal()
mavenCentral()
}
}

新建 KMM 模块

由于 Module 使用 kts 并不影响编译,所以推荐 KMM 单独使用 kts 配置,此时可以利用 KMM 插件比较方便的创建 Module,如果需要使用 Groovy,需要自己根据目录结构单独建立各类文件和目录,相对比较麻烦

这里可以按照图片上的方式创建 KMM 的模块

等待 Gradle Sync 完成以后,就可以看到 KMM 模块的相关代码了

主模块引入 KMM 依赖

此时还需要在 Android 主 App 模块中增加 KMM 模块的依赖,如下图所示,在 app 模块的 build.gradle 文件中,dependencies 闭包下,增加一条 implementation 即可

等待 Sync 完成以后,就可以在 app 模块中调用 KMM 共享模块的代码了

Android App 的集成相对比较简单,到此已基本完成

针对一些已经开发好的工程,如果需要的话,也可以将一些通用的、与界面无关的代码,如:Model 层实体类,移入 Shared 模块当中

iOS 集成流程

构建 Apple Framework

由于 KMM 模块在 iOS 平台是以 Apple Framework 的形式来具体体现的,所以 iOS 工程最主要的就是『编译』和『引入』KMM 模块生成的 Framework

如何让 iOS 工程引入一个外部的 Framework?首先肯定是需要有一个真正的 Framework!

所以,需要首先在上面的 Android 工程中,执行 KMM 模块的 Framework 构建

切换到 Android 工程根目录,执行如下命令:

1
./gradlew kmmsharedmodule:packForXcode

注意:kmmsharedmodule 是 KMM 共享模块的目录名,这里是 KMM 插件新建 Module 时默认的,根据自己的情况修改

如果是首次运行,Kotlin Native 的 Gradle 插件(具体为 compileKotlinIos 这项 Task)会自动下载几项依赖(如下图所示)由于 clang-llvm-apple 这个包比较大,如果网络不好,此时界面会像卡住了一样,需要耐心等待,或者科学上网

成功完成构建以后,Framework 就生成了,目录在 KMM 模块下的 build/xcode-frameworks/ 目录下

Xcode 引入 Framework

此时,打开 Xcode 并打开我们需要引入 KMM 模块的 iOS 工程,首先根据下图所示,添加 Framework 依赖

点击『+』以后,在弹出的对话框中,点击『Add Other…』并选择『Add Files…』

从找到刚才编译好的 Framework 文件,打开引入进工程中,如下图所示

完成以后,根据下图所示操作,配置 Xcode 工程的 Framework Search Path,即为 KMM 模块生成 Framework 文件的目录

其中,${SRCROOT} 代表 Xcode 工程文件所在的根目录,这里建议将 Android 工程放在与 Xcode 工程根目录同级的目录下,这样便于使用相对路径进行配置

添加 Run Script 脚本

毋庸置疑,Xcode 是不支持直接执行 Gradle 任务的,为了能够使 Framework 及时更新,只能使用『Run Script』的形式来调用 Gradle 命令触发 KMM 进行 Framework 构建,所以在完成 Search Paths 的配置以后,需要按下图所示,添加一个『Run Script Phase』用来在 iOS 工程运行之前构建 KMM 的 Framework

Run Script 的具体内容可以参考以下脚本进行配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 防止找不到 JAVA_HOME 环境变量(如果使用 zsh)
if [ -f ~/.zshrc ]; then
echo "zsh"
source ~/.zshrc
fi
# 防止找不到 JAVA_HOME 环境变量(如果使用 bash)
if [ -f ~/.bashrc ]; then
echo "bash"
source ~/.bashrc
fi

cd "$SRCROOT"
cd ../MyApplication2 # 这里为 Android 工程的目录名
# kmmsharedmodule 为 KMM 模块,Gradle project 名https://img.coderyuan.com/1622193265424.png
./gradlew :kmmsharedmodule:clean :kmmsharedmodule:packForXcode -PXCODE_CONFIGURATION=${CONFIGURATION}

填写完成之后,需要调整『Run Script』的顺序,主要是需要保证这段脚本的运行,在『Compile Sources』之前,否则会导致 Xcode 编译报错

操作很简单,根据下图所示,直接拖动即可

最终的结果类似下图所示

至此,iOS 工程的配置就完成了,我们可以在 Build(⌘ + B)之后,在工程的 Objective-C 或 Swift 代码中调用 KMM 模块中的方法

这里推荐使用 Swift,主要原因是其语法和 Kotlin 接近,且不需要额外添加前缀,代码提示也相对较好,Objective-C 则相对比较麻烦

调用示例

Objective-C 调用示例:

Swift 调用示例: