uni-app iOS UTS扩展开发实战:Xcode环境配置、本地编译与真机调试全指南
2026/9/20 6:14:11 网站建设 项目流程

uni-app iOS UTS扩展开发实战:Xcode环境配置、本地编译与真机调试全指南

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

本文基于 uni-app 开源仓库(gh_mirrors/un/uni-app)中的官方文档与hello-uts示例工程整理编写。核心脉络来自 iOS UTS扩展开发,并参考 uts for iOS、UTS插件介绍、UTSiOS 内置对象、uts iOS调试 等文档及仓库示例源码进行纵深扩充。

导读

uni-app 生态中,UTS 插件(uni type script 插件)允许开发者用类 TypeScript 的强类型语法直接调用 iOS 原生 API 与三方 SDK,并编译为 Swift 代码运行。本指南聚焦iOS 平台 UTS 扩展开发:从 HBuilderX 3.6.9+ 起,你可以在本地修改 uts 插件的 iOS 平台代码,直接本地编译并真机运行到 iOS 设备,而无需再提交代码到云端制作自定义基座。读完本文,你将掌握 iOS UTS 插件的完整开发链路——Xcode 环境配置、插件目录与原生配置项、DCloudUTSFoundation内置库、Swift 与 UTS 的关键语法差异、真机调试与常见问题排查。

一、版本要求与能力总览

iOS 平台的 uts 插件本地开发能力自HBuilderX 3.6.9+版本开始提供,核心能力是:

  • 本地编译:无需将代码上传云端,即可在本地将 uts 插件的 iOS 平台代码编译为 Swift;
  • 真机运行:直接运行到 iOS 真机设备,快速验证插件效果。

这意味着插件开发周期大幅缩短:以往修改 iOS 原生代码后需要等待云端打包自定义基座,现在本地修改、本地编译、真机运行一气呵成。使用前提是必须配置 Xcode 环境(详见下文),并且必须安装「uts开发扩展 - iOS」插件

版本注意:HBuilderX 3.6+ 支持在 uni-app 中使用 uts 插件,HBuilderX 3.9+ 支持在 uni-app x 中使用 uts 插件。本文所述的 iOS 本地编译与真机运行能力,面向 HBuilderX 3.6.9+。

二、安装 uts 扩展插件

当你把带有 uts 插件的项目运行到 iOS 真机设备时,HBuilderX 会自动检测并提示安装【uts开发扩展 - iOS】插件。该插件是 iOS 平台 uts 插件本地编译与真机运行的基础依赖,请务必安装,否则无法继续。

安装后,本地修改 uts 插件utssdk/app-ios目录下的代码,即可在本地编译并真机运行,无需再走云端制作自定义基座流程。

三、Xcode 环境配置

本地真机运行 uts 插件目前有以下硬性环境要求:

环境项要求
操作系统macOS(必需)
XcodeXcode 15.2 或更高版本
Command Line Tools与 Xcode 版本相同的 Xcode Command Line Tools

3.1 安装 Xcode

可通过App Store安装,或前往 Apple 开发者官网下载。安装 Xcode 时通常会同步骤安装Xcode IDEXcode命令行工具和iOS模拟器。

新下载 Xcode 后,必须打开一次 Xcode,并确认命令行工具已正确配置。

3.2 检查 Xcode Command Line Tools

命令行工具中包含一些必须的工具(如git等)。启动 Xcode 后,在Xcode | Settings(或 Preferences)| Locations菜单中检查Command Line Tools是否已选择某个版本。

请确保在使用 uts 插件真机运行之前,本地环境已完成如上配置。若 Command Line Tools 未配置,真机运行编译 uts 插件时会直接报错。

3.3 Xcode 版本相关的踩坑提示

