为支撑 H5 的 prepareaudio / mediaTypeAudio 录音上传 + 远端语音播放
(docs/H5-Native-Contract.md §3.1 [4][5] + §3.2 [9])接入 AMR-NB
编解码能力。AMR-NB 是跨端(iOS / Android / 旧版本客户端)契约硬约束,
不可换 AAC / Opus。
## 接入路径
直接 vendor daoqi msext 现成的 fat .a(已上线多年),不打 xcframework /
不重编源码:
- Vendor/OpenCoreAMR/v0.1.x/libopencore-amrnb.a:daoqi 同款 5-slice fat
库(含 2026-06-20 lipo -segalign 8 修过的对齐版本)
- Vendor/OpenCoreAMR/v0.1.x/{interf_dec,interf_enc}.h:amrnb 公开头
- Vendor/OpenCoreAMR/README.md:来源、版本、修复历史、为何不打 xcframework
- ylgamehall/Source/Audio/AMRFileCodec/{amrFileCodec.h,amrFileCodec.mm}:
daoqi 同款 wrapper(文件级 WAV↔AMR 处理)
- ylgamehall/Source/Audio/AMRCodec.swift:Swift 薄 wrapper(wavToAmr /
amrToWav 两个纯函数 + AMRCodec.Error)
理由见 Vendor/OpenCoreAMR/README.md「为何不打 xcframework / 不重编源码」
一节,本质是 opencore-amr 整个 iOS 生态没有"现代主流"分发形态,社区无
官方 SPM / xcframework 维护,强行打反而引入新风险。
## 关键技术点:extern "C" 修复 ObjC++ name mangling
amrFileCodec.h 在原项目里没有 extern "C" 包裹函数声明,daoqi 能跑是
因为调用方 VoiceConverter.mm 也是 ObjC++,双方按相同 C++ name mangling
链接能对上。
新外壳从 Swift 通过 bridging-header 调用,Swift 按 C 函数解析,期望符号
_EncodeWAVEFileToAMRFile / _DecodeWAVEFileToWAVEFile(C 链接);但
.mm 编译时默认 C++ name mangling,符号变成 __Z25Encode...,导致链接器
报 Undefined symbol。
修复:在 amrFileCodec.h 的函数声明外加 #ifdef __cplusplus / extern "C"
包裹。这是标准 C/C++ 头文件兼容写法,对 daoqi 老路径无影响(ObjC++
调用方仍能链接 C-linkage 函数)。
## .gitignore:白名单 Vendor 下的 .a
发现历史遗留问题:原 .gitignore *.a 通配规则把 libWeChatSDK.a 也排除
了,意味着别人 clone 此仓库后链接失败。本次顺带修复:
!Vendor/**/*.a
让 Vendor 下的 .a 显式纳入跟踪。本提交同时把 libWeChatSDK.a(历史
缺失)+ libopencore-amrnb.a(本次新增)一并加入 git 跟踪。
## 工程改动
pbxproj 改动由用户在 Xcode UI 完成(4 项 Build Settings:Add .a 到
Frameworks group / Header Search Paths +2 / Library Search Paths +1;
EXCLUDED_ARCHS arm64-simulator 因真机调试场景暂未配,需要时再加)。
## 验证
BuildProject 通过,0 错误,符号链接正确。XcodeRefreshCodeIssuesInFile
对 AMRCodec.swift 0 诊断。
103 lines
1.9 KiB
Plaintext
103 lines
1.9 KiB
Plaintext
# ===== macOS =====
|
|
.DS_Store
|
|
._*
|
|
.Spotlight-V100
|
|
.Trashes
|
|
|
|
# ===== Xcode =====
|
|
# 构建产物
|
|
build/
|
|
DerivedData/
|
|
*.o
|
|
*.lo
|
|
*.la
|
|
*.al
|
|
.libs
|
|
*.so
|
|
*.so.[0-9]*
|
|
*.la
|
|
*.a
|
|
# Vendor 下的 .a 是项目依赖(如 libWeChatSDK.a / libopencore-amrnb.a),必须跟踪
|
|
# —— 否则其他人 clone 后链接失败。覆盖上面 *.a 的通配规则。
|
|
!Vendor/**/*.a
|
|
*.pyc
|
|
*.swp
|
|
*~.nib
|
|
|
|
# 用户级数据(每个开发者本地不同,不能共享)
|
|
xcuserdata/
|
|
*.xcuserstate
|
|
*.xcuserdatad
|
|
*.xcscmblueprint
|
|
*.xccheckout
|
|
|
|
# 项目文件内的用户专属配置
|
|
*.moved-aside
|
|
*.hmap
|
|
*.ipa
|
|
*.dSYM.zip
|
|
*.dSYM
|
|
|
|
# Playgrounds
|
|
timeline.xctimeline
|
|
playground.xcworkspace
|
|
|
|
# ===== Swift Package Manager =====
|
|
# 本地 SPM 缓存(每台机器各自重建)
|
|
.build/
|
|
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
|
.swiftpm/xcode/xcuserdata/
|
|
.swiftpm/configuration/
|
|
# Package.resolved 需要提交,确保多人 / CI 用同一版本
|
|
# 故意不忽略 Package.resolved
|
|
|
|
# ===== CocoaPods =====
|
|
# Pods/ 不提交(CI / 新人 pod install 重建);Podfile.lock 必须提交
|
|
Pods/
|
|
# 故意不忽略 Podfile.lock
|
|
|
|
# ===== Carthage(如使用)=====
|
|
Carthage/Build/
|
|
Carthage/Checkouts
|
|
|
|
# ===== fastlane =====
|
|
fastlane/report.xml
|
|
fastlane/Preview.html
|
|
fastlane/screenshots/**/*.png
|
|
fastlane/test_output
|
|
|
|
# ===== 代码覆盖率 / Profile =====
|
|
*.gcda
|
|
*.gcno
|
|
*.profraw
|
|
*.profdata
|
|
|
|
# ===== AppCode / JetBrains =====
|
|
.idea/
|
|
|
|
# ===== 签名 / 证书(绝不入库)=====
|
|
*.mobileprovision
|
|
*.provisionprofile
|
|
*.cer
|
|
*.p12
|
|
*.pem
|
|
*.key
|
|
|
|
# ===== 本地敏感配置 =====
|
|
.env
|
|
.env.*
|
|
secrets.xcconfig
|
|
Secrets/
|
|
|
|
# ===== 备份 / 临时 =====
|
|
*.orig
|
|
*.bak
|
|
*.tmp
|
|
*~
|
|
|
|
# ===== docs/res 大型素材 / SDK 下载副本 =====
|
|
# docs/res 是项目维护者的私人素材池(CLAUDE.md 约定),整体 git 跟踪但
|
|
# 排除特别大的 SDK 下载副本(已经走 SPM / Vendor 接入,不需要副本):
|
|
docs/res/AMap_iOS_Loc_ALL/
|
|
docs/res/objc-sdk-8.9.2/
|