インテントの作成
まず、インテントを作成していきます。
これはLiveActivityやDynamicIsland内に設置したボタンをタップした際の処理となります。
import AppIntents
@available(iOS 17.0, *)
struct TestIntent: LiveActivityIntent {
public init() {}
static var title = LocalizedStringResource("Test")
public func perform() async throws -> some IntentResult {
return .result()
}
}
このTestIntent内にNotificationCenterの処理を追加していきます。
また、固有のNotification.Nameを使用するためにNotification.Nameの拡張を行なっていきます。
TestIntent.swiftファイル内のコードは以下のようになります。
import AppIntents
@available(iOS 17.0, *)
struct TestIntent: LiveActivityIntent {
public init() {}
static var title = LocalizedStringResource("Test")
public func perform() async throws -> some IntentResult {
NotificationCenter.default.post(name: Notification.Name.testNotification, object: self)
return .result()
}
}
extension Notification.Name {
static let testNotification = Notification.Name(rawValue: "TestNotification")
}
DynamicIsland内にボタン設置
次に、先ほど作成したインテントを使用する処理を追加していきます。
DynamicIslandExpandedRegion(.bottom)内に作成しているのですが、それ以外はデフォルトのままです。
struct LiveActivityTest: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: LiveActivityAttributes.self) { context in
// Lock screen/banner UI goes here
VStack {
Text("Hello \(context.state.emoji)")
}
.activityBackgroundTint(Color.cyan)
.activitySystemActionForegroundColor(Color.black)
} dynamicIsland: { context in
DynamicIsland {
// Expanded UI goes here. Compose the expanded UI through
// various regions, like leading/trailing/center/bottom
DynamicIslandExpandedRegion(.leading) {
Text("Leading")
}
DynamicIslandExpandedRegion(.trailing) {
Text("Trailing")
}
DynamicIslandExpandedRegion(.bottom) {
HStack {
Text("Bottom \(context.state.emoji)")
if #available(iOS 17.0, *) {
Button(intent: TestIntent()) {
Text("tap")
}
}
}
}
} compactLeading: {
Text("L")
} compactTrailing: {
Text("T \(context.state.emoji)")
} minimal: {
Text(context.state.emoji)
}
.widgetURL(URL(string: "http://www.apple.com"))
.keylineTint(Color.red)
}
}
}
DynamicIslandExpandedRegion(.bottom)内のボタンにインテントを設定しています。
これをタップすることで先ほど作成したインテントのperform()内の処理が走ります。
アプリ側の処理
アプリ内にDynamicIsland内のボタンをタップした際の処理を追加していきます。
part1で作成したものを使用していきます。
import SwiftUI
import ActivityKit
class ContentModel: ObservableObject {
@Published var test = "1"
init() {
NotificationCenter.default.addObserver(self, selector: #selector(test2), name: .testNotification, object: nil)
}
@objc
func test2(notification: Notification) {
DispatchQueue.main.async {
self.test = "2"
}
}
}
struct ContentView: View {
@StateObject var model = ContentModel()
var body: some View {
VStack {
Text("Data: \(model.test)")
Button("開始") {
let contentState = LiveActivityAttributes.ContentState(emoji: "🍛")
let attributes = LiveActivityAttributes(contentState: contentState,
name: "テスト")
do {
_ = try ActivityKit.Activity<LiveActivityAttributes>.request(attributes: attributes,
content: .init(state: contentState,
staleDate: nil), pushType: nil)
} catch {
print(error)
}
}
}
}
}
これにより、DynamicIslandのボタンをタップするとTextが「1」→「2」へとなっていることが確認できます。
ボタンタップ時のNotificationを感知する処理をContentModelに記載してください。
なお、testの値はメインスレッド内で更新するようにしてください。