在 iOS 中使用 ActivityKit 实现锁屏计时器的暂停功能并添加按钮,可以通过以下步骤实现:
1. 定义 Activity 属性 #
在 ActivityAttributes
中添加 isPaused
状态:
struct TimerAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
var endTime: Date
var isPaused: Bool // 暂停状态
}
// 其他固定属性(如计时器总时长)
}
2. 创建处理暂停的 AppIntent #
实现一个自定义的 AppIntent
来响应按钮操作:
struct PauseTimerIntent: AppIntent {
static var title: LocalizedStringResource = "Pause Timer"
@Parameter(title: "ActivityID")
var activityID: String
init() {}
init(activityID: String) {
self.activityID = activityID
}
func perform() async throws -> some IntentResult {
// 通过 activityID 找到对应的 Activity
guard let activity = Activity<TimerAttributes>.activities.first(where: { $0.id == activityID }) else {
return .result()
}
// 获取当前状态
var state = activity.contentState
state.isPaused.toggle() // 切换暂停状态
// 更新 Activity 内容
await activity.update(using: state)
return .result()
}
}
3. 在 Widget 视图中添加按钮 #
在 SwiftUI Widget 视图中,根据状态显示不同按钮:
struct TimerActivityWidget: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: TimerAttributes.self) { context in
VStack {
Text("剩余时间: \(context.state.endTime, style: .timer)")
Button(intent: PauseTimerIntent(activityID: context.activity.id)) {
if context.state.isPaused {
Text("继续")
} else {
Text("暂停")
}
}
}
.activityBackgroundTint(.clear)
}
}
}
4. 启动实时活动时初始化状态 #
开始计时器时,设置初始暂停状态为 false
:
let attributes = TimerAttributes()
let initialState = TimerAttributes.ContentState(endTime: endTime, isPaused: false)
do {
let activity = try Activity.request(attributes: attributes, content: .init(state: initialState, staleDate: nil))
} catch {
print("Error starting activity: \(error)")
}
5. 处理计时器逻辑 #
在应用内部管理计时器,并根据 isPaused
调整剩余时间:
// 监听 Activity 状态变化
Task {
for await activity in Activity<TimerAttributes>.activityUpdates {
if activity.contentState.isPaused {
// 暂停逻辑:记录当前剩余时间
} else {
// 恢复逻辑:基于剩余时间重新计算 endTime
}
}
}
6. 注意事项 #
- iOS 版本要求:此方案需要 iOS 17+,因
AppIntent
和交互式按钮仅在 iOS 17 引入。 - 后台限制:应用被终止后,需通过推送或后台任务恢复计时器状态。
- Activity 生命周期:单个 Activity 最多可持续 8 小时,超时需手动刷新。
通过上述步骤,即可在锁屏实时活动中添加一个可交互的暂停按钮,并通过 AppIntent
动态更新计时器状态。