针对 Xcode 版本,仓库文档还给出两点重要提示(详见 uts for iOS 第 8 章):

  • 高版本 Xcode 编译的 Swift 语言 Framework 动态库、静态库、.a库在低版本 Xcode 上无法编译通过,存在 Swift 版本兼容性问题;
  • 若真机运行编译 uts 插件时报 swift 版本不兼容错误,先检查本地 Xcode 版本,确保本地 Xcode 版本大于或等于云端打包机使用的 Xcode 版本;
  • 若报XCode 版本应大于 13.2.1的错误,说明本地 Xcode 版本过低,直接升级到大于或等于打包机的版本即可(该提示中的 13.2.1 限制可忽略,后续版本会优化提示文案)。

四、iOS uts 插件的工作原理与目录结构

4.1 编译期与运行期行为

对 iOS 开发者而言,uts 插件有两个关键阶段(见 uts for iOS):

  1. 编译时:保存 UTS 源码文件时,IDE 会同步将其编译为对应的 Swift 代码,并生成一个对应的插件 Framework 工程,编译出对应的framework依赖库;
  2. 运行时:真机运行/云打包时,将framework依赖库添加到打包工程,生成最终的 ipa 包。

也就是说:UTS 在 iOS 平台上最终编译为 Swift 源码。即使开发 UTS 插件不强制要求掌握 Swift,熟悉 Swift 语法对排查问题和实现复杂功能都很有帮助。

4.2 app-ios 目录结构

UTS 插件建议以 uni_modules 方式组织。在插件utssdk/app-ios目录下,存放 iOS 平台的原生配置与实现(详见 UTS插件介绍):

目录名/文件名用途
Frameworks插件引用的三方 framework / xcframework 依赖库存放目录
Libs插件引用的三方.a依赖库存放目录(HBuilderX 3.7.2+ 支持)
Resources需要合并到应用 Main Bundle 的资源文件目录(图片、音频等)
EmbedResources合并到编译插件生成的动态库 Framework Bundle 中的资源目录(HBuilderX 5.08+)
config.jsoniOS 平台原生工程配置文件
index.uts主入口,interface.uts声明的能力在 iOS 平台下的实现
Info.plist需要添加到原生工程 Info.plist 的配置
PrivacyInfo.xcprivacy插件隐私清单文件
UTS.entitlements需要添加到原生工程 entitlements 的配置
hybrid.swiftiOS 混编的 swift 文件
interceptor.jsjs 调用插件代码的拦截器

仓库中的真实示例见 hello-uts 的 uts-tencentgeolocation 插件目录,其中实际包含了Frameworks/TencentLBS.frameworkconfig.jsonindex.utsinfo.plist等文件,可以作为标准目录范本对照学习。

4.3 配置 Info.plist

当插件需要在原生工程 Info.plist 中添加配置项时,需在插件app-ios目录中创建Info.plist文件。其格式与配置规则与 iOS 工程一致,云端打包时配置信息会合并到原生工程的 Info.plist 中。

以 hello-uts 中腾讯定位插件的 info.plist 为例,它配置了腾讯定位 APIKey 及后台定位权限:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>TencentLBSAPIKey</key> <string>您申请的APIKey</string> <key>UIBackgroundModes</key> <array> <string>location</string> </array> </dict> </plist>

在 uts 代码中,可通过Bundle.main.infoDictionary?["TencentLBSAPIKey"]读取该配置(见 腾讯定位插件 index.uts 中的configLocationManager()实现)。

4.4 配置 entitlements(UTS.entitlements)

HBuilderX 3.6.11+ 支持

当插件需要开启 capabilities 中的相关服务时,在app-ios目录中创建UTS.entitlements文件。例如勾选 Access WiFi Information 项,对应配置为:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.networking.wifi-info</key> <true/> </dict> </plist>

UTS.entitlements格式及配置规则与 iOS 工程一致,云端打包时会合并到原生工程的 entitlements 配置文件中。

