本文背景#
最近 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 查询电量的逻辑是这样。
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 代码大致如下,删除了函数导出、格式化等逻辑。
import { UIDevice } from "UIKit";
UIDevice.current.isBatteryMonitoringEnabled = true
const batteryLevel = Number(UIDevice.current.batteryLevel * 100)
通过讲逻辑拆分为 UTS 插件,在编译时候通过 UTS 编译器转换为 Swift 代码。
这里安卓平台导入包的过程不完全一样,一般推荐的做法还是按照平台拆分实现功能。
在混编开发之后#
有了原生混编,很多事情就简单多了。这里如果你对 UTS 开发插件还不熟悉,可以参考 [[新手向:包装 UTS 插件]],主要介绍了 UTS 插件如何开发。本文主要展示混编的大致思路,细节不一一展开了。
经典的 UTS 插件目录结构是
uni_modules
- webworker-batteryStatus
-- utssdk
--- app-ios
---- index.uts
-- package.json
在 UTS 插件的 app-ios/index.uts
中新建 NativeCode.swift
,人如其名,这个文件是原生 swift
文件。
NativeCode.swfit
文件内容如下,这是官方推荐的一种写法。
import UIKit
public class NativeCode {
static func getBatteryLevelSwift() -> Float {
// 开启电池监测
UIDevice.current.isBatteryMonitoringEnabled = true
// 获取当前电量
let batteryLevel = UIDevice.current.batteryLevel
// 转换为百分比
return batteryLevel * 100
}
}
在 UTS 中如何调用?
index.uts
代码如下
export function getBatteryLevelSwift() : Float {
return NativeCode.getBatteryLevelSwift()
}
使用就很简单了,引用包,调用方法即可。
<template>
<view>
<view>{{currentLevel}}</view>
<button @click="getLevel"> 电量</button>
</view>
</template>
<script setup>
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
}
</script>
通过
- 原生开发逻辑
- uts 包装逻辑
- uvue 中调用
可以轻松实现混编开发。
安卓实现混编#
和 iOS 类似,也是在 uni_moduels 的 app-android
目录添加 index.uts
和 NativeCode.kt
其中 NativeCode.kt
内容大致
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
内容如下
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 插件]]》