Highlight
WWDC21 第二天集中展示了声音识别、ShazamKit 自定义音频匹配、Screen Time API、StoreKit 2 和 Nearby Interaction 配件支持,开发者可以把系统级识别、限制、购买和空间感知能力接入自己的 App。
核心内容
第二天的 recap 只有一分多钟。它没有展开讲代码,而是把当天的几个技术方向串在一起。
这些方向都来自真实的开发麻烦。
你想识别环境里的声音,以前要自己训练模型、处理音频窗口、判断置信度。Sound Analysis 给了内置分类器,可以直接识别三百多种声音。
你想让手机 App 跟电视上的视频同步,以前要依赖网络、时间码或手动触发。ShazamKit 让 App 听到音频后匹配自定义目录,再根据匹配偏移显示内容。
你想做家长控制,以前拿不到 Screen Time 的系统限制能力。Screen Time API 把限制、授权和设备活动监控拆成三个框架,让 App 在隐私边界内工作。
你想做订阅,以前要处理 SKProductsRequest、交易状态和收据验证。StoreKit 2 把商品、购买、交易和权益变成 Swift 原生 API。
你想让手机和配件互相感知位置,以前 Nearby Interaction 主要用于 Apple 设备之间。iOS 15 开始支持兼容的第三方 UWB 配件。
这场 recap 的价值在于指路。它告诉你第二天哪些 session 值得继续看,以及每个新能力能解决哪类产品问题。
详细内容
用 Sound Analysis 识别环境声音
(00:07)
recap 提到,开发者学习了如何分析和分类声音。对应 session 是 Discover built-in sound classification in SoundAnalysis。
Sound Analysis(声音分析)提供内置声音分类器。它可以从麦克风、音频文件或视频文件中识别离散声音。开发者无需先训练自定义模型。
func getListOfRecognizedSounds() throws -> [String] {
let request = try SNClassifySoundRequest(classifierIdentifier: .version1)
return request.knownClassifications
}
关键点:
getListOfRecognizedSounds()返回内置分类器支持的声音标签。SNClassifySoundRequest是声音分类请求。.version1指定使用系统提供的第一版内置分类器。knownClassifications暴露分类器能识别的标签列表。
拿到标签后,就可以对音频文件做分类。
let request = try SNClassifySoundRequest(classifierIdentifier: .version1)
let analyzer = try SNAudioFileAnalyzer(url: url)
var observer: SNResultsObserving // TODO
try analyzer.add(request, withObserver: observer)
analyzer.analyze()
关键点:
- 第一行创建同一个内置分类请求。
SNAudioFileAnalyzer(url:)读取本地音频文件。SNResultsObserving接收分类结果。analyzer.add把请求和观察者绑定到分析器。analyzer.analyze()开始执行分析。
用 ShazamKit 做自定义音频匹配
(00:17)
recap 提到 ShazamKit 可以识别自定义音频。它给出的场景很具体:电视播放视频,手机上的 companion app 在正确时间显示问题。
对应 session 里,Apple 用一个教育视频做例子。App 先把视频音频生成 reference signature(参考签名),放进自定义目录。运行时,App 从麦克风采集音频流,匹配目录,然后根据 predictedCurrentMatchOffset 找到当前视频位置。
// Matching signatures using SHSession
let session = SHSession()
session.delegate = self
let signatureGenerator = SHSignatureGenerator()
try signatureGenerator.append(buffer, at: nil)
let signature = signatureGenerator.signature()
session.match(signature)
关键点:
SHSession负责执行匹配。session.delegate = self让当前对象接收匹配结果。SHSignatureGenerator把音频 buffer 转成签名。append(buffer, at:)把捕获到的音频写入签名生成器。signature()生成可匹配的音频签名。session.match(signature)用该签名发起匹配。
自定义目录还可以携带元数据。匹配成功后,delegate 返回 SHMatch,App 从 mediaItems 读取标题、老师、集数等信息。
// Receiving matches via the session delegate
extension SongResultViewController: SHSessionDelegate {
public func session(_ session: SHSession, didFind match: SHMatch) {
guard let matchedMediaItem = match.mediaItems.first else {
return
}
DispatchQueue.main.async {
self.songView.titleLabel.text = matchedMediaItem.title
self.songView.artistLabel.text = matchedMediaItem.artist
}
}
}
关键点:
SHSessionDelegate接收 ShazamKit 的匹配回调。session(_:didFind:)在找到匹配时触发。match.mediaItems.first取出第一个匹配的媒体项。matchedMediaItem.title和artist是目录中保存的元数据。DispatchQueue.main.async确保界面更新发生在主线程。
用 Screen Time API 构建家长控制
(00:37)
recap 提到 Nolan 演示了 Screen Time API。demo App 叫 Homework:孩子需要先使用指定学习 App,才能解除某些 App 的限制。
Screen Time API 由三个框架组成。
Managed Settings(托管设置)负责设置限制,比如屏蔽应用、过滤网页、锁定账号设置。Family Controls(家庭控制)负责监护人授权和隐私保护。Device Activity(设备活动)负责按时间窗口和使用阈值触发扩展代码。
import FamilyControls
Task {
do {
try await AuthorizationCenter.shared.requestAuthorization(for: .child)
} catch {
// Handle the error here.
}
}
关键点:
FamilyControls提供 Screen Time API 的授权入口。Task用来调用异步授权方法。AuthorizationCenter.shared是授权中心的共享实例。requestAuthorization(for: .child)请求在儿童设备上使用 Family Controls。- 失败时进入
catch,App 需要处理授权失败。
授权后,App 可以安排设备活动监控。Device Activity 在时间窗口开始、结束或达到阈值时调用扩展。
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(hour: 15, minute: 0),
intervalEnd: DateComponents(hour: 18, minute: 0),
repeats: true
)
let center = DeviceActivityCenter()
try center.startMonitoring(.daily, during: schedule)
关键点:
DeviceActivitySchedule描述一个监控时间窗口。intervalStart是窗口开始时间。intervalEnd是窗口结束时间。repeats: true表示每天重复。DeviceActivityCenter负责启动和停止监控。startMonitoring(_:during:)注册一个命名监控任务。
用 StoreKit 2 简化内购和订阅
(00:46)
recap 提到 StoreKit 2 可以快速实现 in-app subscriptions(App 内订阅)。对应 session 说明,StoreKit 2 提供 Swift 原生 API,用来获取商品、发起购买、处理交易、判断权益和客户状态。
获取商品信息可以直接调用 Product.products(for:)。
let products = try await Product.products(for: ["fuel.small", "car.sports", "nav.pro"])
// 按类型分组
let consumables = products.filter { $0.type == .consumable }
let nonConsumables = products.filter { $0.type == .nonConsumable }
let subscriptions = products.filter { $0.type == .autoRenewable }
关键点:
Product.products(for:)根据产品 ID 拉取商品信息。try await表示这是会抛错的异步调用。products.filter按商品类型分组。.consumable是消耗型商品。.nonConsumable是非消耗型商品。.autoRenewable是自动续期订阅。
购买流程也变成一次异步调用。
let result = try await product.purchase()
switch result {
case .success(let verification):
let transaction = try checkVerified(verification)
await transaction.finish()
case .userCancelled:
break
case .pending:
break
@unknown default:
break
}
关键点:
product.purchase()发起购买。.success返回验证结果。checkVerified用来确认交易已经通过验证。transaction.finish()告诉 StoreKit 交易处理完成。.userCancelled表示用户取消购买。.pending表示交易仍在等待批准或付款。
用 Nearby Interaction 连接第三方 UWB 配件
(00:50)
recap 提到 Nearby Interaction 可以和第三方配件配合使用。对应 session 解释,Nearby Interaction 使用 U1 的 Ultra-Wideband(超宽带)能力,为附近设备提供距离和方向更新。
在两个 iPhone 之间,基本流程是创建 session、设置 delegate、创建配置、运行 session。
let session = NISession()
session.delegate = self
let configuration = NINearbyPeerConfiguration(peerToken: peerDiscoveryToken)
session.run(configuration)
关键点:
NISession是 Nearby Interaction 的核心对象。session.delegate = self接收附近对象更新。NINearbyPeerConfiguration用于两个运行同一 App 的 iPhone。peerDiscoveryToken来自对端设备,需要通过自己的连接通道交换。session.run(configuration)开始空间交互。
运行后,delegate 会收到 NINearbyObject 更新。对象里包含距离,部分场景还包含方向。
func session(_ session: NISession, didUpdate nearbyObjects: [NINearbyObject]) {
guard let nearbyObject = nearbyObjects.first else { return }
let distance = nearbyObject.distance
let direction = nearbyObject.direction
}
关键点:
session(_:didUpdate:)在 Nearby Interaction 有新测量值时触发。nearbyObjects.first取出最近一次更新的对象。distance表示到附近对象的距离。direction表示方向信息,具体可用性取决于设备和场景。
核心启发
1. 做一个环境声音提醒器
- 做什么:识别门铃、狗叫、婴儿哭声,并在 Apple Watch 或 iPhone 上提醒。
- 为什么值得做:Sound Analysis 内置分类器能识别多类离散声音,减少训练模型的成本。
- 怎么开始:先用
SNClassifySoundRequest(classifierIdentifier: .version1)查看支持标签,再接入麦克风音频流,把高置信度结果转成通知。
2. 做一个视频同步答题 App
- 做什么:电视播放课程视频,iPad 自动显示对应题目和答案输入框。
- 为什么值得做:ShazamKit 自定义目录可以把音频位置映射到课程内容,不依赖同一网络或播放器接口。
- 怎么开始:为视频生成 reference signature,保存题目 offset;运行时用
SHSession匹配音频,再用匹配偏移查找当前题目。
3. 做一个家庭作业模式
- 做什么:孩子完成学习 App 的使用时长后,自动解除游戏 App 屏蔽。
- 为什么值得做:Screen Time API 可以在儿童设备上执行限制,并通过 Device Activity 扩展响应使用阈值。
- 怎么开始:先申请 Family Controls capability;用
AuthorizationCenter请求授权;用DeviceActivityCenter建立 schedule;在扩展里用 Managed Settings 更新屏蔽规则。
4. 做一个轻量订阅功能
- 做什么:为内容 App 加一个月度订阅,订阅用户解锁高级栏目。
- 为什么值得做:StoreKit 2 把商品查询、购买和权益判断放进 Swift async/await 流程。
- 怎么开始:在 App Store Connect 配置订阅产品;用
Product.products(for:)拉取商品;调用product.purchase();用当前权益判断是否展示高级内容。
5. 做一个配件寻物体验
- 做什么:让 iPhone 指向一个兼容 UWB 配件,并显示距离变化。
- 为什么值得做:Nearby Interaction 在 iOS 15 支持兼容的第三方硬件,App 可以拿到空间感知更新。
- 怎么开始:阅读 Nearby Interaction 配件规格;在 App 里创建
NISession;与配件交换所需配置数据;根据距离和方向更新界面。
关联 Session
- Discover built-in sound classification in SoundAnalysis — 使用 Sound Analysis 内置分类器识别环境声音、音频文件和视频中的声音。
- Create custom audio experiences with ShazamKit — 构建自定义音频目录,并把音频匹配结果同步到 App 内容。
- Meet the Screen Time API — 介绍 Managed Settings、Family Controls 和 Device Activity 三个框架。
- Meet StoreKit 2 — 用 Swift 原生 API 实现内购、订阅、交易验证和权益判断。
- Explore Nearby Interaction with third-party accessories — 使用 Nearby Interaction 与兼容第三方 UWB 配件进行距离和方向交互。
评论
GitHub Issues · utterances