ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

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

uni-app iOS UTS扩展开发实战:Xcode环境配置、本地编译与真机调试全指南 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 Tools3.1 安装 Xcode可通过App Store安装或前往 Apple 开发者官网下载。安装 Xcode 时通常会同步骤安装Xcode IDE、Xcode命令行工具和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编译时保存 UTS 源码文件时IDE 会同步将其编译为对应的 Swift 代码并生成一个对应的插件 Framework 工程编译出对应的framework依赖库运行时真机运行/云打包时将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.08config.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.framework、config.json、index.uts、info.plist等文件可以作为标准目录范本对照学习。4.3 配置 Info.plist当插件需要在原生工程 Info.plist 中添加配置项时需在插件app-ios目录中创建Info.plist文件。其格式与配置规则与 iOS 工程一致云端打包时配置信息会合并到原生工程的 Info.plist 中。以 hello-uts 中腾讯定位插件的 info.plist 为例它配置了腾讯定位 APIKey 及后台定位权限?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keyTencentLBSAPIKey/key string您申请的APIKey/string keyUIBackgroundModes/key array stringlocation/string /array /dict /plist在 uts 代码中可通过Bundle.main.infoDictionary?[TencentLBSAPIKey]读取该配置见 腾讯定位插件 index.uts 中的configLocationManager()实现。4.4 配置 entitlementsUTS.entitlementsHBuilderX 3.6.11 支持当插件需要开启 capabilities 中的相关服务时在app-ios目录中创建UTS.entitlements文件。例如勾选 Access WiFi Information 项对应配置为?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keycom.apple.developer.networking.wifi-info/key true/ /dict /plistUTS.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 文件中 importHBuilderX 目前暂不支持.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.jsoniOS 平台原生配置config.json用于配置依赖的系统库、最低系统版本等信息仓库中的真实示例见 腾讯定位插件 config.json{ frameworks: [ libz.1.2.5.tbd ] }完整字段说明详见 UTS插件介绍 中 iOS 平台原生配置一节字段说明frameworks可选依赖的系统库有.framework、.tbd、.dylib类型deploymentTarget可选插件支持的最低 iOS 版本默认12.0应设为所有依赖三方库中最低支持版本号里的最高值identifier可选插件单独编译为动态库的 Bundle IdentifierHBuilderX 5.0validArchitectures可选支持的 CPU 架构默认arm64dependencies-pods可选需要依赖的 pod 库HBuilderX 3.8.5dependencies-pod-resourcesHBuilderX 5.25指定 pod 库资源打包后保存位置app保存到主应用、framework保存到 uts 插件动态库、all同时保存uni-app 项目默认alluni-app x 项目默认framework五、iOS 平台内置库 DCloudUTSFoundation 与 UTSiOSHBuilderX 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 的 keyWindowgetAppId()/getAppName()/getAppVersion()/getAppVersionCode()/getAppWgtVersion()获取 AppId、应用名称、版本名称、版本号、资源版本号getDataPath()/getDeviceId()/getModel()/getOsLanguage()/getSystemSetting()获取 dataPath、deviceId、设备型号、系统语言、系统设置isSimulator(): boolean是否是模拟器destroyInstance(obj: AnyObject): void销毁指定的原生实例对象HBuilderX 4.25uni-app xgetPointer(...)表示 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(titletitle,messagemessage,preferredStyleUIAlertController.Style.alert) let okAction new UIAlertAction(title确认, styleUIAlertAction.Style.default, handler(action: UIAlertAction):void { result(0) // 点击按钮的回调方法 }) let cancelAction new UIAlertAction(title取消, styleUIAlertAction.Style.cancel, handler(action: UIAlertAction):void { result(1) }) alert.addAction(okAction) alert.addAction(cancelAction) // 打开 alert 弹窗 UTSiOS.getCurrentViewController().present(alert, animated true) }) }这段代码同时演示了两个关键点线程模型uts 方法默认在子线程执行涉及 UI 操作必须通过DispatchQueue.main.async(execute():void { ... })切回主线程构造与命名参数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 null6.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: FatherUTS 用extends遵循协议Swift 用冒号class SomeClass: FirstProtocolUTS 用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-actionUTS 不支持 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 中用Mapstring, 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隐式转换得到UnsafePointerUTS 中用UTSiOS.getPointer(digest)表示符号常用于CC_MD5等 C 接口调用。6.9 Swift 特有修饰符与 keywordHBuilderX 4.06 支持open、fileprivate、internal、weak、optional等 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.requestany({ ... } as RequestOptionsany)。七、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 节不支持创建单例Swift 的static let shared写法在 uts class 中不可用仅在 uts 内部使用、不向 js export 的 class 可在混编 swift 中实现单例函数返回值不支持直接返回 class 类型需为该 class 创建 interface 并返回 interface 类型规范示例见 uts for iOS 6.7 节的RequestTask例子在interface.uts定义 interface → 在index.uts定义实现类 → export 函数返回 interface 类型函数参数不支持自定义 class 类型。八、iOS uts 调试uts 插件在 iOS 上的调试能力与 HBuilderX 版本相关详见 uts iOS调试调试能力版本要求uni-app (x) uts 插件调试iOS 17 以下HBuilderX 3.7.6uni-app (x) uts 插件调试iOS 17 以上HBuilderX 4.81uni-app x 的 jscore 调试HBuilderX 4.318.1 开启调试uni-app (x) 项目运行到 iOS 且包含 uts 插件或使用原生工程基座运行成功后点击 HBuilderX 控制台的红色虫子图标下拉菜单选择【开启uts调试(swift)】或【开启uts调试(jscore)】此功能仅 Mac 支持。首次开启 uts 调试(swift) 需要重新编译动态库遇到确认弹窗请点击【确定】。8.2 断点与调试视图在要调试的 uts 文件代码行号上鼠标右击或双击即可添加断点。开启调试后HBuilderX 左侧显示调试视图分为 5 部分调试工具栏、变量窗口、监视窗口、调用堆栈窗口、断点窗口。调试快捷键继续F8、下一步F10、进入F11、返回ShiftF11。可在变量窗口右键将变量添加到监视或将鼠标悬停到变量上打开悬停窗口查看值。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_modulesUTSiOS 内置对象完整 APIUTSiOSiOS 调试指南uts iOS调试可运行示例examples/hello-uts工程中的uts-alert、uts-toast、uts-tencentgeolocation、uts-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),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进