# iOS SDK

> 在你的 iOS 应用里集成 iKho Embedded SDK:扫描并绑定 S1 录音卡、读取设备状态、把录音通过 BLE 或 Wi-Fi 同步到手机。

开发者平台处于内测阶段,接口契约以联调时提供的正式文档为准。账号由对接工程师开通,详见联系我们。

  
  

iKho Embedded SDK 让你的 iOS 应用把 S1 录音卡当作一等公民的采集设备:一次配置用户令牌,即可扫描、绑定、读取设备状态,并把设备上的录音同步到手机。SDK 采用代理(delegate)驱动,设备生命周期与同步进度都通过回调返回。

## 环境要求

  | 项目 | 要求 

  | iOS 部署目标 | iOS 15.0 及以上(以正式发布说明为准) 
| Xcode | 15 及以上 
| Swift | 5.9 及以上 
| 测试设备 | 需真机 iPhone。SDK 以 arm64 真机框架分发,模拟器不支持设备联调 
| 硬件 | 一张 iKho S1 录音卡(硬件规格以量产规格为准) 

## 安装

SDK 以私有 Swift Package / CocoaPods 分发,包名为 IKhoEmbedded。依赖地址与私有源随开通邮件发放,请勿硬编码到公共仓库。

  Swift Package ManagerCocoaPods
  

  

  swift
    
  

  
```
class="tk-cmt">// Package.swift —— 依赖地址随开通邮件发放
dependencies: [
    .package(url: class="tk-str">"https:class="tk-cmt">//<你的内测 Git 地址>/ikho-embedded-ios.git", from: class="tk-str">"0.9.0"),
],
targets: [
    .target(
        name: class="tk-str">"YourApp",
        dependencies: [
            .product(name: class="tk-str">"IKhoEmbedded", package: class="tk-str">"ikho-embedded-ios"),
        ]
    ),
]
```

  bash
    
  

  
```
# Podfile —— 私有源地址随开通邮件发放
source 'https://<你的内测 Podspec 源>'
source 'https://cdn.cocoapods.org/'

target 'YourApp' do
  use_frameworks!
  pod 'IKhoEmbedded', '~> 0.9.0'
end

# 安装依赖
# pod install
```

## 初始化

在应用启动时用用户令牌配置一次 SDK。用户令牌由你的后端调用认证 API为每个终端用户签发,密钥仅保存在后端,切勿随包下发。

  AppDelegate.swift
    
  

  
```
import IKhoEmbedded

class="tk-cmt">// 应用启动时调用一次(如 AppDelegate / App.init)
IKhoEmbedded.configure(userToken: class="tk-str">"USER_ACCESS_TOKEN")
```

  
    userToken
    String
    
    必填
    
  

  为当前终端用户签发的访问令牌(JWT),用于设备鉴权与文件同步。设备握手令牌由 SDK 从令牌中自动解析。

  

  
    region
    IKhoRegion
    
    
    默认 .chinaMainland
  

  目标区域。当前仅 .chinaMainland(中国大陆)内测可用,海外区域规划中。所有设备与文件请求均走境内节点,不出境。

  

### 刷新用户令牌

用户令牌过期或重新登录后,更新令牌即可,无需重新配置 SDK。

  swift
    
  

  
```
IKhoEmbedded.setUserToken(class="tk-str">"NEW_USER_ACCESS_TOKEN")
```

## 权限声明

SDK 通过蓝牙与 S1 通信,并在应用内提供录制与试听,需在 Info.plist 声明以下条目,否则系统会拒绝相关能力。

  Info.plist
    
  

  
```
<key>NSBluetoothAlwaysUsageDescription</key>
<string>用于连接 iKho 录音卡并同步设备上的录音</string>

<key>NSMicrophoneUsageDescription</key>
<string>用于在应用内录制与试听音频</string>

<!-- 后台保持蓝牙连接,支持后台同步 -->
<key>UIBackgroundModes</key>
<array>
  <string>bluetooth-central</string>
</array>
```

Wi-Fi 快传另需在应用能力中开启 Hotspot Configuration entitlement,见下方「Wi-Fi 快传」。

## 扫描与绑定设备

设置代理后开始扫描,扫描结果通过 deviceScanResult 回调返回;选中目标设备调用 bind(device:) 完成加密绑定。

  
    1

    设置代理并开始扫描
