从桌面工程复制而来,作为本仓库的 Xuxucheck/ 子目录。 为控制仓库体积做了两处删减: - 移除 Frameworks/opencv2.xcframework 下的两个 visionOS 切片 (xros-arm64、xros-arm64-simulator,合计约 106 MB),并同步删掉该 xcframework 内 Info.plist 里对应的两条 AvailableLibraries 记录, 只保留 ios-arm64 与 ios-arm64_x86_64-simulator。 - 移除全部 .DS_Store 与 xcuserdata/。 已用 xcodebuild 从本目录完整编译验证:BUILD SUCCEEDED, ProcessXCFramework 以 --platform ios 成功选中框架,产物含 3699 个 cv:: 符号 (OpenCV 确实链入),嵌入 framework 3 个,与移除无用 pod 之后的状态一致。 仓库约 206 MB,其中 OpenCV 203 MB、其余源码与依赖约 3 MB。
XuXuCheck
干化学尿液试纸分析 App(iOS / SwiftUI)。用户用相机拍摄试纸,App 通过 C++/OpenCV 定位试纸、
跨 16 帧采样 16 个试剂垫,再把 HSV/Lab 测量值上传服务端。除相机与扫描流程外,其余界面
(产品介绍、记录、成员、我的)都是服务端渲染的网页,由 WKWebView 承载。
| Bundle ID | com.niaodaifu.xuxu.XuXuCheck |
| Deployment Target | iOS 18.4 |
| 开发语言 | Swift 5.0 + Objective-C++(OpenCV 桥接) |
| 界面语言 | 英文(App 内置)/ 中文(业务域) |
| 版本管理 | https://git.china-planet.com/admin/ios.git 的 Xuxucheck/ 子目录 |
本目录是 git 仓库里的副本,由桌面版工程复制而来,为控制仓库体积做了两处删减: 删掉了
Frameworks/opencv2.xcframework/里的两个 visionOS 切片(xros-arm64、xros-arm64-simulator,合计约 106 MB)以及所有.DS_Store/xcuserdata/。 切片是连同 xcframework 内的Info.plist一起删的,只保留ios-arm64与ios-arm64_x86_64-simulator—— 本工程只构建 iOS,不受影响(已编译验证)。 桌面上的原始工程仍是完整四切片版本,两者内容一致,只有这一处差异。
一、环境要求
| 项 | 要求 |
|---|---|
| macOS | 任意较新版本 |
| Xcode | 16.3 或更高(deployment target 为 iOS 18.4,需要 iOS 18.4 SDK)已在本机 Xcode 27.0(Build 27A266a)验证 |
| CocoaPods | 不需要安装 —— 依赖已随项目提供,见第三节 |
| iOS 真机 | 相机 / 扫描流程必须真机;模拟器只会显示空白相机分支 |
| Apple ID | 需要能用于签名的账号,见第四节 |
二、编译方式
必须打开 XuXuCheck.xcworkspace,不是 XuXuCheck.xcodeproj。
后者不带 Pods 依赖,打开会报一大堆找不到符号的错误。
open XuXuCheck.xcworkspace
图形界面:选中 XuXuCheck scheme 和目标设备 → ⌘R。
命令行(先用 xcrun devicectl list devices 查设备 id):
# 真机
xcodebuild -workspace XuXuCheck.xcworkspace -scheme XuXuCheck \
-configuration Debug -destination 'id=<设备 id>' \
-allowProvisioningUpdates build
# 只验证能否编译,不依赖具体设备
xcodebuild -workspace XuXuCheck.xcworkspace -scheme XuXuCheck \
-destination 'generic/platform=iOS' build
第一次编译会比较久(数分钟):7 个 pod 全部从源码编译,加上大量 OpenCV 头文件。 这是正常的,不是卡住。
测试 target 目前是空壳(XuXuCheckTests 用 Swift Testing,XuXuCheckUITests 用 XCTest),
跑单个用例:
xcodebuild -workspace XuXuCheck.xcworkspace -scheme XuXuCheck \
-only-testing:XuXuCheckTests/XuXuCheckTests/example test
三、依赖已随仓库提供,无需恢复
OpenCV
-
位置:
Frameworks/opencv2.xcframework(203 MB) -
切片:
ios-arm64、ios-arm64_x86_64-simulator(桌面版工程另有xros-arm64、xros-arm64-simulator两个 visionOS 切片,本仓库为控制体积已删除,见开头的说明); 两个都是 静态库,因此没有 Embed 阶段,运行时不依赖任何 opencv 文件(代码已编进 App) -
工程中只有一处引用,在
XuXuCheck.xcodeproj/project.pbxproj:path = Frameworks/opencv2.xcframework; sourceTree = "<group>" -
工程里没有
FRAMEWORK_SEARCH_PATHS/HEADER_SEARCH_PATHS:构建时 Xcode 的ProcessXCFramework会把对应切片拷进 DerivedData,编译器与链接器通过自动的-F$(BUILT_PRODUCTS_DIR)找到它 -
#include <opencv2/opencv.hpp>走的是 framework 式查找 →opencv2.framework/Headers/opencv.hpp, 所以不需要额外的头文件搜索路径 -
⚠️ 不要把它改成指向
~/Downloads/opencv2.framework。那是 OpenCV 4.11.0 官方 fat 包 (含i386/armv7,没有独立的模拟器切片),与本项目使用的自建 xcframework 不是同一个东西 -
框架包内是 macOS 经典的版本化布局(
opencv2、Headers、Resources都是指向Versions/Current/*的符号链接,Versions/Current再指向A),终点在包内,不指向任何外部目录
CocoaPods
Pods/ 目录已完整随项目提供(pod 源码、Pods.xcodeproj、Target Support Files 齐全),
所以:
-
不需要执行
pod install,新机器连 CocoaPods 都不用装。工程里三个[CP]脚本阶段 都是纯 shell(diff比对 lock + 运行生成的.sh),构建时不调用pod命令 -
依赖清单(共 3 个):
Alamofire4.x(不是 5.x)、AlamofireObjectMapper5.2, 以及它带进来的ObjectMapper3.5 -
因为 Alamofire 是 4.x,代码里的
Alamofire.request(...)和DataResponse<T>是正确写法, 不要"顺手"升级。Alamofire 也升不动:AlamofireObjectMapper5.2.1 要求Alamofire ~> 4.7, 要上 5.x 就必须先把它换成Codable,牵连 6 个Mappable类、32 处<-和 6 处.responseObject -
原先还依赖
ProgressHUD、SDWebImage+SDWebImageSwiftUI、WrappingHStack,但 App 代码 从未 import 过任何一个(全仓零引用)。use_frameworks!会把每个 pod 都做成动态 framework 并嵌进.app,所以它们每次构建都要编译、启动时都要加载 —— 已移除,嵌入框架由 7 个/6.4 MB 降到 3 个/2.8 MB -
⚠️ 改
Podfile后跑pod install必须用 1.16.2:gem install cocoapods -v 1.16.2 pod install用其它版本会重写
Pods.xcodeproj,可能引入不必要的差异 -
⚠️
pod install会重新生成Pods.xcodeproj,这里曾经埋着一个雷:podspec 自己声明的最低 部署目标是 8.0,而 Xcode 27 只接受 15.0~27.0,低于 15.0 会在编译任何代码之前就报错 (The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 15.0 to 27.0.x)。原来的工程是手工把这 22 处改成 15.6 才能编译的,而手工改动每次pod install都会被覆盖 —— 也就是说以前任何人跑一次pod install,这个项目就编译不过了,只是没人跑过。现在改由
Podfile末尾的post_install钩子统一设置,重新生成也不会丢。不要把这段挪回 手工改工程文件,那样等于把这个坑重新埋上
四、签名
当前配置:自动签名(CODE_SIGN_STYLE = Automatic),Team BK4A926286。
在另一台 Mac 或另一个账号上编译时,二选一:
- 沿用同一团队 —— 把新机器的 Apple ID 加入团队成员,并在该 Mac 的 Xcode 里登录, 自动签名会签发新证书。
- 换成自己的账号 —— 修改
DEVELOPMENT_TEAM,但必须同时修改 Bundle ID (com.niaodaifu.xuxu.XuXuCheck属于原团队),例如改成com.yourname.XuXuCheck。 免费个人账号也可以跑起来。
常见报错与对策:
| 报错 | 原因与处理 |
|---|---|
No profiles for 'com.niaodaifu.xuxu.XuXuCheck' were found 并伴随 PLA Update available ... Account Holder ... must agree |
团队协议未接受,会锁住该团队的证书/描述文件资源。只有 Account Holder 能在 developer.apple.com 后台处理 |
Your account already has an Apple Development signing certificate ... but its private key is not installed |
指的是历史(常为已过期)证书的私钥不在本机钥匙串。通常新证书已可用;确认无用后可在钥匙串里删掉那张旧证书 |
编译到 Embed Pods Frameworks 时报 errSecInternalComponent |
钥匙串拒绝了 codesign 使用私钥。用 Xcode 图形界面编译一次并在弹窗点「始终允许」,或检查该证书私钥的「访问控制」 |
五、复制到另一台 Mac
整包复制即可编译,不需要 pod install。 因为 Pods/、opencv、工程文件里
没有任何 /Users/... 绝对路径(已逐文件核查),整个目录也不依赖项目之外的任何东西。
注意事项:
- 不要放在 Desktop / Documents / Downloads —— macOS 隐私保护会拦截 Xcode 和命令行对其的访问
(表现为
Operation not permitted)。建议放~/Developer/之类不设防的位置 - 拷贝前建议删掉本机残留:各处的
xcuserdata/(工程里共 4 处,含个人窗口/断点状态)与.DS_Store - 在新机器上打开
XuXuCheck.xcworkspace,签名按第四节调整 - 首次编译同样需要数分钟
- 目录体积约 206 MB(其中 opencv 203 MB、
Pods0.9 MB),传输较慢
六、目录结构
XuXuCheck/
├── XuXuCheck.xcworkspace ← 打开这个
├── XuXuCheck.xcodeproj
├── Frameworks/
│ └── opencv2.xcframework ← 309 MB,自带的 OpenCV
├── Pods/ ← 已随项目提供,无需 pod install
├── Podfile / Podfile.lock ← CocoaPods 1.16.2
├── XuXuCheck/ ← App 源码(SwiftUI + opencv/ 下的 C++ 管线)
├── XuXuCheckTests/ ← 空壳
├── XuXuCheckUITests/ ← 空壳
├── docs/ ← 专题说明(含实测数据)
├── CLAUDE.md ← 架构说明与非显而易见的坑
└── README.md
七、已知坑
- Debug 产物是分裂的:Xcode 16+ 的 debug-dylib 机制下,真实代码在
XuXuCheck.debug.dylib(约 10 MB),主可执行文件只有约 90 KB、只是个壳。 判断"OpenCV 有没有链进去"要看前者,别看错文件 - 模拟器没有相机,扫描流程必须真机
- 本目录不是 git 仓库,没有历史可回溯,改动前请自行备份
- 更多架构说明见
CLAUDE.md;WebView 顶部/底部边距的处理与实测数据见docs/webview-safe-area.md