4.5 依赖资源文件与三方库

  • 资源文件:放到插件目录~/utssdk/app-ios/Resources/,云端打包时该目录下所有文件会添加到应用 main bundle 中,建议只保存 uts 插件内置资源;
  • 三方 framework/xcframework:存放到~/utssdk/app-ios/Frameworks/,云端打包时全部添加到工程,目前支持静态库和动态库;
  • 三方.a:存放到~/utssdk/app-ios/Libs/。注意.a库的所有文件(.a文件与对应.h/.swiftmodule)须放在同一个文件夹内,多个.a库创建多个文件夹,且不要把.a.h嵌套在多层文件夹内(不会递归查找)。OC 创建的.a库使用时无需 import 可直接使用;Swift 创建的.a库使用前需在 uts 文件中 import;HBuilderX 目前暂不支持.a库相关代码的语法提示。

关于不包含 Modules 的 framework:部分 OC 开发的第三方 SDK 产物.framework内不含 Modules 文件夹,不支持 use module 模式,不能直接在 Swift 文件中导入,也无法直接被 uts 插件引用。有源码时可在 Xcode 中创建与 SDK target 同名的.h头文件并设为 public,或通过module.map.modulemap自定义 Module Map 后重新编译;无源码时可在TestSDK.framework文件夹下手动创建Modules/module.modulemap文件声明需要暴露的头文件(详见 uts for iOS 3.4.3 节)。

4.6 config.json:iOS 平台原生配置

config.json用于配置依赖的系统库、最低系统版本等信息,仓库中的真实示例见 腾讯定位插件 config.json:

{ "frameworks": [ "libz.1.2.5.tbd" ] }

完整字段说明(详见 UTS插件介绍 中 iOS 平台原生配置一节):