把实现了 IKhoDeviceDelegate 的对象设为代理,调用 scanDevices()。

  

  
    2

    在扫描回调中选中设备
在 deviceScanResult(_:) 中按序列号或用户选择挑出目标设备,并 stopScan()。

  

  
    3

    完成加密绑定
调用 bind(device:),绑定结果通过 deviceBindChanged(_:) 返回。

  

  swift
    
  

  
```
import IKhoEmbedded

final class DeviceCoordinator: IKhoDeviceDelegate {
    private var lastSerial: String?

    func start() {
        IKhoDeviceManager.shared.delegate = self
        IKhoDeviceManager.shared.scanDevices()
    }

    class="tk-cmt">// 扫描到设备时回调(可能多次触发)
    func deviceScanResult(_ devices: [IKhoDevice]) {
        guard let target = devices.first(where: { $0.serialNumber == lastSerial })
                ?? devices.first else { return }
        IKhoDeviceManager.shared.stopScan()
        IKhoDeviceManager.shared.bind(device: target)
    }

    class="tk-cmt">// 绑定结果
    func deviceBindChanged(_ result: IKhoBindResult) {
        if result.bound { print(class="tk-str">"已绑定 \(result.serialNumber)") }
    }
}
```

一台 S1 同一时间只能绑定一个应用(用于文件加密与安全隔离)。绑定与应用安装绑定,用户卸载你的应用前请先解绑,否则设备无法再绑定到其他应用。

## 设备状态与电量

握手完成后,设备总体状态(电量、充电、剩余存储)通过 deviceStateChanged(_:) 回调返回;电量或充电变化会额外触发 deviceBatteryChanged。也可主动调用 refreshDeviceState() 拉取一次。

  swift
    
  

  
```
func deviceStateChanged(_ state: IKhoDeviceState) {
    print(class="tk-str">"电量 \(state.batteryLevel)% · 充电中 \(state.isCharging)")
    print(class="tk-str">"剩余存储 \(state.freeStorage) / \(state.totalStorage) 字节")
}

class="tk-cmt">// 主动刷新一次设备状态
IKhoDeviceManager.shared.refreshDeviceState()
```

## 录音列表与同步

调用 fetchRecordings() 读取设备上的录音清单(默认走 BLE 通道),结果通过 recordingListUpdated(_:) 返回。选中某条录音调用 exportAudio 同步到手机,进度与结果通过代理回调。

  swift
    
  

  
```
class="tk-cmt">// 读取设备上的录音列表(默认 BLE 通道)
IKhoDeviceManager.shared.fetchRecordings()

func recordingListUpdated(_ recordings: [IKhoRecording]) {
    for r in recordings {
        print(class="tk-str">"\(r.id) · \(r.durationSeconds)s · \(r.sizeBytes) bytes")
    }
}

class="tk-cmt">// 把某条录音同步到手机
IKhoDeviceManager.shared.exportAudio(recordingId: recording.id, format: .m4a)

func exportProgress(recordingId: String, progress: Int) { /* 0–100 */ }
func exportCompleted(recordingId: String, outputPath: String) { /* 文件已就绪 */ }
func exportFailed(recordingId: String, error: IKhoError) { /* 处理错误 */ }
```

大文件同步建议:显示进度并预告耗时;开启后台/断点续传,避免退到后台中断;大批量或大文件优先用 Wi-Fi 快传。

## Wi-Fi 快传

BLE 之外,S1 支持 Wi-Fi 快传通道,吞吐显著高于 BLE,适合批量或大文件同步。开启后,后续 exportAudio 会在通道就绪后自动优先走 Wi-Fi。

  swift
    
  

  
```
class="tk-cmt">// 开启 Wi-Fi 快传(设备会开启热点,SDK 自动接入)
IKhoDeviceManager.shared.setWiFiTransfer(enabled: true)

class="tk-cmt">// 通道就绪后再发起同步
func wifiTransferReady() {
    IKhoDeviceManager.shared.exportAudio(recordingId: recording.id, format: .m4a)
}
```

Wi-Fi 快传注意点:

- 需在应用能力中开启 Hotspot Configuration entitlement。
- 快传期间手机会临时接入 S1 的热点,过程中普通网络可能短暂中断。
- 握手或传输失败会自动回退到 BLE 同步。

## 导出音频

