Add iOS Live Activity push support#278
Open
rwarner wants to merge 6 commits intohome-assistant:mainfrom
Open
Conversation
Live Activity push tokens from ActivityKit are direct APNs tokens (hex-encoded), not FCM tokens. The existing iOSV1 endpoint cannot handle them — this adds a dedicated iOSLiveActivityV1 endpoint that sends directly to the APNs HTTP/2 API using JWT authentication, bypassing FCM entirely. New files: - apns.js: APNs HTTP/2 client with ES256 JWT auth (Node built-ins only, no new dependencies). JWT cached and rotated every 45 min. HTTP/2 sessions cached per environment (sandbox/production). - live-activity.js: payload builder for start/update/end events. Maps content_state fields to the HALiveActivityAttributes struct expected by the iOS companion app. Sets apns-push-type: liveactivity and routes to correct APNs topic using bundle ID from registration_info. Updated files: - handlers.js: adds handleLiveActivityRequest(), which validates hex APNs tokens, applies rate limiting, sends via apns.js, and handles BadDeviceToken (400) without error reporting. - index.js: exports iOSLiveActivityV1 Cloud Function. - webapp.js: adds /api/sendPush/iOS/liveActivity/v1 route for local dev. Tests: 20 tests across fixture-driven createPayload tests and handleLiveActivityRequest integration tests covering success, token validation, rate limiting, APNs error mapping, and end-event rate-limit bypass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves createLiveActivityPayload() from the standalone live-activity.js into ios.js as a second export, keeping all iOS-specific logic in one place consistent with the existing android.js/ios.js pattern. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Follows the existing test naming convention (legacy.test.js -> legacy.js) now that the Live Activity payload builder lives in ios.js. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds first-class iOS Live Activity push support by introducing a dedicated endpoint that sends directly to APNs (HTTP/2 + JWT), along with an iOS payload builder and tests/fixtures to validate live-activity payload generation and handler behavior.
Changes:
- Introduces a new
iOSLiveActivityV1endpoint (Cloud Functions export + local Fastify route) backed by a newhandleLiveActivityRequesthandler. - Adds APNs sender module (
apns.js) implementing ES256 JWT generation and HTTP/2 session reuse. - Extends
ios.jswithcreateLiveActivityPayloadand adds fixture-driven + integration tests for Live Activity pushes.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| functions/webapp.js | Adds local Fastify route for the new live-activity endpoint. |
| functions/index.js | Exposes iOSLiveActivityV1 Cloud Function and exports the new handler for tests. |
| functions/handlers.js | Implements handleLiveActivityRequest with APNs token validation + rate limiting + APNs send/error mapping. |
| functions/ios.js | Adds createLiveActivityPayload (APS liveactivity structure + headers/environment). |
| functions/apns.js | New APNs HTTP/2 client module with JWT auth + session caching. |
| functions/test/ios.test.js | Adds fixtures + integration/unit coverage for live-activity payload creation and handler behavior. |
| functions/test/fixtures/live-activity/*.json | Adds fixture inputs/expectations for start/update/end live-activity payload generation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Fix misleading comment in webapp.js (was "Import the functions from index.js") - Validate APNs token length (must be exactly 64 hex chars) in isValidApnsToken; add test - Normalize apnsEnvironment to 'sandbox'|'production' to prevent unbounded session cache growth - Guard JSON.parse in apns.js against non-JSON APNs responses - Fix test: pass body overrides flat to createLiveActivityRequest (not nested under body:) - Add explanatory comments throughout apns.js, ios.js, and handlers.js for non-obvious decisions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rwarner
added a commit
to rwarner/core
that referenced
this pull request
Mar 20, 2026
Add support for iOS Live Activities in the mobile_app integration: - Add `supports_live_activities`, `supports_live_activities_frequent_updates`, `live_activity_push_to_start_token`, and `live_activity_push_to_start_apns_environment` fields to SCHEMA_APP_DATA for explicit validation during device registration - Add `update_live_activity_token` webhook handler: stores per-activity APNs push tokens reported by the iOS companion app when a Live Activity is created locally via ActivityKit - Add `live_activity_dismissed` webhook handler: cleans up stored tokens when a Live Activity ends on the device - Both handlers fire bus events so automations can react to activity lifecycle - Add `supports_live_activities()` utility helper - Add 4 tests covering token storage, default environment, dismissal cleanup, and nonexistent tag dismissal for: home-assistant/mobile-apps-fcm-push#278 for: home-assistant/iOS#4444 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This was referenced Mar 20, 2026
Firebase Admin SDK v13.5.0+ supports the liveActivityToken field in the apns config object, which tells FCM to automatically set apns-push-type: liveactivity and route the notification to APNs. This eliminates the need for a custom direct APNs HTTP/2 client. Changes: - Delete apns.js (custom HTTP/2 + JWT APNs client) — no longer needed - Bump firebase-admin from ^12.1.0 to ^13.5.0 - Rewrite ios.js: createPayload detects live_activity_token in request body and builds FCM payload with apns.liveActivityToken (camelCase) - Remove handleLiveActivityRequest from handlers.js — existing handleRequest + messaging.send() handles everything - Remove iOSLiveActivityV1 endpoint from index.js and webapp.js - Rewrite tests for FCM-based delivery path - Update fixtures to use FCM payload structure The relay server no longer needs APNS_TEAM_ID, APNS_KEY_ID, or APNS_PRIVATE_KEY environment variables. HA core sends both the FCM registration token (push_token) and the Live Activity APNs token (live_activity_token) to the same /api/sendPush/iOS/v1 endpoint. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
firebase-admin v13.5.0+ (required for liveActivityToken) has a peer dependency on firebase-functions v6.1.1+. firebase-functions v6 changes the default export to v2 APIs, so index.js now imports from firebase-functions/v1 to retain functions.config(), functions.region(), and functions.runWith(). Test mocks updated to mock both firebase-functions and firebase-functions/v1 paths. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
rwarner
added a commit
to rwarner/core
that referenced
this pull request
Mar 24, 2026
Add support for iOS Live Activities in the mobile_app integration: - Add `supports_live_activities`, `supports_live_activities_frequent_updates`, `live_activity_push_to_start_token`, and `live_activity_push_to_start_apns_environment` fields to SCHEMA_APP_DATA for explicit validation during device registration - Add `update_live_activity_token` webhook handler: stores per-activity APNs push tokens reported by the iOS companion app when a Live Activity is created locally via ActivityKit - Add `live_activity_dismissed` webhook handler: cleans up stored tokens when a Live Activity ends on the device - Both handlers fire bus events so automations can react to activity lifecycle - Add `supports_live_activities()` utility helper - Add 4 tests covering token storage, default environment, dismissal cleanup, and nonexistent tag dismissal for: home-assistant/mobile-apps-fcm-push#278 for: home-assistant/iOS#4444 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds iOS Live Activity push support using FCM's native
liveActivityTokenfield (Firebase Admin SDK v13.5.0+).When HA core sends a notification with
live_activity_tokenin the request body, the relay server'sios.jspayload builder detects it and constructs an FCM message withapns.liveActivityToken. FCM then automatically setsapns-push-type: liveactivityand routes the notification to Apple's push servers — no custom APNs client, JWT signing, or HTTP/2 session management needed.Changes:
ios.js:createPayloaddetectslive_activity_tokenin the request body and delegates tobuildLiveActivityPayload(), which sets the FCMapns.liveActivityTokenfield with the correctapsstructure for start/update/end eventspackage.json: Bumpsfirebase-adminfrom^12.1.0to^13.5.0(minimum version withliveActivityTokensupport) andfirebase-functionsfrom^5.0.1to^6.1.1(required peer dependency for firebase-admin v13)index.js: Updated import fromfirebase-functionstofirebase-functions/v1— firebase-functions v6 changes the default export to v2 APIs, but the v1 import retainsfunctions.config(),functions.region(), andfunctions.runWith()used by existing Cloud Function definitionshandleRequest, and backward compatibility with normal notificationsNo new files, no new endpoints — Live Activity notifications flow through the existing
/api/sendPush/iOS/v1endpoint alongside normal iOS notifications. TheAPNS_TEAM_ID,APNS_KEY_ID, andAPNS_PRIVATE_KEYenvironment variables are not needed.Test plan
messaging.send()receives correctliveActivityTokenfor: home-assistant/iOS#4444
for: home-assistant/core#166072