客户端原生大佬狂喜：uni-app x 支持原生混编了！

本文背景

最近 uni-app x 发布了全新版本，其中有一点是 uni-app x 4.25 支持原生混编了，也就是可以直接使用 kotlin/java/swift 代码了，客户端原生大佬们可以火力全开了！

新增 编译器 uts 插件支持 Kotlin、Java、Swift 代码混编

很多人和我一样，需要使用 uni-app x 开发 app，但对客户端原生开发 (后面统一叫 “原生开发”) 比较陌生，又不熟悉相关领域知识。可以借助 UTS 语言来进行原生功能开发。

也有很多原生开发老手参与开发 uni-app x，熟悉原生开发的各种底层细节，更倾向于使用已有的原生开发经验。

两个不同的人群需求不同，会有一些不同角度的产品建议反馈：

前端反馈实现页面布局、业务开发快，但是原生开发不熟，有问题解决不了

原生开发反馈，希望复用已有的原生 SDK、原生工具包

大家的目标是一样的，加速 app 开发落地，早完工不加班！

本文简单介绍原生混编的基础概念、相关用法、进阶提升等。

为什么会有原生混编？

这个功能目标群体是谁，有什么用，对我有影响吗？

uni-app x 开发应用，以往要实现业务逻辑，调用原生功能时候之前需要使用 UTS 语言来编写兼容代码，通过编译器来转换成 Kotlin 和 Swift。

这对前端同学比较友好：因为 UTS 的语法是和 TS 很像，只要知道原生怎么写，转换一下就可以上手了。实现了让前端工程师有能力调用客户端原生功能。

另一方面，对原生开发老手来说就有需要吐槽的地方了，还要额外学习 UTS 和 UTS 插件等东西，希望可以复用以后的原生开发知识。

这次更新就支持了在 UTS 插件中使用原生混编功能。这里举一个例子来进行说明。

关联文章：

[[如何快速学习和测试 Swift 和 UIKit 代码？]]

[[如何快速学习和测试 Android Kotlin 代码？]]

这里以 iOS 为主要介绍平台，安卓大同小异，为了一致的阅读体验，在文章的末尾放出安卓相关代码。

新概念主要先看思路。

iOS 里查询当前电量

熟悉 uni-app x 的用户可能听过好几次查询当前手机电量的案例了，没办法这个是在太经典了。

假设现在我要求在 app 查询当前手机电量，如果当前电量比较高，比如 80% 以上时候 app 应用就使用高级动画，低于这个值就开启普通动画。

如果使用 uni-app x 获取当前手机电量，这个需求是一个原生需求，需要调用客户端的 api 来获取。这个需求 uni-app x 已经封装好了这个 api，直接使用 uni.getBatteryInfo 就得到了。

这里我们假装没有，需要自己实现。

iOS 原生代码举例

可以通过问原生同事、问 AI、翻阅 uni-app x 的开源代码，得知 iOS 查询电量的逻辑是这样。

Copy
import UIKit

func getBatteryLevel() -> Float {
// 开启电池监测
UIDevice.current.isBatteryMonitoringEnabled = true

// 获取当前电量
let batteryLevel = UIDevice.current.batteryLevel
// 转换为百分比
return batteryLevel * 100
}

// 获取电量并打印·
let currentBatteryLevel = getBatteryLevel()
print("当前电量: \(currentBatteryLevel)%")

在混编开发之前

在 uni-app x 支持混编功能之前，我们需要使用 UTS 翻译以上代码，通过 UTS 编译器转为原生：知道原生如何写 - 翻译为 UTS - 翻译为 Swift。

UTS 代码大致如下，删除了函数导出、格式化等逻辑。

Copy
import { UIDevice } from "UIKit";
UIDevice.current.isBatteryMonitoringEnabled = true
const batteryLevel = Number(UIDevice.current.batteryLevel * 100)

通过讲逻辑拆分为 UTS 插件，在编译时候通过 UTS 编译器转换为 Swift 代码。

这里安卓平台导入包的过程不完全一样，一般推荐的做法还是按照平台拆分实现功能。

在混编开发之后

有了原生混编，很多事情就简单多了。这里如果你对 UTS 开发插件还不熟悉，可以参考 [[新手向：包装 UTS 插件]]，主要介绍了 UTS 插件如何开发。本文主要展示混编的大致思路，细节不一一展开了。

经典的 UTS 插件目录结构是

Copy
uni_modules
- webworker-batteryStatus
-- utssdk
--- app-ios
---- index.uts
-- package.json

在 UTS 插件的 app-ios/index.uts 中新建 NativeCode.swift，人如其名，这个文件是原生 swift 文件。

NativeCode.swfit 文件内容如下，这是官方推荐的一种写法。

Copy
import UIKit

public class NativeCode {
static func getBatteryLevelSwift() -> Float {
// 开启电池监测
UIDevice.current.isBatteryMonitoringEnabled = true

// 获取当前电量
let batteryLevel = UIDevice.current.batteryLevel
// 转换为百分比
return batteryLevel * 100
}
}

在 UTS 中如何调用？

index.uts 代码如下

Copy
export function getBatteryLevelSwift() : Float {
return NativeCode.getBatteryLevelSwift()
}

使用就很简单了，引用包，调用方法即可。

Copy

<view>
<view>{{currentLevel}}</view>
电量
</view>



import { getBatteryLevelSwift } from '../../uni_modules/webworker-batteryLevel'
const currentLevel = ref(0)
const getLevel = () => {
console.log('click button')
// console.log(getBatteryLevelSwift())
const res = getBatteryLevelSwift()
currentLevel.value = res
}


通过

原生开发逻辑

uts 包装逻辑

uvue 中调用

可以轻松实现混编开发。

安卓实现混编

和 iOS 类似，也是在 uni_moduels 的 app-android 目录添加 index.uts 和 NativeCode.kt

其中 NativeCode.kt 内容大致

Copy
package uts.sdk.modules.ottoBatteryLevel;
import android.content.Context
import android.os.BatteryManager

object NativeCode {
fun getBatteryLevel(context: Context): Int {
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
return batteryLevel
}
}

其中 index.uts 内容如下

Copy
import Context from "android.content.Context";

export function getBatteryLevel() : Int {
const context = UTSAndroid.getAppContext()!;
return NativeCode.getBatteryLevel(context)
}

其他部分和 ios 一致，在 uvue 调用 uts 插件。

接下来做什么？

希望通过这篇文章介绍，可以让你对 UTS 插件开发、原生混编、uni-app x 开发有进一步的理解。

有了大杀器可以探索更多内容了。接下来可以做什么？

官方的 demo 实现学习更多细节

官方开源了 hello uts 仓库，可以从这个案例了解更多细节。

uni_modules/uts-tests/utssdk/NativeCode.uts · dev · DCloud / Hello UTS · GitCode

官方文档了解更多技术细节

详细说明了原生混编的来龙去脉，更加详细。
https://doc.dcloud.net.cn/uni-app-x/plugin/uts-plugin-hybrid.htm

学习 uts 插件开发

参考 《[[新手向：包装 UTS 插件]]》