Skip to content

UTS 插件

UTS (uni TypeScript) 是 uniapp 推出的使用 TypeScript 开发原生插件的解决方案,让您可以用熟悉的语法编写跨平台原生代码。

什么是 UTS

特点

  • 📝 使用 TypeScript 语法
  • 🚀 接近原生的性能
  • 🔄 跨平台代码复用
  • 🛠️ 统一的开发体验
  • 📦 自动类型推导
  • 🎯 直接调用系统 API

与传统原生开发对比

特性传统原生UTS
语言Java/Kotlin + ObjC/SwiftTypeScript
学习成本
代码复用困难容易
类型安全部分完全
开发效率
性能100%95%+

快速开始

创建 UTS 插件

1. 使用脚手架

bash
npx degit dcloudio/uni-uts-plugin my-uts-plugin
cd my-uts-plugin

2. 项目结构

my-uts-plugin/
├── utssdk/
│   ├── interface.uts          # 接口定义
│   ├── app-android/           # Android 实现
│   │   └── index.uts
│   ├── app-ios/              # iOS 实现
│   │   └── index.uts
│   └── web/                  # Web 实现(可选)
│       └── index.uts
├── package.json
└── README.md

Hello 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

真机调试

  1. 连接设备
  2. 运行项目到真机
  3. 查看控制台输出
  4. 使用 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 特性吗?

支持大部分,但有一些限制,如不支持装饰器、部分高级类型等。


下一步

Released under the MIT License.