ActivityKit

RSS for tag

Help people keep track of tasks and events that they care about with Live Activities on the Lock Screen, the Dynamic Island, and in StandBy.

Posts under ActivityKit tag

112 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

frequentPushEnablementUpdates for live activity is never called.
frequentPushEnablementUpdates asynchronous sequence is never called even if 'More Frequent Updates' is toggled ON or OFF. for await frequentPushEnabled in ActivityAuthorizationInfo().frequentPushEnablementUpdates { // never called } Though we are able to get the 'More Frequent Updates' value once by the following: var isEnabled = ActivityAuthorizationInfo().frequentPushesEnabled //true if ON, false if OFF This only gives the result once as it is not async observation sequence. But the 'frequentPushEnablementUpdates' async sequence is never called. As per the doc - 'frequentPushEnablementUpdates' is an asynchronous sequence you use to observe whether a person permitted you to update Live Activities with frequent ActivityKit push notifications.
0
0
33
1d
Does Live Activity always receive updates for pushToStartTokenUpdates and activityUpdates?
Our context involves smart kitchen appliances, where cooking may be initiated by an app or directly by the device. When the app is not running, we can only start a Live Activity through a remote push notification. However, an increasing number of users report issues where they cannot update or terminate the Live Activity. While we can reproduce this issue in some cases, it is inconsistent and lacks a clear pattern. I have a sample project and would like to confirm the following questions: When the app is not running, does each pushToStartToken update wake the app and reliably trigger the callback below? for await pushToken in Activity<DeviceAttributes>.pushToStartTokenUpdates { } When the app is not running, does each pushTokenUpdates update wake the app and reliably trigger the callback below? Task { for await activity in Activity<DeviceAttributes>.activityUpdates { Task { for try await tokenData in activity.pushTokenUpdates { } } } } Must pushToStartTokenUpdates and pushTokenUpdates be placed directly in application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?), or can they be in another wrapper, such as an RxSwift wrapper? If pushTokenUpdates is updated, but the received pushToken fails to synchronize to the server due to network issues, how should this be handled? Alternatively, if you have any better suggestions, I would be very grateful to hear them. Here is a simple example.
1
0
33
2d
BadDeviceToken Error in Live Activities
Hello everyone, I’m currently receiving feedback from clients in a production environment who are encountering a BadDeviceToken error with Live Activities, which is preventing their states from updating. However, for other clients, the token is working fine and everything functions as expected. I’m collaborating with the back-end developers to gather more information about this issue, but the only log message we’re seeing is: Failed to send a push, APNS reported an error: BadDeviceToken I would greatly appreciate it if anyone could provide some insight or information on how to resolve this issue.
2
0
106
2w
Sample ActivityConfiguration for Apple Watch?
I'm unable to find sample code that demonstrates how to support a custom Live Activity layout for Apple Watch. I have read the documentation and have added the supplementalActivityFamilies with small and medium. However, I am not able to detect when the activityFamily is set to small. This is what I'm trying to use without success: struct MyWidgetLiveActivity: Widget { @Environment(\.activityFamily) var activityFamily: ActivityFamily var body: some WidgetConfiguration { ActivityConfiguration(for: MyWidgetAttributes.self) { context in if activityFamily == .small { Text("Apple Watch! \(activityFamily.description)") } else { Text("Not small family: \(activityFamily.description)") } } dynamicIsland: { context in return DynamicIsland { DynamicIslandExpandedRegion(.leading) { Text("Leading") } DynamicIslandExpandedRegion(.trailing) { Text("Trailing") } DynamicIslandExpandedRegion(.bottom) { Text("Bottom") } } compactLeading: { Text("CL") } compactTrailing: { Text("CT") } minimal: { Text("M") } } .supplementalActivityFamilies([.small, .medium]) } } This code shows "Not small family: medium" on my Apple Watch. Could somebody provide some insight into why this doesn't work for me?
2
0
117
1w
How to detect interaction of the widget's toggle at locked device
https://developer.apple.com/documentation/WidgetKit/Adding-interactivity-to-widgets-and-Live-Activities#Add-a-toggle Before explaining the situation, I referred to this document. I'm making a widget with a toggle that works with Intent. (To be precise, it's Live Activity, but Apple's literally toggling and button interaction are implemented in the same way) If you press the toggle when the device is locked, the toggle represents the state. However, as described at the top of the same document, the device must be unlocked to execute Intent, so I can't actually change the data. That's fine, but how can I return the isOn of the toggle to false? I'm blocked here because no code is executed. If it is a widget in the home screen, it will be basically unlocked, so I can proceed according to the method of the document, but if it is today's view, user can access it even if device is locked. I tested it in today's view with the Reminders app, If I don't unlock the device after tapping the toggle it returns the toggle back to false state. I wonder how I can achieve this. Is there an API that I missed? Summary. Tap the toggle of the widget while the device is locked. The device waits for unlocking, but the user cancels it without unlocking it. (Still locked) Return the isOn of the toggle to false. <- The part I want.
2
0
142
6d
Decoding Error when starting a Live Activity via Push Notification
Hi, I'm a bit stuck when it comes to implementing live activities. I'm trying to start one by sending a push. my activity attributes looks like: import Foundation import ActivityKit public struct NeoPrototypeActivity: ActivityAttributes { public let classId: String public let name: String public let room: String public let startTime: Date public init(classId: String, name: String, room: String, startTime: Date) { self.classId = classId self.name = name self.room = room self.startTime = startTime } public struct ContentState: Codable & Hashable { public let participationState: ParticipationState public init(participationState: ParticipationState) { self.participationState = participationState } } } public enum ParticipationState: String, Codable, Hashable, Equatable { case upcoming case upcomingOnWaitingList case checkedIn case waitingList case lostSpot case lostSpotFromWaitingList case classCompleted public var description: String { switch self { case .upcoming: return "Upcoming" case .upcomingOnWaitingList: return "Upcoming on Waiting List" case .checkedIn: return "Checked In" case .waitingList: return "Waiting List" case .lostSpot: return "Lost Spot" case .lostSpotFromWaitingList: return "Lost Spot from Waiting List" case .classCompleted: return "Class completed" } } } which I have in a SPM package that is imported by my widget and iOS targets. Then I am sending a push notification (to my simulator in this case) with the following payload { "aps": { "timestamp": 1728419211, "event": "start", "content-state": { "participationState": "upcoming" }, "attributes-type": "NeoPrototypeActivity", "attributes": { "classId": "1234", "name": "Indoor Running", "room": "room 2", "startTime": "2024-10-19T13:22:59+02:00" }, "alert": { "title": "Hola Mundo", "body": "Todo Bien" } } } I am using the right values for the deviceID when sending the push. I get a 200 ok from the CloudKit console. yet my live activity doesn't start. I'm trying to look at the errors in the Console app and the only relevant thing is see is: [NeoPrototypeActivity] Error creating activity: NSCocoaErrorDomain (4864) The data couldn’t be read because it isn’t in the correct format. It seems like a decoding error, but I don't know what exactly failed I wrote some test to try the decoding like: import Testing import Foundation @testable import PrototypeActivities @Test func decoding() async throws { struct StateContainer: Codable { let participationState: ParticipationState } let jsonString = """ { "participationState": "upcoming" } """ let json = try #require(jsonString.data(using: .utf8)) let result = try JSONDecoder().decode(StateContainer.self, from: json) #expect(result.participationState == .upcoming) } @Test func decodingActivity() throws { // let jsonString = """ // { // "classId": "1234", // "name": "Indoor Running", // "room": "room 2", // "startTime": "2024-10-19T11:22:59Z" // } // """ let jsonString = """ { "classId": "1234", "name": "Indoor Running", "room": "room 2", "startTime": 1729337784 } """ let json = try #require(jsonString.data(using: .utf8)) let jsonDecoder = JSONDecoder() // jsonDecoder.dateDecodingStrategy = .iso8601 let activity = try jsonDecoder.decode(NeoPrototypeActivity.self, from: json) #expect(activity.classId == "1234") #expect(activity.name == "Indoor Running") }``` but even with using the default JSON decoder date format, I still get the same error. Not sure how to fix this or to get more details.
2
0
197
2w
Using a custom DiscreteFormatStyle in Live Activities
With iOS 18, Text has a new initializer that takes in a TimeDataSource and a DiscreteFormatStyle. Similar to this question, I'd like to make a compact timer but can't find a way to do that with any of the system formats. Since the new API takes in a DiscreteFormatStyle though I figure I could make my own. This works in an app but not in a Live Activity; in Previews it crashes and in the simulator the view looks like placeholder. Are custom format styles not supported in this case? Or might there something wrong with my implementation? Formatter Preview Crash Log
1
0
179
2w
Live Activity expanded leading/trailing regions VoiceOver focus misalignment
There seems to be a misalignment when using VoiceOver and selecting the leading/trailing regions in the expanded presentation for Live Activities. This is demonstrated with an extremely basic sample project, where the expanded region is defined by the following code: DynamicIsland { DynamicIslandExpandedRegion(.leading) { Text("Leading") } DynamicIslandExpandedRegion(.trailing) { Text("Trailing") } DynamicIslandExpandedRegion(.bottom) { Text("Bottom \(context.state.emoji)") } } Is this simply a bug or am I doing something incorrectly/is there a workaround?
2
0
158
2w
Can I fix this big difference between swiftui preview and actual watch widget layout?
Hi, working on customising my live activity Smart Stack layout for ios18. A thing that is very frustrating is that I consistently looks different for me in the Xcode preview and on the actual watch. See attached screenshots below. The sizes are different, and italic doesn't work on the watch, for example. It makes it time-consuming and unpredictable, so I was wondering if this is a known issue or if I'm doing something wrong, and also can I do anything? thanks edit: this is the layout: var body: some View { VStack(alignment: .center, spacing:4) { HStack(alignment: .center) { IconView(resource: "n-compact-w", bgColor: Color.checkedIn, padding: 2, paddingRight: 6, paddingBottom: 6) .frame(maxWidth: 25, maxHeight: 25).aspectRatio(1, contentMode: .fit) Text("Checked Out") .font(.title3).bold() } Text(status.loc) .font(.headline) .multilineTextAlignment(.center) Text(FormatUtils.getFormattedDateTime(status.time)).font(.subheadline) .multilineTextAlignment(.center).italic() } }
4
0
204
3w
live activity push channel management request return "TopicMismatch" when bundle in include capital letter
When I request channel list for bundle id "com.apnspush.LiveActivityPushDemo", the request returns "TopicMismatch". Then when I request channel list for bundle id "com.apnspush.liveactivitypush", the request return is normal. I have tried all my bundle ids that include capital letters, they all failed with "TopicMismatch". Does anyone know the reason? curl -v -X GET \ -H "authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg" \ -H "apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127" \ --http2 \ https://api-manage-broadcast.sandbox.push.apple.com:2195/1/apps/com.apnspush.LiveActivityPushDemo/all-channels Note: Unnecessary use of -X or --request, GET is already inferred. * Host api-manage-broadcast.sandbox.push.apple.com:2195 was resolved. * IPv6: (none) * IPv4: 17.138.176.4 * Trying 17.138.176.4:2195... * Connected to api-manage-broadcast.sandbox.push.apple.com (17.138.176.4) port 2195 * ALPN: curl offers h2,http/1.1 * (304) (OUT), TLS handshake, Client hello (1): * CAfile: /etc/ssl/cert.pem * CApath: none * (304) (IN), TLS handshake, Server hello (2): * (304) (IN), TLS handshake, Unknown (8): * (304) (IN), TLS handshake, Request CERT (13): * (304) (IN), TLS handshake, Certificate (11): * (304) (IN), TLS handshake, CERT verify (15): * (304) (IN), TLS handshake, Finished (20): * (304) (OUT), TLS handshake, Certificate (11): * (304) (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF * ALPN: server accepted h2 * Server certificate: * subject: C=US; ST=California; O=Apple Inc.; CN=api-manage-broadcast.sandbox.push.apple.com * start date: May 30 17:31:41 2024 GMT * expire date: Apr 10 00:00:00 2025 GMT * subjectAltName: host "api-manage-broadcast.sandbox.push.apple.com" matched cert's "api-manage-broadcast.sandbox.push.apple.com" * issuer: CN=Apple Public Server RSA CA 12 - G1; O=Apple Inc.; ST=California; C=US * SSL certificate verify ok. * using HTTP/2 * [HTTP/2] [1] OPENED stream for https://api-manage-broadcast.sandbox.push.apple.com:2195/1/apps/com.apnspush.LiveActivityPushDemo/all-channels * [HTTP/2] [1] [:method: GET] * [HTTP/2] [1] [:scheme: https] * [HTTP/2] [1] [:authority: api-manage-broadcast.sandbox.push.apple.com:2195] * [HTTP/2] [1] [:path: /1/apps/com.apnspush.LiveActivityPushDemo/all-channels] * [HTTP/2] [1] [user-agent: curl/8.7.1] * [HTTP/2] [1] [accept: */*] * [HTTP/2] [1] [authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg] * [HTTP/2] [1] [apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127] > GET /1/apps/com.apnspush.LiveActivityPushDemo/all-channels HTTP/2 > Host: api-manage-broadcast.sandbox.push.apple.com:2195 > User-Agent: curl/8.7.1 > Accept: */* > authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg > apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127 > * Request completely sent off < HTTP/2 403 < apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127 < * Connection #0 to host api-manage-broadcast.sandbox.push.apple.com left intact {"reason":"TopicMismatch"}% curl -v -X GET \ -H "authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg" \ -H "apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127" \ --http2 \ https://api-manage-broadcast.sandbox.push.apple.com:2195/1/apps/com.apnspush.liveactivitypush/all-channels Note: Unnecessary use of -X or --request, GET is already inferred. * Host api-manage-broadcast.sandbox.push.apple.com:2195 was resolved. * IPv6: (none) * IPv4: 17.138.176.4 * Trying 17.138.176.4:2195... * Connected to api-manage-broadcast.sandbox.push.apple.com (17.138.176.4) port 2195 * ALPN: curl offers h2,http/1.1 * (304) (OUT), TLS handshake, Client hello (1): * CAfile: /etc/ssl/cert.pem * CApath: none * (304) (IN), TLS handshake, Server hello (2): * (304) (IN), TLS handshake, Unknown (8): * (304) (IN), TLS handshake, Request CERT (13): * (304) (IN), TLS handshake, Certificate (11): * (304) (IN), TLS handshake, CERT verify (15): * (304) (IN), TLS handshake, Finished (20): * (304) (OUT), TLS handshake, Certificate (11): * (304) (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF * ALPN: server accepted h2 * Server certificate: * subject: C=US; ST=California; O=Apple Inc.; CN=api-manage-broadcast.sandbox.push.apple.com * start date: May 30 17:31:41 2024 GMT * expire date: Apr 10 00:00:00 2025 GMT * subjectAltName: host "api-manage-broadcast.sandbox.push.apple.com" matched cert's "api-manage-broadcast.sandbox.push.apple.com" * issuer: CN=Apple Public Server RSA CA 12 - G1; O=Apple Inc.; ST=California; C=US * SSL certificate verify ok. * using HTTP/2 * [HTTP/2] [1] OPENED stream for https://api-manage-broadcast.sandbox.push.apple.com:2195/1/apps/com.apnspush.liveactivitypush/all-channels * [HTTP/2] [1] [:method: GET] * [HTTP/2] [1] [:scheme: https] * [HTTP/2] [1] [:authority: api-manage-broadcast.sandbox.push.apple.com:2195] * [HTTP/2] [1] [:path: /1/apps/com.apnspush.liveactivitypush/all-channels] * [HTTP/2] [1] [user-agent: curl/8.7.1] * [HTTP/2] [1] [accept: */*] * [HTTP/2] [1] [authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg] * [HTTP/2] [1] [apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127] > GET /1/apps/com.apnspush.liveactivitypush/all-channels HTTP/2 > Host: api-manage-broadcast.sandbox.push.apple.com:2195 > User-Agent: curl/8.7.1 > Accept: */* > authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg > apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127 > * Request completely sent off < HTTP/2 200 < apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127 < * Connection #0 to host api-manage-broadcast.sandbox.push.apple.com left intact {"channels":["vtVPwIhLEe8AAG79CdMNuQ=="]}%
0
0
145
3w
Get Cache error with ActivityKit when reboot App。
We are currently experiencing the following weird issue with our iPhone app. As the title says, NSUserDefaults is losing our custom keys and values when phone is rebooted but not unlocked, and this is happening on a very specific scenario with ActivityKit. Context: We are using the NSUserDefaults in the app to store user data (e.g. username). Issue: An error occurred with no permission to access cached messages after a restart. Scenario: When receiving a Dynamic Island notification, if the phone is restarted, after unlocking the phone and tapping on the Dynamic Island to open the App, all cached information results in an error. Reasons for the error: After restarting the APP, the files are in a locked state. The Dynamic Island proactively invokes the App method. When executing the startup method and retrieving cached messages, an error occurs due to lack of permission. All storage, including files, NSUserDefaults, Keychain, and Plist retrieval, results in errors. The error message is as follows: { "errorCode": "-25308", "errorDesc": "Error Domain=com.samsoffes.sskeychain Code=-25308 "(null)"", "serviceName": "com.qunar.qunarclient8", "account": "iid" } The data returned at this time is in a protected state, [UIApplication sharedApplication].isProtectedDataAvailable. Any help or idea will be truly appreciated :)
0
0
117
4w
How can I use an image for my live activity smartstack layout?
Hello, I am updating my live activity for the new ios18 Smart Stack functionality. I got it working through the WWDC session (Bring your live activities to Apple watch). I'm doing supplementalActivityFamilies([.small]) and then a custom layout in the .small ActivityFamily However, any images I try to use in the Smart Stack just show up as grey squares. (it works on the phone live activity) I suspect it's because my app images are not moved over to the watch? Because I don't have a watch app and such no watch target? If anyone can help me understand if there's anything I can do in order to have a custom image show up on the smart stack, I'd be very grateful.
3
0
180
4w
How to disable Live Activity on Apple Watch while keeping it enabled on iPhone?
I'm using Live Activity features in my app, but I want to customize the user experience across different Apple devices. Specifically, I'd like to: Keep Live Activity enabled and functioning on the iPhone Disable or prevent Live Activity from appearing on the connected Apple Watch Is this level of device-specific control possible with Live Activity? If so, what's the best approach to implement this functionality? What I've tried: I've looked through Apple's documentation on Live Activity, but couldn't find specific information about device-level control. I've experimented with ActivityKit, but haven't found a clear way to distinguish between iPhone and Apple Watch when pushing updates.
4
0
339
3w
Obtaining LiveActivities pushToStart token
I want to add Live Activities to my e-commerce app to show the estimated delivery ETA when an order is out for delivery, with the Live Activity initiated from the server. Issue 1: How can I consistently obtain a pushToStart token when a user logs in to my e-commerce app? Currently, I’m considering starting and ending a dummy Live Activity to retrieve the token. Is there a better way to trigger pushToStartTokenUpdates and send the token to my server? Issue 2: How do I properly invalidate the pushToStart token when a user logs out, ensuring the next user doesn’t inherit the same token? Ideally, I don't want the user to wait until the token is automatically invalidated before logging out.
2
0
203
Oct ’24
Live Activity activityBackgroundTint not using dark mode colour variant
I have defined a colour in the asset catalog of my widget extension. I am using this widget extension for my live activity. This colour has both an ‘Any’ and ‘Dark’ appearance. I am using this colour in the activityBackgroundTint modifier for my main live activity view (the ActivityPreviewViewKind is content, visible on the Lock Screen). In light mode, this works as expected, but in dark mode, the background colour is still the light mode variant. The content within the view changes according to whether the system is in light or dark mode, but the background does not. I want to avoid using just the background modifier instead of activityBackgroundTint, as this does not colour the ‘Allow Live Activities from …’ and ‘Clear’ sections, which is undesirable. I have also tried reading colorScheme from the environment and choosing the light or dark mode colour variant accordingly, but this workaround also doesn’t completely work. If you keep changing from light and dark mode (via the Settings app, not the control centre, for whatever reason), the background colour actually becomes the opposite of the expected value in this case. Is there a workaround that can help me achieve what I want, or am I simply doing something wrong? I have filed a bug report under FB15148099
1
2
211
Sep ’24