Files
duooomi-ble-sdk/BUILD_ISSUES.md
2026-04-08 15:36:13 +08:00

7.1 KiB
Raw Permalink Blame History

构建问题记录

问题 1expo prebuild 报 EEXIST 目录冲突

现象npx expo prebuild --platform ios 报错 EEXIST: file already exists, mkdir 'ios/DuooomiBleSDK'

原因macOS 文件系统大小写不敏感。Expo prebuild 先创建 ios/duooomiblesdk(小写),然后 expo-brownfield 插件尝试创建 ios/DuooomiBleSDK(驼峰),被视为同一目录导致 EEXIST。

修复patch expo-brownfieldplugin/build/ios/utils/filesystem.js,将 mkdirrecursive 参数默认值改为 true

// 修改前
const mkdir = (path, recursive = false) => {
// 修改后
const mkdir = (path, recursive = true) => {

注意:这是 node_modules 内的 patchpnpm install 后会丢失。如需持久化,使用 pnpm patch expo-brownfield


问题 2CocoaPods ffi_c 加载失败

现象pod install 报错 LoadError - cannot load such file -- ffi_c

原因:终端运行在 Rosetta2 x86_64 模拟环境下,导致 Ruby gem 的原生扩展ffi、nkf架构与解释器不匹配。

修复:强制使用 arm64 原生架构运行:

env /usr/bin/arch -arm64 /bin/bash --login -c 'source ~/.rvm/scripts/rvm && rvm use 2.7.5 && pod install --project-directory=ios'

问题 3Xcode 26 编译 fmt 库失败(已解决)

现象BUILD FAILED,错误为 call to consteval function ... is not a constant expression,出现在 fmt/format-inl.h

原因Xcode 26 的 Apple Clang 17+ 声明支持 __cpp_constevalfmt 11.0.2 据此启用 consteval 关键字,但编译器实现存在 bug 导致编译失败。

修复patch ios/Pods/fmt/include/fmt/base.h,在 consteval 检测逻辑中禁用 Apple Clang 17+

// 在 __apple_build_version__ < 14000029L 判断之后添加:
#elif defined(__apple_build_version__) && __apple_build_version__ >= 17000000L
#  define FMT_USE_CONSTEVAL 0  // consteval is broken in Apple clang 17+ (Xcode 26).

注意pod install 会重新下载 Pods此 patch 需要在每次 pod install 后重新应用。


问题 4签名错误已解决

现象Signing for "duooomiblesdk" requires a development team

原因Expo Brownfield 构建过程会编译宿主 App targetXcode 对 App target 强制要求签名。

修复xcodebuild 参数中加 CODE_SIGNING_ALLOWED=NO


问题 5RCTAppDependencyProvider.h 缺失(已解决)

现象The file "RCTAppDependencyProvider.h" couldn't be opened because there is no such file

原因React Native codegen 没有自动运行,需要手动触发。

前置依赖

pnpm add -D @react-native-community/cli

修复:在构建前手动运行 codegen

npx react-native codegen --platform ios --outputPath ios

问题 6Xcode 16 不兼容 Expo SDK 55已确认

现象unknown attribute 'MainActor' 等 Swift 编译错误

原因Expo SDK 55 的 expo-modules-core 使用了 Swift 6 特性,需要 Xcode 26 的 Swift 编译器。Xcode 16 只有 Swift 5.x无法编译。

结论:必须使用 Xcode 26不能降级到 Xcode 16。配合问题 3 的 fmt patch 解决 C++ 兼容性。


构建完整流程(已验证通过)

# 1. 安装依赖
pnpm install

# 2. Patch expo-brownfield mkdir每次 pnpm install 后需重做)
# 文件node_modules/.pnpm/expo-brownfield@.../plugin/build/ios/utils/filesystem.js
# 修改recursive = false → recursive = true

# 3. Prebuild
rm -rf ios
npx expo prebuild --platform ios
# prebuild 内部的 pod install 会因 ffi 失败,忽略

# 4. Pod installarm64 环境)
env /usr/bin/arch -arm64 /bin/bash --login -c 'source ~/.rvm/scripts/rvm && rvm use 2.7.5 && pod install --project-directory=ios'

# 5. Patch fmt consteval每次 pod install 后需重做)
# 文件ios/Pods/fmt/include/fmt/base.h
# 在 __apple_build_version__ < 14000029L 判断后添加 >= 17000000L 的判断

# 6. 运行 codegen
npx react-native codegen --platform ios --outputPath ios

# 7. 构建真机 + 模拟器(使用 DEVELOPER_DIR 指定 Xcode 26无需 sudo 切换)
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

# 真机
xcodebuild -workspace ios/duooomiblesdk.xcworkspace -scheme DuooomiBleSDK \
  -derivedDataPath ios/build -sdk iphoneos -arch arm64 \
  -configuration Release CODE_SIGNING_ALLOWED=NO

# 模拟器
xcodebuild -workspace ios/duooomiblesdk.xcworkspace -scheme DuooomiBleSDK \
  -derivedDataPath ios/build -sdk iphonesimulator -arch arm64 -arch x86_64 \
  -configuration Release CODE_SIGNING_ALLOWED=NO

# 8. 合并为 XCFramework
xcodebuild -create-xcframework \
  -framework ios/build/Build/Products/Release-iphoneos/DuooomiBleSDK.framework \
  -framework ios/build/Build/Products/Release-iphonesimulator/DuooomiBleSDK.framework \
  -output artifacts/DuooomiBleSDK.xcframework

# 9. 产物(约 75MB
# artifacts/DuooomiBleSDK.xcframework (约 75MB)
#   ├── ios-arm64/                        ← 真机
#   ├── ios-arm64_x86_64-simulator/       ← 模拟器
#   └── Info.plist

问题 7运行时 hermesvm.framework 缺失(已解决)

现象App 启动 crashdyld: Library not loaded: @rpath/hermesvm.framework/hermesvm

原因DuooomiBleSDK.framework 动态链接 hermesvm.frameworkHermes JS 引擎),但构建 XCFramework 时只输出了 SDK 本身,没有包含 Hermes。

修复:将 hermesvm.xcframework 也复制到产物目录,宿主 App 需要同时嵌入两个 framework

# 复制 hermesvm 到 artifacts
cp -R ios/Pods/hermes-engine/destroot/Library/Frameworks/universal/hermesvm.xcframework artifacts/

# 宿主 App 的 project.yml 中添加:
dependencies:
  - framework: path/to/DuooomiBleSDK.xcframework
    embed: true
  - framework: path/to/hermesvm.xcframework
    embed: true

CLAUDE.md 与实际代码的偏差

CLAUDE.md 中描述的 API 设计意图与 BleSDK.ts 实际实现存在以下差异,后续需要统一:

状态 key 不一致

CLAUDE.md 设计为单个 deviceState 对象,但实际实现使用多个独立 key

  • btState — 连接状态
  • connectedDevice — 已连接设备
  • deviceInfo — 设备详情
  • version — 固件版本
  • isActivated — 是否激活
  • transferProgress — 传输进度
  • error — 错误信息
  • discoveredDevices — 发现的设备列表

Action 名称不一致

CLAUDE.md 描述 实际代码
init 无此 actionSDK 在 RN mount 时自动初始化
syncFile transferFile(参数为 { fileUri, commandType }
connect 内自动 bind bind 是独立 action
connect 内自动 getInfo getDeviceInfo / getVersion 是独立 action

集成注意事项

  1. 必须显式调用 ReactNativeHostManager.shared.initialize()ExpoBrownfieldAppDelegate 不会自动调用
  2. 必须加载 ReactNativeView(即使隐藏),否则 JS 运行时不启动sendMessage 无人接收
  3. BrownfieldState.subscribe 返回的 AnyCancellable 必须持有引用,否则订阅立即失效
  4. subscribe 回调在 RN 桥接线程,更新 UI 需手动 DispatchQueue.main.async