init:多米蓝牙 sdk

This commit is contained in:
km2023
2026-04-08 15:36:13 +08:00
parent 9e27189799
commit 90dcd9605c
48 changed files with 7557 additions and 9143 deletions

193
BUILD_ISSUES.md Normal file
View File

@@ -0,0 +1,193 @@
# 构建问题记录
## 问题 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-brownfield``plugin/build/ios/utils/filesystem.js`,将 `mkdir``recursive` 参数默认值改为 `true`
```js
// 修改前
const mkdir = (path, recursive = false) => {
// 修改后
const mkdir = (path, recursive = true) => {
```
**注意**:这是 node_modules 内的 patch`pnpm 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 原生架构运行:
```bash
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_consteval`fmt 11.0.2 据此启用 `consteval` 关键字,但编译器实现存在 bug 导致编译失败。
**修复**patch `ios/Pods/fmt/include/fmt/base.h`,在 consteval 检测逻辑中禁用 Apple Clang 17+
```c
// 在 __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 没有自动运行,需要手动触发。
**前置依赖**
```bash
pnpm add -D @react-native-community/cli
```
**修复**:在构建前手动运行 codegen
```bash
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++ 兼容性。
---
## 构建完整流程(已验证通过)
```bash
# 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 启动 crash`dyld: Library not loaded: @rpath/hermesvm.framework/hermesvm`
**原因**`DuooomiBleSDK.framework` 动态链接 `hermesvm.framework`Hermes JS 引擎),但构建 XCFramework 时只输出了 SDK 本身,没有包含 Hermes。
**修复**:将 `hermesvm.xcframework` 也复制到产物目录,宿主 App 需要同时嵌入两个 framework
```bash
# 复制 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`