UTS 插件
UTS (uni TypeScript) 是 uniapp 推出的使用 TypeScript 开发原生插件的解决方案,让您可以用熟悉的语法编写跨平台原生代码。
什么是 UTS
特点
- 📝 使用 TypeScript 语法
- 🚀 接近原生的性能
- 🔄 跨平台代码复用
- 🛠️ 统一的开发体验
- 📦 自动类型推导
- 🎯 直接调用系统 API
与传统原生开发对比
| 特性 | 传统原生 | UTS |
|---|---|---|
| 语言 | Java/Kotlin + ObjC/Swift | TypeScript |
| 学习成本 | 高 | 低 |
| 代码复用 | 困难 | 容易 |
| 类型安全 | 部分 | 完全 |
| 开发效率 | 中 | 高 |
| 性能 | 100% | 95%+ |
快速开始
创建 UTS 插件
1. 使用脚手架
bash
npx degit dcloudio/uni-uts-plugin my-uts-plugin
cd my-uts-plugin2. 项目结构
my-uts-plugin/
├── utssdk/
│ ├── interface.uts # 接口定义
│ ├── app-android/ # Android 实现
│ │ └── index.uts
│ ├── app-ios/ # iOS 实现
│ │ └── index.uts
│ └── web/ # Web 实现(可选)
│ └── index.uts
├── package.json
└── README.mdHello World 示例
定义接口
interface.uts:
typescript
export interface GreetOptions {
name: string
}
export interface GreetResult {
message: string
}
export interface MyPlugin {
greet(options: GreetOptions): GreetResult
}Android 实现
app-android/index.uts:
typescript
import { GreetOptions, GreetResult } from '../interface.uts'
export function greet(options: GreetOptions): GreetResult {
const message = `Hello, ${options.name}!`
return { message }
}
// 调用 Android 系统 API
export function showToast(text: string): void {
const context = UTSAndroid.getAppContext()!
const duration = android.widget.Toast.LENGTH_SHORT
android.widget.Toast.makeText(context, text, duration).show()
}iOS 实现
app-ios/index.uts:
typescript
import { GreetOptions, GreetResult } from '../interface.uts'
export function greet(options: GreetOptions): GreetResult {
const message = `Hello, ${options.name}!`
return { message }
}
// 调用 iOS 系统 API
export function showAlert(text: string): void {
const alert = new UIAlertController()
alert.title = "提示"
alert.message = text
const action = UIAlertAction.actionWithTitle("确定",
UIAlertActionStyle.default, null)
alert.addAction(action)
const rootVC = UIApplication.sharedApplication.keyWindow?.rootViewController
rootVC?.presentViewController(alert, true, null)
}在项目中使用
1. 安装插件
将插件目录放到项目的 uni_modules/ 下:
your-project/
└── uni_modules/
└── my-uts-plugin/2. 调用插件
vue
<script setup>
import { greet, showToast } from '@/uni_modules/my-uts-plugin'
const handleGreet = () => {
const result = greet({ name: 'World' })
console.log(result.message) // "Hello, World!"
// Android 调用
// #ifdef APP-ANDROID
showToast('你好!')
// #endif
// iOS 调用
// #ifdef APP-IOS
showAlert('你好!')
// #endif
}
</script>
<template>
<button @click="handleGreet">问候</button>
</template>进阶开发
调用系统 API
Android 示例
typescript
// 获取设备信息
export function getDeviceInfo(): DeviceInfo {
const context = UTSAndroid.getAppContext()!
const build = android.os.Build
return {
model: build.MODEL,
brand: build.BRAND,
version: build.VERSION.RELEASE,
sdk: build.VERSION.SDK_INT
}
}
// 文件操作
export function saveFile(path: string, content: string): boolean {
try {
const file = new java.io.File(path)
const writer = new java.io.FileWriter(file)
writer.write(content)
writer.close()
return true
} catch (e: Exception) {
console.error(e)
return false
}
}
// 网络请求
export function httpGet(url: string, callback: (result: string) => void): void {
const client = new okhttp3.OkHttpClient()
const request = new okhttp3.Request.Builder()
.url(url)
.build()
client.newCall(request).enqueue(new okhttp3.Callback() {
override onResponse(call: okhttp3.Call, response: okhttp3.Response): void {
const body = response.body()?.string() ?? ""
UTSAndroid.getUniActivity()!.runOnUiThread(new Runnable() {
override run(): void {
callback(body)
}
})
}
override onFailure(call: okhttp3.Call, e: java.io.IOException): void {
console.error(e.message)
}
})
}iOS 示例
typescript
// 获取设备信息
export function getDeviceInfo(): DeviceInfo {
const device = UIDevice.currentDevice
return {
model: device.model,
name: device.name,
version: device.systemVersion,
uuid: device.identifierForVendor?.UUIDString ?? ""
}
}
// 文件操作
export function saveFile(path: string, content: string): boolean {
const data = content.dataUsingEncoding(NSUTF8StringEncoding)
return data?.writeToFile(path, true) ?? false
}
// 网络请求
export function httpGet(url: string, callback: (result: string) => void): void {
const nsUrl = NSURL.URLWithString(url)!
const request = NSURLRequest.requestWithURL(nsUrl)
const task = NSURLSession.sharedSession.dataTaskWithRequest(request) {
(data: NSData?, response: NSURLResponse?, error: NSError?) in
if (error != null) {
console.error(error!.localizedDescription)
return
}
if (data != null) {
const str = NSString.alloc().initWithData(data!, NSUTF8StringEncoding)
DispatchQueue.main.async {
callback(str as string)
}
}
}
task.resume()
}集成第三方 SDK
Android - 添加依赖
在插件根目录创建 config.json:
json
{
"dependencies": [
"com.squareup.okhttp3:okhttp:4.10.0",
"com.google.code.gson:gson:2.10"
]
}使用依赖:
typescript
import Gson from 'com.google.gson.Gson'
export function parseJSON(json: string): Map<string, any> {
const gson = new Gson()
const type = object.class.java
return gson.fromJson(json, type) as Map<string, any>
}iOS - 添加依赖
在 config.json 中:
json
{
"dependencies": {
"Alamofire": "5.6.4",
"SwiftyJSON": "5.0.1"
}
}使用依赖:
typescript
// 注意: iOS 的第三方库需要用 Swift/ObjC 封装后才能在 UTS 中使用异步操作
Promise 示例
typescript
export function asyncOperation(): Promise<string> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("操作完成")
}, 1000)
})
}
// 使用
asyncOperation().then(result => {
console.log(result)
})回调示例
typescript
export type SuccessCallback = (result: string) => void
export type FailCallback = (error: string) => void
export interface AsyncOptions {
success?: SuccessCallback
fail?: FailCallback
}
export function asyncWithCallback(options: AsyncOptions): void {
setTimeout(() => {
try {
const result = "操作成功"
options.success?.(result)
} catch (e) {
options.fail?.(e.message)
}
}, 1000)
}常用功能示例
1. 相机拍照
typescript
// Android
export function takePhoto(callback: (path: string) => void): void {
const activity = UTSAndroid.getUniActivity()!
const intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
// 启动相机并处理结果
// ... (完整实现需要 Activity Result API)
}
// iOS
export function takePhoto(callback: (path: string) => void): void {
const picker = UIImagePickerController()
picker.sourceType = UIImagePickerControllerSourceType.camera
// 设置代理并展示
// ... (完整实现需要代理)
}2. 本地存储
typescript
// Android
export function saveData(key: string, value: string): void {
const context = UTSAndroid.getAppContext()!
const prefs = context.getSharedPreferences("app_data", Context.MODE_PRIVATE)
const editor = prefs.edit()
editor.putString(key, value)
editor.apply()
}
export function getData(key: string): string | null {
const context = UTSAndroid.getAppContext()!
const prefs = context.getSharedPreferences("app_data", Context.MODE_PRIVATE)
return prefs.getString(key, null)
}
// iOS
export function saveData(key: string, value: string): void {
NSUserDefaults.standardUserDefaults.setObject(value, key)
NSUserDefaults.standardUserDefaults.synchronize()
}
export function getData(key: string): string | null {
return NSUserDefaults.standardUserDefaults.stringForKey(key)
}3. 权限请求
typescript
// Android
export function requestPermission(
permission: string,
callback: (granted: boolean) => void
): void {
const activity = UTSAndroid.getUniActivity()!
if (ContextCompat.checkSelfPermission(activity, permission)
== PackageManager.PERMISSION_GRANTED) {
callback(true)
return
}
// 请求权限
ActivityCompat.requestPermissions(
activity,
[permission],
1001
)
// 需要在 Activity 中处理结果
}调试与测试
日志输出
typescript
// 普通日志
console.log("调试信息")
// Android 系统日志
// #ifdef APP-ANDROID
android.util.Log.d("TAG", "Debug message")
// #endif
// iOS 系统日志
// #ifdef APP-IOS
NSLog("Debug message")
// #endif真机调试
- 连接设备
- 运行项目到真机
- 查看控制台输出
- 使用 Chrome DevTools (Android) 或 Safari (iOS)
发布插件
1. 完善文档
创建 README.md:
markdown
# 我的 UTS 插件
## 功能
- 功能1
- 功能2
## 安装
\`\`\`bash
npm install my-uts-plugin
\`\`\`
## 使用
\`\`\`typescript
import { method } from 'my-uts-plugin'
method()
\`\`\`
## API
### method(options)
描述...2. 配置 package.json
json
{
"name": "my-uts-plugin",
"version": "1.0.0",
"description": "我的 UTS 插件",
"main": "utssdk/index.uts",
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-android": "y",
"app-ios": "y"
}
}
}
},
"keywords": ["uniapp", "uts", "plugin"]
}3. 提交到插件市场
参考原生模块的发布流程。
最佳实践
1. 类型安全
充分利用 TypeScript 类型系统:
typescript
export interface Config {
timeout: number
retryCount: number
}
export function setConfig(config: Partial<Config>): void {
// 类型安全的配置
}2. 错误处理
typescript
export function riskyOperation(): Result<string, Error> {
try {
// 操作
return { success: true, data: "结果" }
} catch (e) {
return { success: false, error: new Error(e.message) }
}
}3. 平台兼容
typescript
export function platformSpecific(): string {
// #ifdef APP-ANDROID
return "Android"
// #endif
// #ifdef APP-IOS
return "iOS"
// #endif
// #ifdef WEB
return "Web"
// #endif
}常见问题
UTS 和 JS 有什么区别?
UTS 编译为原生代码,性能接近原生;JS 运行在 WebView 中,性能较低。
可以混用 UTS 和原生代码吗?
可以。UTS 可以调用原生 API,也可以和原生模块互操作。
UTS 支持所有 TypeScript 特性吗?
支持大部分,但有一些限制,如不支持装饰器、部分高级类型等。