exportAudio 支持指定导出格式;多条录音可用 exportAudioBatch 批量导出,进度按条汇总。

  swift
    
  

  
```
class="tk-cmt">// 单条导出,指定格式(mp3 / m4a / wav)
IKhoDeviceManager.shared.exportAudio(recordingId: id, format: .mp3)

class="tk-cmt">// 批量导出多条录音
IKhoDeviceManager.shared.exportAudioBatch(recordingIds: selectedIds, format: .wav)

func exportBatchProgress(completed: Int, total: Int) {
    print(class="tk-str">"已完成 \(completed) / \(total)")
}
```

  | 格式 | 取值 | 适用 

  | MP3 | .mp3 | 通用、体积小,便于回放与上传转写 
| M4A | .m4a | AAC 封装,画质与体积均衡,iOS 原生友好 
| WAV | .wav | 无损,用于二次处理或高精度转写 

## 解绑设备

用户切换应用或卸载前,调用 unbind(clear:) 解除绑定并清除本地绑定态。

  swift
    
  

  
```
class="tk-cmt">// 解绑当前设备并清除本地绑定态
IKhoDeviceManager.shared.unbind(clear: true)
```

  
    clear
    Bool
    
    必填
    
  

  设为 true 时清除全部本地连接与缓存的绑定信息。

  

## 错误码

SDK 层错误通过 didEncounterError(_:) 或各操作的失败回调返回,IKhoError 携带以下错误码。

  | 错误码 | 含义 | 建议处理 

  | IKHO_ERR_UNAUTHORIZED | 用户令牌无效或已过期 | 重新签发用户令牌后调用 setUserToken 
| IKHO_ERR_BLE_UNAVAILABLE | 蓝牙未开启或未授权 | 引导用户在系统设置开启蓝牙并授予权限 
| IKHO_ERR_DEVICE_NOT_FOUND | 扫描超时未发现设备 | 确认设备已开机且在近场,重试扫描 
| IKHO_ERR_BIND_OCCUPIED | 设备已被其他应用绑定 | 提示用户在原应用先解绑,再重试绑定 
| IKHO_ERR_CONNECTION_LOST | 与设备的连接中断 | 靠近设备后自动重连,或手动重新扫描 
| IKHO_ERR_TRANSFER_FAILED | 音频同步过程中断 | 支持断点续传,重新发起同步 
| IKHO_ERR_STORAGE_FULL | 手机本地存储空间不足 | 清理空间后重试导出 
| IKHO_ERR_WIFI_HANDSHAKE | Wi-Fi 快传握手失败 | 回退到 BLE 同步或稍后重试 

## 代理回调一览

所有设备事件通过 IKhoDeviceDelegate 返回。其中 deviceStateChanged 为唯一必须实现的回调,其余可按需实现。

  | 分组 | 回调 | 说明 

  | 连接 | deviceScanResult(_:) | 扫描结果更新 
| 连接 | deviceConnectionChanged(_:) | 连接状态变化(已连接 / 断开) 
| 连接 | deviceBindChanged(_:) | 绑定状态变化 
| 状态 | deviceStateChanged(_:) | 必须实现。握手完成后返回设备总体状态(电量 / 充电 / 存储) 
| 状态 | deviceBatteryChanged(level:isCharging:) | 电量或充电状态变化 
| 录音 | recordingStarted(_:) | 设备开始录音 
| 录音 | recordingStopped(_:) | 设备停止录音 
| 录音 | recordingListUpdated(_:) | fetchRecordings() 结果返回 
| 同步 | exportProgress(recordingId:progress:) | 单条同步进度,0–100 
| 同步 | exportCompleted(recordingId:outputPath:) | 单条同步完成,文件写入 outputPath 
| 同步 | exportFailed(recordingId:error:) | 单条同步失败 
| 同步 | exportBatchProgress(completed:total:) | 批量同步进度 
| Wi-Fi | wifiTransferReady() | Wi-Fi 快传通道就绪,可发起同步 
| 错误 | didEncounterError(_:) | 其他 SDK 层错误 

回调默认在 SDK 内部队列触发,更新 UI 或已发布状态前请切回主线程。

## 下一步

    
    
      Starter App 指南

      用官方 iOS 起步应用几分钟跑通绑定、同步与转写。

      打开指南 

    

    
    
      React Native 接入

      已有 RN 应用?通过桥模块复用同一套设备能力。

      查看 RN 桥
