{"id":70467,"date":"2025-03-19T16:16:12","date_gmt":"2025-03-19T10:46:12","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=70467"},"modified":"2025-03-19T16:35:00","modified_gmt":"2025-03-19T11:05:00","slug":"live-activities-introduction-and-setup-part-2","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/live-activities-introduction-and-setup-part-2\/","title":{"rendered":"Live Activities Introduction and Setup \u2013 Part 2"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>In <a href=\"https:\/\/www.tothenew.com\/blog\/live-activities-introduction-and-setup-part-1\/\">Part 1<\/a> we learned about how to set up live activities from scratch. We learned about how to set up, design, and implement live activities for different modes of the iPhone including Lock Screen and Dynamic Island. We learned about the life cycle of activity from the app. How to start, update, and end an activity from the app only. But the real power of live activities comes when it works with a backend push notification when the app is in a killed state. To update users about new actions on that activity through push notifications show the real use of this api. In this part, we will learn about the live activity life cycle through push notifications.<\/p>\n<h2>Push Notifications for lifecycle operations<\/h2>\n<h3>Start Activity<\/h3>\n<p>On devices with iOS 17.2 or newer, it\u2019s possible to obtain the push token without starting the live activity. To do so, we need to observe the <strong>pushToStartTokenUpdates<\/strong> asynchronous sequence. Once we receive it and send it to the backend, it\u2019s possible to start the live activity anytime using push notification.<\/p>\n<div id=\"attachment_70466\" style=\"width: 1958px\" class=\"wp-caption aligncenter\"><img aria-describedby=\"caption-attachment-70466\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-70466 size-full\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.19.27\u202fPM.png\" alt=\"Startin a activity\" width=\"1948\" height=\"314\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.19.27\u202fPM.png 1948w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.19.27\u202fPM-300x48.png 300w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.19.27\u202fPM-1024x165.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.19.27\u202fPM-768x124.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.19.27\u202fPM-1536x248.png 1536w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.19.27\u202fPM-624x101.png 624w\" sizes=\"(max-width: 1948px) 100vw, 1948px\" \/><p id=\"caption-attachment-70466\" class=\"wp-caption-text\">Startin a activity<\/p><\/div>\n<h3>Update Activity<\/h3>\n<p>We need to send the special push token to our backend to receive live activity updates. After starting the live activity receiving this push token is feasible. The activity instance has an asynchronous sequence <strong>pushTokenUpdates<\/strong>, which emits the push token every time it is updated.<\/p>\n<div id=\"attachment_70472\" style=\"width: 1390px\" class=\"wp-caption aligncenter\"><img aria-describedby=\"caption-attachment-70472\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-70472 size-full\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.23.10\u202fPM.png\" alt=\"Update Token\" width=\"1380\" height=\"468\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.23.10\u202fPM.png 1380w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.23.10\u202fPM-300x102.png 300w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.23.10\u202fPM-1024x347.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.23.10\u202fPM-768x260.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-12.23.10\u202fPM-624x212.png 624w\" sizes=\"(max-width: 1380px) 100vw, 1380px\" \/><p id=\"caption-attachment-70472\" class=\"wp-caption-text\">Update Token<\/p><\/div>\n<p>Once we receive the new push token, we should send it to our backend. It\u2019s important to note that this push token can change during the live activity\u2019s lifecycle, so we need to keep observing the push token updates and send it every time it changes.<\/p>\n<h3>End Activity<\/h3>\n<p>Once our event ends we can easily end that particular live activity by sending an end push notification on the same update token.<\/p>\n<h3>Push notification payloads<\/h3>\n<p>It is important to understand how the whole system works. That\u2019s why we will talk about what should be sent in the request payload to the Apple Push Notification service (APN).<\/p>\n<p>Below, you can see the payload needed to start a live activity (for iOS 17.2).<\/p>\n<ul>\n<li>The event field has a <strong>start<\/strong> value.<\/li>\n<li>The <strong>content-state<\/strong> field should exactly match the <strong>LiveMatchScoreAttributes<\/strong>.<\/li>\n<li>The <strong>attributes-type<\/strong> field defines the type of live activity we would like to start; in our case, it\u2019s <strong>LiveMatchScoreAttributes<\/strong>.<\/li>\n<li>The alert section makes the device highlight like a standard notification. It\u2019s recommended to include it when starting the live activity to grab user attention that new live activity started.<\/li>\n<\/ul>\n<div id=\"attachment_70474\" style=\"width: 635px\" class=\"wp-caption aligncenter\"><img aria-describedby=\"caption-attachment-70474\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-70474 size-large\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.00.54\u202fPM-1024x968.png\" alt=\"Start activity payload\" width=\"625\" height=\"591\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.00.54\u202fPM-1024x968.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.00.54\u202fPM-300x284.png 300w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.00.54\u202fPM-768x726.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.00.54\u202fPM-624x590.png 624w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.00.54\u202fPM-24x24.png 24w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.00.54\u202fPM.png 1030w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-70474\" class=\"wp-caption-text\">Start activity payload<\/p><\/div>\n<p><strong>Below<\/strong>, you can see the payload for updating the live activity.<\/p>\n<ul>\n<li>The event field has an update value.<\/li>\n<li>The vital thing to note is that the timestamp has to change with each new notification. If we keep sending live activity push updates with the same timestamp, the system won\u2019t update live activity.<\/li>\n<li>The <strong>content-state<\/strong> field should exactly match the <strong>LiveMatchScoreAttributes<\/strong>.<\/li>\n<li>There is no need to send attributes representing the static and attributes-type data.<\/li>\n<\/ul>\n<div id=\"attachment_70475\" style=\"width: 804px\" class=\"wp-caption aligncenter\"><img aria-describedby=\"caption-attachment-70475\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-70475 size-full\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.01.47\u202fPM.png\" alt=\"Update Activity Payload\" width=\"794\" height=\"632\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.01.47\u202fPM.png 794w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.01.47\u202fPM-300x239.png 300w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.01.47\u202fPM-768x611.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.01.47\u202fPM-624x497.png 624w\" sizes=\"(max-width: 794px) 100vw, 794px\" \/><p id=\"caption-attachment-70475\" class=\"wp-caption-text\">Update Activity Payload<\/p><\/div>\n<p>&nbsp;<\/p>\n<p><strong>Finally, you can check the payload for ending the live activity here-<\/strong><\/p>\n<ul>\n<li>The field event has an <strong>end<\/strong> value.<\/li>\n<li>The <strong>content-state<\/strong> field contains the final live activity state that will be displayed before ending by the system.The <strong>dismissal-date<\/strong> field defines when the system should remove the live activity. To remove the live activity immediately, the dismissal date value must be in the past. If no date is provided, it will be removed within a 4-hour window. If the provided date is more than 4 hours later, the date will be ignored, and the removal will occur after 4 hours.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<div id=\"attachment_70476\" style=\"width: 798px\" class=\"wp-caption aligncenter\"><img aria-describedby=\"caption-attachment-70476\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-70476 size-full\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.03.03\u202fPM.png\" alt=\"End Activity Payload\" width=\"788\" height=\"816\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.03.03\u202fPM.png 788w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.03.03\u202fPM-290x300.png 290w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.03.03\u202fPM-768x795.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.03.03\u202fPM-624x646.png 624w, \/blog\/wp-ttn-blog\/uploads\/2025\/03\/Screenshot-2025-03-16-at-6.03.03\u202fPM-24x24.png 24w\" sizes=\"(max-width: 788px) 100vw, 788px\" \/><p id=\"caption-attachment-70476\" class=\"wp-caption-text\">End Activity Payload<\/p><\/div>\n<h2>Push notifications headers<\/h2>\n<p>To identify the push notification request as a live activity, it must include special headers, and the key headers include:<\/p>\n<ul>\n<li><strong>apns-topic:<\/strong> This should be set to &lt;app_bundle_id&gt;.push-type.liveactivity.<\/li>\n<li><strong>apns-push-type:<\/strong> Set this to liveactivity.<\/li>\n<li><strong>apns-priority:<\/strong> This determines the priority of the push notification. To deliver it immediately, set it to 10.<\/li>\n<li><strong>authorization:<\/strong> This is the authorization token for the push notification.<\/li>\n<\/ul>\n<h2>Testing live activity push notifications<\/h2>\n<h3>Note: Make sure notifications are configured properly in your project and Apple certificates. Also, live activity supports Token based notifications.<\/h3>\n<p>All Set. We have set up everything now and we can test push notifications through any notification tester until we have our backend system ready.<\/p>\n<p>Let\u2019s look at those fields and give them the proper values:<\/p>\n<ul>\n<li><strong>Device Token<\/strong> \u2013 This is the push token we get when observing push token updates, it was described earlier.<\/li>\n<li><strong>bundle id<\/strong> \u2013 This field should be the application bundle id. (bundleid.push-type.liveactivity)<\/li>\n<li><strong>apns-push-type<\/strong> \u2013 This should be set to live activity.<\/li>\n<li><strong>apns-push-priority<\/strong> \u2013 This determines the priority of the push notifications, it\u2019s better to set it to high to ensure the push notification is delivered immediately.<\/li>\n<li><strong>payload<\/strong> \u2013 In this text field we should just paste the live activity push notification payload with the proper content-state value.<\/li>\n<\/ul>\n<p>Now, press that send button, and let\u2019s see the live activity update in action!<\/p>\n<h2>Conclusion<\/h2>\n<p>For supporting multiple different types of activities, animations and more are still not covered in this. There are lot more to explore. If your activity is up and running then cheers you did a great job. Happy to discuss more possibilities around it.<\/p>\n<p>Source<\/p>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/activitykit\/displaying-live-data-with-live-activities https:\/\/developer.apple.com\/documentation\/activitykit\/starting-and-updating-live-activities-with-activitykit-push-notifications\">https:\/\/developer.apple.com\/documentation\/activitykit\/displaying-live-data-with-live-activities<\/a><\/p>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/activitykit\/starting-and-updating-live-activities-with-activitykit-push-notifications\">https:\/\/developer.apple.com\/documentation\/activitykit\/starting-and-updating-live-activities-with-activitykit-push-notifications<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction In Part 1 we learned about how to set up live activities from scratch. We learned about how to set up, design, and implement live activities for different modes of the iPhone including Lock Screen and Dynamic Island. We learned about the life cycle of activity from the app. How to start, update, and [&hellip;]<\/p>\n","protected":false},"author":1783,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":156},"categories":[1400],"tags":[7157],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/70467"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1783"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=70467"}],"version-history":[{"count":6,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/70467\/revisions"}],"predecessor-version":[{"id":70662,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/70467\/revisions\/70662"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=70467"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=70467"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=70467"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}