# iOS 原生接入 RTC iOS 原生 SDK 使用设备的音视频采集与渲染。宿主 SwiftUI/UIKit 页面决定布局和交互;SDK 提供入会、媒体、会议状态与回放资源。先在 iPhone/iPad 上完成只看入会,再分别开启摄像头和麦克风。 ```mermaid flowchart LR A["页面强持有 SDK 与 delegate"] --> B["入会并等待 didJoin"] B --> C["绑定每一路远端轨道"] C --> D["前后台核对媒体状态"] D --> E["leave 并释放视图"] ``` ## 导入同批 SDK 使用同批 `AKStreamRtcSDK` Swift Package,或同时嵌入配套 AKStreamRtcSDK/WebRTC XCFramework 与资源。最低 iOS 15。App 的 Info.plist 应提供真实相机和麦克风用途说明;跨应用屏幕共享另需 ReplayKit Broadcast Extension、App Groups 与对应签名。测试 CA 只用于隔离环境,正式 App 必须让系统验证生产证书链与实际地址。 源码接入时,`AKStreamRtcSDK/Package.swift` 通过相对路径引用相邻的 `WebRTCSDK`。把两个目录一起放进工程,再在 Xcode 中选择 `AKStreamRtcSDK` 产品;只复制其中一个 Package.swift 会丢失 WebRTC 依赖。二进制接入则检查两个 XCFramework 是否都已嵌入,CPU 架构与真机/模拟器目标一致。摄像头和麦克风用途说明使用 `NSCameraUsageDescription`、`NSMicrophoneUsageDescription`,文案应说明业务实际用途。 在 `@MainActor` 页面里创建并**强持有**客户端,同时强持有 delegate: ```swift let client = AkNativeRtcClient(localRenderer: localRenderer, delegate: delegate) client.setInitialMediaEnabled(microphone: false, camera: false) client.joinWithAccessTicket(baseURL: serverURL, roomID: roomID, accessTicket: accessTicket, passcode: passcode) ``` `localRenderer` 是页面创建的 `RTCVideoRenderer`,`delegate` 实现 `AkNativeRtcClientDelegate`。请求入会后等待 `didJoin` 或 `didFail`;远端轨道由 `didReceiveRemoteVideo` 交给对应视图,移除时只释放那一路。页面不能因为看到了系统绿色摄像头指示就认定麦克风已成功送包。 | 代理回调 | 页面处理 | |---|---| | `didJoin`、`didFail` | 完成或结束入会等待,不从同步方法返回值推断入会成功 | | `didReceiveRemoteVideo`、`didRemoveRemoteVideo` | 依 `publicationID` 建立和移除一张画面;同一成员摄像头与共享不能混用 | | `didChangeLocalMedia`、`didChangeMediaPermission` | 显示本机真实输入与主持限制,解除限制不自动开麦 | | `didChangeContinuousRecording` | 显示当前录制状态;`null` 表示没有活动任务 | | `didFailHTTP` | 保留 HTTP 状态区分票据失效与权限不足 | ## 权限、录制和退出 根据 `didChangeLocalMedia`、`didChangeMediaPermission` 和错误回调更新按钮。关闭摄像头不应连带关闭麦克风;App 从后台恢复后还要核对实际媒体状态。iOS 的音频路由由 SDK 协调,不要为每路视频单独启动冲突的 AVAudioSession。 匹配目标版本 的持续录制可通过 `try await client.getContinuousRecording()` 查询;主持人使用 `startContinuousRecording()`、`stopContinuousRecording(recordingId:)`。`didChangeContinuousRecording` 提供状态通知。宿主自己渲染“录制中”和回放入口,SDK 不负责页面样式。1.0.0.157 的旧安装包不包含这些完整档案能力。全部 Swift 函数、回调和 ReplayKit 特殊情况见[iOS 函数参考](ios-api.md)。 请求成功仅说明服务端接受控制,状态可能先是 `Starting`,停录可能先是 `Stopping`。页面要继续使用回调或查询读取最终状态;主持移交后旧主持再调用应收到权限拒绝。会后查询档案须用业务后端新签的档案票据,不要使用入会票据或缓存的 RTC Token。 离会时调用 `client.leave()` 并按 SDK 生命周期关闭;不要只让页面消失。App 签名、开发者信任和测试证书问题与会议媒体问题分开排查。验收步骤见[端侧验收清单](acceptance.md)。 如果手机显示“证书无效”,核对实际连接地址是否在证书 SAN 中、证书链与手机时间是否有效,再检查 App 的信任设置;安装测试 CA 不等于应用已经信任它。若本机预览正常而服务器没有 iPhone 麦克风流,检查音频采集与发送包计数、系统音频路由和另一台设备的接收结果,不能只凭系统绿色相机灯判断有声音。 | 现象 | 先排哪一层 | 怎样证实已经修复 | |---|---|---| | App 提示开发者不受信任 | 描述文件有效期、设备信任、重新签名 | 真机能从桌面启动同一包名的最新版 | | 入会一直重连 | 局域网地址、HTTPS、WebSocket、票据 | `didJoin` 到达,服务器记录该设备会话 | | 本地画面有、别人看不到 | 摄像头发送统计、WHIP/ICE | 第二台终端持续解码新帧 | | 系统显示相机在用但别人听不到 | 麦克风授权、音频路由、发送包 | 另一端收到音频包并听到真实声音 | | 共享按钮不可用 | ReplayKit 扩展与 App Groups 签名 | 系统广播选择器能找到扩展并产生共享发布 |