2

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.

  • I'm experiencing the same thing , One aside question , Should we use bundle id of the app or the live extension as the apns-token ? Also what is apns-push-type? – sheko May 15 '23 at 07:38
  • 1
    As far as I know you should be using the bundle id of the app and not the extension. the apis-push-type is liveactivities as we are setting the type in the header as follows: --header "apns-push-type:liveactivity". If this does not answer your second question, can you elaborate more on it? – Eser Lodhia May 15 '23 at 07:53
  • thanks, but when i set the device token to the activity's push token generated from **pushTokenUpdates** in the curl , i got **DeviceTokenNotForTopic** while i set the app bundle as apns-topic – sheko May 15 '23 at 08:06
  • 1
    I tried adding targets bundle as apns topic and I got **DeviceTokenNotForTopic**. goes through fine with app bundle id. – Eser Lodhia May 15 '23 at 09:37

2 Answers2

0

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.

  1. Issue with stale timestamps
  2. Issue with ContentState serializability

Timestamp

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 struct ContentState. 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 and end).

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!

   "content-state": {
      "driverName": "Tony Stark",
      "deliveryStartInt": 1663300480,
      "deliveryEndInt": 1663301480,   
    }
   },
 public struct ContentState: Codable, Hashable {
            var driverName: String
            var deliveryStartInt: Int
            var deliveryEndInt: Int
        }
Kyle Venn
  • 4,597
  • 27
  • 41
  • 1
    I made it more simpler and changed the second variable in the content state as estimatedDelivery: String and made changes accordingly to start and update methods. Unfortunately, it still does not work for me. Ps: I do get 200 response. – Eser Lodhia May 16 '23 at 05:47
  • Hello, I was able to figure it out! I have provided the solution. Thank you! – Eser Lodhia May 16 '23 at 11:11
  • Great! I updated the answer to cover those cases. Was your original deliveryTimer serializing correctly? – Kyle Venn May 16 '23 at 15:32
  • 1
    I have a feeling i was messing up somewhere with the closed range, what I did was change the second dynamic variable to a simple string. Either ways, I will check the first content state with the close range and give you and update! – Eser Lodhia May 16 '23 at 20:22
0

Ok so I figured it out.

What I did not realise is the timestamp key in the apns payload, i.e;

"timestamp":1663300480

Needs to be updated every time you send a payload. You can get the latest time stamps from here. Hope this helps!