ActivityKit — 添加交互式按钮
This article is extracted from the chat log with AI. Please identify it with caution.

在 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 动态更新计时器状态。

本文共 650 字,创建于 May 24, 2025
相关标签: Xcode, SwiftUI, ByAI