I am trying to update the live activities with push notifications and I use the two methods one to start the live activity and the other to update the live activity which are as follows:
func startActivity(completion: @escaping (String) -> Void) {
print("startActivity() is running")
let attributes = PizzaDeliveryAttributes(numberOfPizzas: 2, totalAmount: "420", orderNumber: "359")
let future = Calendar.current.date(byAdding: .minute, value: 35, to: Date())!.addingTimeInterval(40)
let date = Date.now...future
let initialContentState = PizzaDeliveryAttributes.ContentState(driverName: "Bill James", deliveryTimer:date)
let activityContent = ActivityContent(state: initialContentState, staleDate: Calendar.current.date(byAdding: .minute, value: 30, to: Date())!)
do {
self.deliveryActivity = try Activity.request(attributes: attributes, content: activityContent, pushType: .token)
print("Requested a pizza delivery Live Activity (String(describing: self.deliveryActivity?.id)).")
Task {
for await data in self.deliveryActivity!.pushTokenUpdates {
let myToken = data.map {String(format: "%02x", $0)}.joined()
print("Token printed: (myToken)")
completion(myToken)
}
}
} catch (let error) {
print("Error requesting pizza delivery Live Activity (error.localizedDescription).")
}
}
func updatePizzaDeliveryStatus(minutes: String, seconds: String) async {
var future = Calendar.current.date(byAdding: .minute, value: (Int(minutes) ?? 0), to: Date())!
future = Calendar.current.date(byAdding: .second, value: (Int(seconds) ?? 0), to: future)!
let date = Date.now...future
let updatedDeliveryStatus = PizzaDeliveryAttributes.PizzaDeliveryStatus(driverName: "Anne Johnson", deliveryTimer: date)
let alertConfiguration = AlertConfiguration(title: "Delivery update", body: "Your pizza order will arrive in 25 minutes.", sound: .default)
let updatedContent = ActivityContent(state: updatedDeliveryStatus, staleDate: nil)
do {
try await self.deliveryActivity?.update(updatedContent, alertConfiguration: alertConfiguration)
} catch {
print("Failed to update Live Activity: (error)")
}
}
I am able to generate pushTokens on every new live activity started and also send the curl command through to update the live activity which I will provide below. I expect the dynamic content of the attributes to update, but nothing happens when the push goes through.
curl -v
--header "apns-topic:<Bundle-Id>.push-type.liveactivity"
--header "apns-push-type:liveactivity"
--header "authorization: bearer $AUTHENTICATION_TOKEN"
--data
'{"aps": {
"timestamp":1663300480,
"event": "update",
"content-state": {
"driverName": "Tony Stark",
"deliveryTimer": {
"start": 1663300480,
"end": 1663301480
}
},
"alert": {
"title": "Race Update",
"body": "Tony Stark is now leading the race!"
}
}}'
--http2
https://${APNS_HOST_NAME}/3/device/$DEVICE_TOKEN
And this is what content state in the attributes look like:
public struct ContentState: Codable, Hashable {
var driverName: String
var deliveryTimer: ClosedRange<Date>
}
Any help or insight is deeply appreciated.
2
Answers
Ok so I figured it out.
What I did not realise is the timestamp key in the apns payload, i.e;
Needs to be updated every time you send a payload. You can get the latest time stamps from here. Hope this helps!
When you run your curl, if you’re getting a status code
200
response, then the push notifications are making it to the device.Assuming you’re getting a 200, I can see it being two things.
ContentState
serializabilityTimestamp
Your timestamp needs to be updated each time you send a push (can’t send 2 pushes with the same timestamp). And the time has to be current. You can get that here.
ContentState
iOS is using codable to deserialize the push notification
content-state
into the structContentState
. For this to work, the keys must match exactly for both. (I know this ContentState is from their example, but they use a simpler one for the push example)ClosedRange is codable, but I don’t know what the keys are (possibly not
start
andend
).Try putting only primitive types in your ContentState and see if that fixes it. If so, you can investigate the codability of ClosedRange. Let me know how that goes!