ActivityKit — 计时器示例
This article is extracted from the chat log with AI. Please identify it with caution.

下面我会帮你从零构建一个完整的 计时器类 Live Activity 示例项目,分为两大部分:

  1. 主 App(启动、更新、结束 Live Activity)

  2. Widget Extension(展示在锁屏 / 动态岛)


✅ 1. 创建项目与结构 #

在 Xcode 中:

  • 创建一个 iOS App

  • 勾选 “Include Widget Extension”

  • 命名主 App 为:TimerLiveActivityApp

  • 命名 Widget Extension 为:TimerLiveActivityExtension


🧱 2. 定义 ActivityAttributes(在主 App 中) #

新建文件:TimerAttributes.swift

import ActivityKit

struct TimerAttributes: ActivityAttributes {
    public struct ContentState: Codable, Hashable {
        var remainingTime: TimeInterval
    }

    var taskName: String
}

🚀 3. 启动 Live Activity(在主 App 中) #

ContentView.swift 中:

import SwiftUI
import ActivityKit

struct ContentView: View {
    @State private var activity: Activity<TimerAttributes>?

    var body: some View {
        VStack(spacing: 20) {
            Button("启动计时器 (25分钟)") {
                startTimer()
            }
            .buttonStyle(.borderedProminent)

            Button("更新剩余时间 (10分钟)") {
                updateTimer()
            }
            .disabled(activity == nil)

            Button("结束计时器") {
                endTimer()
            }
            .disabled(activity == nil)
        }
        .padding()
    }

    func startTimer() {
        let attributes = TimerAttributes(taskName: "专注任务")
        let contentState = TimerAttributes.ContentState(remainingTime: 25 * 60)

        do {
            activity = try Activity<TimerAttributes>.request(
                attributes: attributes,
                contentState: contentState,
                pushType: nil
            )
        } catch {
            print("启动失败: \(error)")
        }
    }

    func updateTimer() {
        Task {
            await activity?.update(using: TimerAttributes.ContentState(remainingTime: 10 * 60))
        }
    }

    func endTimer() {
        Task {
            await activity?.end(dismissalPolicy: .immediate)
            activity = nil
        }
    }
}

📱 4. 设计 Widget Extension #

修改 Widget 文件名(可选) #

将自动生成的 Widget 重命名为 TimerLiveActivityWidget.swift

修改内容如下: #

import ActivityKit
import WidgetKit
import SwiftUI

struct TimerLiveActivityWidget: Widget {
    var body: some WidgetConfiguration {
        ActivityConfiguration(for: TimerAttributes.self) { context in
            // 锁屏界面
            VStack {
                Text(context.attributes.taskName)
                    .font(.headline)
                Text("剩余时间: \(Int(context.state.remainingTime / 60)) 分钟")
            }
            .padding()
        } dynamicIsland: { context in
            // 动态岛界面
            DynamicIsland {
                DynamicIslandExpandedRegion(.leading) {
                    Text("🕒")
                }
                DynamicIslandExpandedRegion(.trailing) {
                    Text("\(Int(context.state.remainingTime / 60)) min")
                        .bold()
                }
                DynamicIslandExpandedRegion(.bottom) {
                    Text("正在专注中...")
                        .font(.caption)
                }
            } compactLeading: {
                Text("⏱")
            } compactTrailing: {
                Text("\(Int(context.state.remainingTime / 60))")
            } minimal: {
                Text("⏱")
            }
        }
    }
}

🛠 5. 配置 Extension 的 Info.plist #

确保包含下列键值:

<key>NSExtension</key>
<dict>
    <key>NSExtensionAttributes</key>
    <dict>
        <key>com.apple.widgetkit.live-activity</key>
        <true/>
    </dict>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.widgetkit-extension</string>
</dict>

🧪 6. 真机测试 & 模拟更新 #

Live Activities 仅支持真机测试,特别是动态岛部分。你可以:

  • 点击“启动计时器”

  • 回到主屏幕或锁屏,观察 Live Activity 展示

  • 点“更新剩余时间”后观察变化

  • 点“结束计时器”后 UI 消失


📌 后续可拓展内容(可选) #

  • 自动倒计时更新(使用 Timer)

  • 使用 pushType: .token 获取远程更新能力

  • 提供多个计时任务并发

  • 使用后台任务继续刷新状态(Background Tasks)

本文共 894 字,创建于 May 19, 2025
相关标签: Xcode, ByAI, SwiftUI, ChatGPT