Create a great ShazamKit experience
System & Services 进阶 20m

打造出色的 ShazamKit 体验

Create a great ShazamKit experience

2023年6月5日

在 Apple 官方观看视频

一句话判断

SHManagedSession 把音频录制和识别的代码量砍到了几行——如果你之前因为 AVAudioEngine 的复杂性而放弃接入 ShazamKit,现在是重新考虑的时候了。

这场 Session 讲了什么

Session 聚焦 ShazamKit 在 2023 年的三项更新:

1. SHManagedSession(管理式会话): 全新的高级 API,自动处理麦克风权限申请、音频引擎配置、音频缓冲区采集。开发者只需创建 session、调用 result 方法、处理返回结果。相比之前手动配置 AVAudioEngine 的方式,代码量大幅减少。

Managed Session 支持两种使用方式:

  • result() 方法:单次识别,返回 match/noMatch/error 三种结果。
  • results async sequence:持续识别流,适合长时间监听场景。

还提供了 prepare() 方法用于预热——提前分配资源和预录制,让后续的识别请求响应更快。

2. Shazam Library API 重新设计: 对 Shazam 音乐库的访问能力进行了重新定义和增强,具体包括更好的媒体项目管理能力。

3. 最佳实践: Session 提供了完整的示例项目,展示如何从传统 SHSession 迁移到 SHManagedSession

Session 中有个很直观的 Demo:一个”学跳舞”App,用麦克风识别正在播放的歌曲,然后自动匹配对应的舞蹈教学视频。这个场景很好地展示了 ShazamKit 与其他 API(如音乐播放、视频播放)的组合使用。

值得深挖的点

prepare() 的时机选择值得思考。不调用 prepare 时,第一次 result() 请求需要先分配资源、启动录制,然后才能开始识别。调用 prepare 后,资源和录制都提前就绪,result() 能更快返回匹配结果。如果你的 App 有一个”准备识别”的 UI 状态(比如用户进入了识别页面但还没点击按钮),这就是调用 prepare 的最佳时机。

从 SHSession 到 SHManagedSession 的迁移路径设计得很顺畅。Session 展示了具体的迁移步骤:替换实例类型、删除音频引擎配置代码、删除权限请求代码、简化停止逻辑。整个过程不涉及业务逻辑变更,纯粹是基础设施的简化。

Signature 的隐私保护设计值得注意。音频被转换为 Signature 后是不可逆的——无法从 Signature 还原原始录音。这意味着 ShazamKit 在传输和匹配过程中不会泄露用户的音频内容。

代码片段

使用 SHManagedSession 进行单次识别:

import ShazamKit

class Matcher {
    private let managedSession = SHManagedSession()

    func recognize() async {
        do {
            // 单次识别,自动处理麦克风权限和录音
            let result = try await managedSession.result()
            switch result {
            case .match(let match):
                // 获取匹配的媒体信息
                if let item = match.mediaItems.first {
                    print("识别到:\(item.title ?? "未知") - \(item.artist ?? "未知")")
                }
            case .noMatch:
                print("未找到匹配")
            }
        } catch {
            print("识别出错:\(error)")
        }
    }

    func stop() {
        managedSession.cancel()  // 取消当前识别并停止录音
    }
}

使用 async sequence 进行持续识别:

func startContinuousRecognition() async {
    managedSession.prepare()  // 预热,加快首次识别速度

    do {
        for try await result in managedSession.results {
            switch result {
            case .match(let match):
                // 处理每次匹配结果
                handleMatch(match)
            case .noMatch:
                // 继续监听
                break
            }
        }
    } catch {
        // 处理错误或用户主动取消
        print("识别结束:\(error)")
    }
}

从传统代码迁移到 Managed Session 的变化:

// 迁移前:手动配置音频引擎
// let session = SHSession()
// let audioEngine = AVAudioEngine()
// audioEngine.inputNode.installTap(...)  // 配置音频缓冲区
// audioEngine.prepare()
// audioEngine.start()
// ... 大量样板代码

// 迁移后:三行搞定
let managedSession = SHManagedSession()
let result = try await managedSession.result()
// 就这么简单

最佳实践

  • 在用户进入识别界面的时刻调用 prepare(),在点击识别按钮时调用 result(),这样可以最小化识别延迟。
  • Info.plist 中必须添加 NSMicrophoneUsageDescription,Managed Session 会自动使用这个描述来请求权限。
  • 长时间监听场景用 results async sequence 而不是循环调用 result(),前者更高效且能持续返回多个匹配。
  • cancel() 会同时停止录音和取消正在进行的匹配,在页面消失或 App 进入后台时调用。
  • 匹配结果中的 mediaItems 可能包含多个条目(比如同一首歌的不同版本),用 first 不一定总是最佳选择,根据业务需求决定如何展示。
  • ShazamKit 匹配即使在嘈杂环境(如餐厅)中也能工作,但极度嘈杂或音量过低的环境下识别率会下降。

还有什么值得关注

  • 2022 年引入的 Shazam CLI 工具和自定义目录(Custom Catalogs)功能仍然可用,适合需要大规模音频指纹管理的场景。
  • 自定义目录中的 frequency skewing 功能可以帮助区分相似音频片段,对音乐类 App 特别有用。
  • Signature 是不可逆的,这在某些需要留存原始音频的场景中可能是个限制——你需要在本地同时保存原始录音。
  • ShazamKit 的匹配依赖网络连接,离线状态下无法使用。
  • 搭配 MusicKit API,可以在识别歌曲后直接播放完整版或添加到播放列表,构建完整的音乐发现体验。
WWDC 2023