跳到正文
Embedded SDK

iOS SDK

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

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

iKho S1 录音卡

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

环境要求

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

安装

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

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.m4aAAC 封装,画质与体积均衡,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_HANDSHAKEWi-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-FiwifiTransferReady()Wi-Fi 快传通道就绪,可发起同步
错误didEncounterError(_:)其他 SDK 层错误

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

下一步