Skip to the content.

PTools 5.36.1 P2 现代系统扩展指南

这些能力都是可选模块,Core 默认不携带。所有示例面向 iOS 17+ / Swift 6+;涉及 AppIntent、 Widget 或 Live Activity 时,宿主还必须配置对应的 Extension Target 和 entitlements。

安装

SwiftPM 选择:

PToolsConfiguration
PToolsFeedback
PToolsAudio
PToolsAppIntents
PToolsWidgetCore
PToolsActivities

CocoaPods:

pod 'PooTools/Configuration'
pod 'PooTools/Feedback'
pod 'PooTools/Audio'
# Extension Target 中按需单独添加:
pod 'PooTools/AppIntents'
pod 'PooTools/WidgetCore'
pod 'PooTools/Activities'

Configuration / Feature Flags

let checkoutEnabled = PTConfigKey(name: "checkout.enabled", defaultValue: false)
let store = PTConfigurationStore(
    context: .init(environment: .staging, appVersion: "5.36.1"),
    defaults: [checkoutEnabled.name: try JSONEncoder().encode(false)]
)

try await store.setLocalOverride(true, for: checkoutEnabled)
let snapshot = try await store.refresh()
let enabled = try snapshot.value(for: checkoutEnabled)

来源优先级为 defaults → bundle → environment → local override → remote → debug override。 Remote 只实现 PTConfigurationProvider;不要把 token、密码或个人隐私放入配置源。Debug override 仅在 Debug 编译中可见。

Feedback / Haptics

PTHapticEngine.shared.installAsDefault()
PTFeedbackCenter.shared.emit(.selectionChanged)
PTFeedbackCenter.shared.emit(.success)

自定义 CoreHaptics 模式通过 PTHapticPattern,硬件不支持时会安全跳过;业务层使用语义事件, 不要在每个按钮里重复创建 generator。policy = .disabled 可用于无障碍或测试环境。

Audio

let audio = PTAudioSessionCoordinator.shared
try await audio.configure(.init(category: .playAndRecord, mode: "default"))
try await audio.activate()
let recorder = PTAudioRecorder()
guard await PTAudioPermission.requestMicrophoneAccess() else { return }
try await recorder.record(to: outputURL)

录音前必须显式请求麦克风权限;PTAudioPlayer 只负责本地简单播放,流媒体继续使用 AVPlayer 或业务媒体模块。events() 提供中断、路由变化和 media services reset 快照,waveform() 返回 无 UI 依赖的有界采样值。

App Intents / Router

let descriptor = PTAppIntentRouteDescriptor(
    route: PTRoute(id: "orders"),
    mode: .routeToApp
)
try await PTAppIntentRouteBridge.shared.execute(descriptor)

AppIntent 的静态声明仍由 Apple AppIntent / AppShortcutsProvider 管理;PTools 只将安全的 PTRouteRequest 交给宿主适配器。无 UI 的动作使用 .headless,需要唤起 App 的动作使用 .routeToApp。危险支付、删除等动作不要默认暴露给 Siri。

WidgetCore

let store = try PTWidgetSharedStore(appGroupIdentifier: "group.example.app")
try await store.write(PTWidgetSnapshot(value: payload), for: widgetKey)
PTWidgetReloadCoordinator.shared.requestReload(kind: "OrderWidget")
let request = try PTWidgetDeepLink(url: widgetURL).route()

App Group 必须由宿主显式传入并配置 entitlement;PTools 不猜 identifier。WidgetCore 不提供 SwiftUI View,TimelineProvider 和 Widget UI 保留在宿主 Widget Extension。

Activities

宿主定义自己的 ActivityAttributes 和 UI,PTools 只负责生命周期:

let coordinator = PTActivityCoordinator<OrderAttributes>()
let id = try await coordinator.start(attributes: attributes, state: initialState,
                                     staleDate: Date(timeIntervalSinceNow: 900),
                                     relevanceScore: 0.5)
for await token in coordinator.pushTokens() {
    await uploadPushToken(token, for: id)
}

更新支持 deduplicated/throttled policy,结束支持 immediate/afterStaleDate。Push Server、 锁屏/Dynamic Island 业务 UI、敏感信息脱敏由宿主负责。若需要后台刷新,宿主可实现 PTActivityBackgroundAdapter,将 staleDate 转发给已有的 BackgroundTasks 或通知调度器; PTools 不会在 Activities 内部创建循环依赖。generation 可用于丢弃旧请求的异步回写。

示例与验证

最小示例片段位于 Example/P0/README.md、 Example/P1/README.md、Example/P2/README.md 和 Example/Extensions。脚本 Scripts/CI/check_p2_modern_modules.sh 检查产品、subspec、并发边界和 extension-safe 规则; 完整 UIKit 验证使用 Xcode Simulator,而不是 macOS swift build 代替。