EasyApp

控制中心小组件

了解如何在 EasyAppSwiftUI 中实现控制中心小组件

简介

EasyAppWidgetControl 基于 iOS 18 的 Control Center Widgets(控制中心小组件)构建,允许用户在控制中心或锁屏快速切换应用内定时器状态。本文介绍控件配置、数据提供者以及如何扩展更多控制项。

核心结构

  • 控制入口 EasyAppWidgetControl 遵循 ControlWidget 协议,通过 AppIntentControlConfiguration 注册。
  • 数据模型 内部定义的 Value 保存控件当前状态(isRunningname)。
  • Intent 配置 TimerConfigurationStartTimerIntent 允许用户编辑定时器名称并在系统中写回状态。

关键代码位于 EasyAppSwiftUI/EasyAppWidget/EasyAppWidgetControl.swift

struct EasyAppWidgetControl: ControlWidget {
    static let kind: String = "sunshineLixun.EasyAppSwiftUI.EasyAppWidget"

    var body: some ControlWidgetConfiguration {
        AppIntentControlConfiguration(
            kind: Self.kind,
            provider: Provider()
        ) { value in
            ControlWidgetToggle(
                "Start Timer",
                isOn: value.isRunning,
                action: StartTimerIntent(value.name)
            ) { isRunning in
                Label(isRunning ? "On" : "Off", systemImage: "timer")
            }
        }
        .displayName("Timer")
        .description("A an example control that runs a timer.")
    }
}

Provider 与状态

  • Provider 实现 AppIntentControlValueProvider,负责返回控件在预览与实际运行时的 Value
  • currentValue 可以连接到实际的业务数据(例如后台定时器)。示例代码暂时返回 true 表示定时器正在运行,可替换为真实逻辑。
struct Provider: AppIntentControlValueProvider {
    func previewValue(configuration: TimerConfiguration) -> Value {
        EasyAppWidgetControl.Value(isRunning: false, name: configuration.timerName)
    }

    func currentValue(configuration: TimerConfiguration) async throws -> Value {
        let isRunning = true // Check if the timer is running
        return EasyAppWidgetControl.Value(isRunning: isRunning, name: configuration.timerName)
    }
}

Intent 定义

  • TimerConfiguration 让用户在控制中心编辑面板中自定义定时器名称。
  • StartTimerIntent 实现 SetValueIntent,用于处理开关的实际写回逻辑(示例中仅返回 .result(),可以扩展为调用业务层接口)。
struct StartTimerIntent: SetValueIntent {
    static let title: LocalizedStringResource = "Start a timer"

    @Parameter(title: "Timer Name")
    var name: String

    @Parameter(title: "Timer is running")
    var value: Bool

    func perform() async throws -> some IntentResult {
        // Start the timer…
        return .result()
    }
}

集成步骤

  1. 确认 Xcode 版本 >= 16,并在项目中启用 Control Center Widgets 能力。
  2. EasyAppWidgetBundle.swift 中包含 EasyAppWidgetControl() 以注册控制器:
    @main
    struct EasyAppWidgetBundle: WidgetBundle {
        var body: some Widget {
            EasyAppWidget()
            EasyAppWidgetLiveActivity()
            EasyAppWidgetControl()
        }
    }
  3. 构建并安装应用后,打开系统设置或控制中心编辑面板,添加 Timer 控件。
  4. 在控制中心点击控件,将触发 StartTimerIntent。可在 Intent 中调用实际业务逻辑,完成定时器开关。

自定义建议

  • 修改 ControlWidgetToggle 文案、图标或替换为 ControlWidgetButton 以匹配其他交互类型。
  • 若控件需要展示更多状态,可扩展 Value 结构并在 Provider 中返回附加字段。
  • 使用 LocalizedStringResource 为显示名称与描述提供多语言支持,并同步更新 localizable 文件。

调试与常见问题

  • 控件未出现在控制中心:确认 Widget Extension 支持 iOS 18+,并在真机上测试(模拟器暂不支持 Control Center Widgets)。
  • 状态未刷新:在 currentValue 中调试实际业务返回值,必要时使用 WidgetCenter.shared.reloadAllTimelines() 或新的 Control API 强制刷新。
  • Intent 未执行:确保 StartTimerIntent.perform() 实现了业务逻辑,并在主应用中启用相应的 App Intent 权限。
  • 命名冲突:更新 kind 字段时请保持唯一性,避免与桌面/锁屏 Widget 重复。

通过 EasyAppWidgetControl,你可以在控制中心快速暴露关键操作,将桌面、锁屏、灵动岛与控制中心体验串联起来,为用户提供统一的多端交互入口。

Last updated on