字段说明
frameworks可选,依赖的系统库(有.framework.tbd.dylib类型)
deploymentTarget可选,插件支持的最低 iOS 版本,默认12.0;应设为所有依赖三方库中最低支持版本号里的最高值
identifier可选,插件单独编译为动态库的 Bundle Identifier(HBuilderX 5.0+)
validArchitectures可选,支持的 CPU 架构,默认arm64
dependencies-pods可选,需要依赖的 pod 库(HBuilderX 3.8.5+)
dependencies-pod-resourcesHBuilderX 5.25+,指定 pod 库资源打包后保存位置:app保存到主应用、framework保存到 uts 插件动态库、all同时保存(uni-app 项目默认all,uni-app x 项目默认framework

五、iOS 平台内置库 DCloudUTSFoundation 与 UTSiOS

HBuilderX 3.6.11+ 支持

DCloudUTSFoundation为框架内置库,所有 uts 插件都会依赖此基础库,封装了一些常用方法便于开发者直接调用。使用时需先在 uts 文件中导入UTSiOS类,所有方法都通过该类调用:

import { UTSiOS } from "DCloudUTSFoundation"

完整的 UTSiOS 静态方法清单可查看 UTSiOS 内置对象文档,常用方法包括:

方法说明
getCurrentViewController(): UIViewController获取当前 app 显示的 UIViewController 实例
colorWithString(value: string): UIColor将字符串色值转换为 UIColor(转换失败返回黑色)
getResourcePath(resourceName: string): string获取指定插件资源的运行期绝对路径
convert2AbsFullPath(inputPath: string): string将文件的项目相对地址转换为运行期绝对地址
getKeyWindow(): UIWindow获取当前 app 的 keyWindow
getAppId()/getAppName()/getAppVersion()/getAppVersionCode()/getAppWgtVersion()获取 AppId、应用名称、版本名称、版本号、资源版本号
getDataPath()/getDeviceId()/getModel()/getOsLanguage()/getSystemSetting()获取 dataPath、deviceId、设备型号、系统语言、系统设置
isSimulator(): boolean是否是模拟器
destroyInstance(obj: AnyObject): void销毁指定的原生实例对象(HBuilderX 4.25+,uni-app x)
getPointer(...)表示 Swift 指针操作中的&符号

5.1 getCurrentViewController 实战:uts-alert 插件

仓库中的 uts-alert 插件 index.uts 是 UTSiOS 最典型的应用示例——弹出系统对话框:

import { UTSiOS } from "DCloudUTSFoundation" import { DispatchQueue } from 'Dispatch'; export function showAlert(title: string|null, message: string|null, result: (index: Number) => void) { // uts方法默认会在子线程中执行,涉及 UI 操作必须在主线程中运行 DispatchQueue.main.async(execute=():void => { let alert = new UIAlertController(title=title,message=message,preferredStyle=UIAlertController.Style.alert) let okAction = new UIAlertAction(title="确认", style=UIAlertAction.Style.default, handler=(action: UIAlertAction):void => { result(0) // 点击按钮的回调方法 }) let cancelAction = new UIAlertAction(title="取消", style=UIAlertAction.Style.cancel, handler=(action: UIAlertAction):void => { result(1) }) alert.addAction(okAction) alert.addAction(cancelAction) // 打开 alert 弹窗 UTSiOS.getCurrentViewController().present(alert, animated= true) }) }

这段代码同时演示了两个关键点:

  1. 线程模型:uts 方法默认在子线程执行,涉及 UI 操作必须通过DispatchQueue.main.async(execute=():void => { ... })切回主线程;
  2. 构造与命名参数:UTS 中使用new关键字创建实例,参数用=连接(见下一节语法差异)。

5.2 colorWithString 与 getResourcePath

// 字符串色值转 UIColor,支持 #f00、#ff0000、rgb(255,0,0)、rgba(255,0,0,0.5)、red 等格式 let bgColor = UTSiOS.colorWithString("#000000") view.backgroundColor = bgColor // 获取运行期绝对路径 const imagePath = UTSiOS.getResourcePath("/static/logo.png") const image = new UIImage(contentsOfFile = imagePath) /* imagePath 示例: "/var/mobile/Containers/Data/Application/FA7080BA-.../Documents/Pandora/apps/__UNI__FB95CAB/www/static/logo.png" */

六、Swift 与 UTS 差异重点(面向 Swift 开发者)

对于熟悉 iOS 开发的 Swift 语言者,UTS 在语法上有不少"习惯性差异",以下是最容易踩坑的要点(完整清单见 uts for iOS 第 5 章)。

6.1 常量和变量

// swift var str = "abc" // 变量 let str1 = "abc" // 常量
// uts let str = "abc" // 变量 const str1 = "abc" // 常量

6.2 可选类型

// swift var user: String? = nil
// uts let user: string | null = null

6.3 构造方法、函数参数、枚举值

语法点SwiftUTS
实例化UIAlertController()new UIAlertController()(需new
参数连接title: "提示"(冒号)title="提示"(等号)
枚举.alert可简写UIAlertController.Style.alert必须写全

UTS 目前不支持带关联值的枚举(如enum Barcode { case upc(Int, Int, Int, Int) })。若三方库中此类枚举无法改动,可在 Swift 文件中调用并打包进 framework 供 uts 插件使用;若有源码,可改为不含关联值的枚举 + 合适的数据结构表示关联信息。

6.4 类继承与协议

  • 继承:Swift 用冒号class Son: Father,UTS 用extends
  • 遵循协议:Swift 用冒号class SomeClass: FirstProtocol,UTS 用implements,可同时 implements 多个协议。

6.5 系统版本判断

Swift 的if #available(iOS 10.0, *)在 UTS 中写作:

if (UTSiOS.available("iOS 10.0, *")) { }

标记 class 或函数的最低系统版本:

@available(iOS 15.0, *) class Test { test1() {} } class Test1 { @UTSiOS.available("iOS 16.1, *") test2() {} }

注意:当前 uts不支持对 class 属性设置系统版本号约束。存储属性会直接编译报错Stored properties cannot be marked potentially unavailable with '@available';计算属性虽然编译不报错但约束不生效(已知问题,后续版本会修复)。

6.6 闭包、@escaping 与 target-action

  • UTS 不支持 Swift 的尾随闭包简写,handler闭包必须写完整;原生逃逸闭包参数前需加@escaping
  • 调用原生 target-action 方法(如给UIButton添加点击事件、注册通知中心事件)时:selector 通过Selector("方法名字符串")构建,定义的回调方法需要添加@objc前缀。仓库中的 uts-screenshot-listener 插件 是监听截屏事件的完整示例:
const method = Selector("userDidTakeScreenshot") NotificationCenter.default.addObserver(this, selector = method, name = UIApplication.userDidTakeScreenshotNotification, object = null) @objc static userDidTakeScreenshot() { const obj = new UTSJSONObject() this.listener?.(obj) }

6.7 字典、参数标签与异步方法

  • Swift 的Dictionary在 UTS 中用Map<string, any>代替(map.set("name","uts"));
  • 实现三方 SDK 的协议方法时,带参数标签的方法参数需用注解@argumentLabel("didUpdate")表示;无参数标签的参数需传空字符串@argumentLabel(""),例如高德定位的reGeocode参数;
  • 异步方法:Swift 在参数列表后加async关键字,UTS 在方法最前面加async关键字。使用async定义异步方法仅 iOS 13+ 支持,低版本调用会报错

6.8 try / try? / try! 与指针操作

UTS 通过UTSiOS.try(...)支持 Swift 的三种 try 写法:

// try:与 do-catch 配合 try { let dict = UTSiOS.try(JSONSerialization.jsonObject(with = data, options = [])) } catch (e) { console.log(e) } // try?:失败返回 nil UTSiOS.try(JSONSerialization.jsonObject(with = data, options = []), "?") // try!:失败会闪退 UTSiOS.try(JSONSerialization.jsonObject(with = data, options = []), "!")

指针操作:Swift 中&digest隐式转换得到UnsafePointer,UTS 中用UTSiOS.getPointer(digest)表示&符号,常用于CC_MD5等 C 接口调用。

6.9 Swift 特有修饰符与 @keyword

HBuilderX 4.06+ 支持

openfileprivateinternalweakoptional等 Swift 特有修饰符在 ts 中没有对应物,UTS 提供@UTSiOS.keyword("xxx")语法糖,在符合 Swift 语法要求的场景下使用:

// 将一个类设为 private @UTSiOS.keyword("private") class TestA { // 用 weak 修饰属性避免循环引用 @UTSiOS.keyword("weak") private delegate: TestProtocol | null = null }

6.10 显式标注类型

uts 插件环境中无法默认推断类型,需要显式标注类型,例如uni.request<any>({ ... } as RequestOptions<any>)

七、uts 插件开发最佳实践与常见问题

7.1 interface.uts 声明与 index.uts 实现

官方推荐的多端一致性最佳实践:在插件根目录interface.uts中统一声明对外暴露的 API 类型、参数类型、返回值类型、错误码类型(建议遵循 uni 错误规范,错误码以90开头),再在各平台index.uts中做具体实现。若不跨端(如只做 iOS 插件),也可以直接在分平台目录写index.uts(详见 UTS插件介绍)。

7.2 获取当前 UIViewController 与操作 UI 线程

  • 获取 UIViewController:参考 hello-uts 中的 uts-alert 插件(即上文 5.1 节示例);
  • 操作 UI 线程:DispatchQueue.main.async(execute=():void => { ... }),参考 uts-toast 插件。

7.3 销毁原生对象实例(内存管理)

HBuilderX 4.25+ 支持

uts 插件中通过export导出给 js 用的 class,创建的实例会一直被保存在内存中,不主动销毁可能造成内存泄漏。解决方案是在类中实现destory()方法调用UTSiOS.destroyInstance(this),并在使用该对象的页面unmounted()时机调用:

// uts 插件中 export class Test { id: number name: string constructor(id: number, name: string) { this.id = id this.name = name } doSomething() { console.log("do something") } destory() { UTSiOS.destroyInstance(this) } }
// uvue 页面 let test = new Test("1111", "name_11111") test.doSomething() this.test = test unmounted() { this.test.destory() }

7.4 避免闭包循环引用

自定义 class 中若定义了闭包类型属性,而闭包内部又访问了 class 的其他属性或自身,就会形成循环引用导致内存泄漏。解决方式是在闭包体最开头添加"[weak self]"标记:

doSomething() { if (this.callback == null) { this.callback = (res: string) => { "[weak self]" // 标记后 this 变为可空 console.log(this?.name, res) // 需用可选链或非空断言 } } this.callback?.("like basketball") }

判断标准:callback 是否被 this 持有,且闭包内是否访问了 this,两条都满足就需要加标记。使用标记后this变成可为空的值,访问属性和方法必须使用可选链或非空断言。

7.5 向 js 导出 class 的三个限制

需要向 js export 并在 uvue 页面中使用的 class 有以下明确限制(详见 uts for iOS 6.9 节):

  1. 不支持创建单例(Swift 的static let shared写法在 uts class 中不可用;仅在 uts 内部使用、不向 js export 的 class 可在混编 swift 中实现单例);
  2. 函数返回值不支持直接返回 class 类型,需为该 class 创建 interface 并返回 interface 类型(规范示例见 uts for iOS 6.7 节的RequestTask例子:在interface.uts定义 interface → 在index.uts定义实现类 → export 函数返回 interface 类型);
  3. 函数参数不支持自定义 class 类型

八、iOS uts 调试

uts 插件在 iOS 上的调试能力与 HBuilderX 版本相关(详见 uts iOS调试):

调试能力版本要求
uni-app (x) uts 插件调试(iOS 17 以下)HBuilderX 3.7.6+
uni-app (x) uts 插件调试(iOS 17 以上)HBuilderX 4.81+
uni-app x 的 jscore 调试HBuilderX 4.31+

8.1 开启调试

uni-app (x) 项目运行到 iOS 且包含 uts 插件(或使用原生工程基座),运行成功后点击 HBuilderX 控制台的红色虫子图标,下拉菜单选择【开启uts调试(swift)】或【开启uts调试(jscore)】(此功能仅 Mac 支持)。首次开启 uts 调试(swift) 需要重新编译动态库,遇到确认弹窗请点击【确定】。

8.2 断点与调试视图

在要调试的 uts 文件代码行号上,鼠标右击或双击即可添加断点。开启调试后,HBuilderX 左侧显示调试视图,分为 5 部分:调试工具栏、变量窗口、监视窗口、调用堆栈窗口、断点窗口。调试快捷键:继续F8、下一步F10、进入F11、返回Shift+F11。可在变量窗口右键将变量添加到监视,或将鼠标悬停到变量上打开悬停窗口查看值。

8.3 注意事项

  • 开启 uts 调试依赖 uts 调试插件,弹窗提示安装依赖插件时务必点击安装,否则无法调试;
  • uts 调试(swift) 显示连接成功后可能需要等待十几秒方可使用;调试进程codelldb会占用较大内存;调试模式下修改 uts 插件导致重装 App 可能失败;基座重装后需重新开启调试;
  • jscore 调试需在手机 "设置" > "Safari" > "高级" > "Web检查器" 中打开开关;服务开启成功后,修改编译为 jscore 的代码,热更新后会自动重连调试。

九、已知待解决问题

当前 HBuilderX 写 iOS uts 插件时部分语法提示仍有缺失(如构造方法只提示一个、缺失可选类型标识、参数标签无标记、不支持导入含子模块的原生模块、暂不支持.a库代码提示);类型兼容方面元组类型目前不支持。这些问题会在后续版本中优化(详见 uts for iOS 第 7 章)。

十、继续深入

  • 完整的 iOS uts 插件教程:uts for iOS(含.a库使用、无 Modules framework 处理、AppIntents/Shortcuts 支持、pod 依赖等进阶内容)
  • 插件整体架构与目录规范:UTS插件介绍、uni_modules
  • UTSiOS 内置对象完整 API:UTSiOS
  • iOS 调试指南:uts iOS调试
  • 可运行示例:examples/hello-uts工程中的uts-alertuts-toastuts-tencentgeolocationuts-screenshot-listener等插件(源码位于examples/hello-uts/uni_modules/下),是学习 iOS uts 插件开发的最佳范本

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询