chore(live-notifications): update events, local update API, asset management, typed config#765
Draft
mahmoud-elmorabea wants to merge 19 commits into
Draft
Conversation
Replace the bespoke /v1/live_activities REST client with two CDP track events per the SDK→CDP contract: - "Live Notification" eventType=start (local start via public API) - "Live Notification" eventType=end (user dismissal) - "Live Notification Token" registrationType=push_to_start (per enabled type) All contract fields ride under `properties` (the Segment track envelope is fixed; the edge reads them there). `deviceId` is the FCM token and doubles as `pushToStartToken`; `instanceUUID` is the client-generated activity id. Events are gated on an identified user (auth-only). The instance-token flow is dropped — Android has no per-instance push token. The dismiss receiver now carries instanceUUID + activityType on the delete PendingIntent and reads the FCM token to emit `end`. Retry/flush is handled by the data pipeline, so the HTTP client, backoff and instance registration are removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…le UI Add a public ModuleMessagingPushFCM.registerLiveNotificationToken(activityType) that registers a single type's push-to-start token on demand, on top of the automatic registration of every enabled type at login / token change. Harden the auto-registration: registerAll now retries (serialized via a mutex) so it survives the brief window where the pipeline's identified state lags the UserChangedEvent that triggered it — previously a racy pass during identify left several types unregistered with no retry. Sample (java_layout): add a "Register Push-to-Start Token" section to the live notification demo — a dropdown of all supported types + an on-demand register button with a result snackbar. The login flow already enables (and thus auto-registers) all supported types via setLiveNotificationTypes. Verified on emulator: login registers all 7 enabled types; the on-demand button emits one register_push_to_start for the selected type. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…CDP events The edge/action-destination contract renamed the live-activity type property to `notificationType` (live activity → live notification rename). The SDK was still emitting `properties.activityType`, so the edge resolved an empty type and dropped it. Switch the wire key to `notificationType` for all three ops (start, end, push_to_start); the Android-facing API parameter names keep the `activityType` domain term. Verified on emulator: push_to_start now sends `properties.notificationType=io.customer.liveactivities.*`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…has no content
A push whose template fields never reached the render `data` (content not
flattened at the envelope top level, or empty) was still posting a notification
— the templates emit placeholder text ("Order #", " · $"), so the result looked
empty rather than being rejected.
Templates now return null when they have no usable content, and the handler logs
an error and skips posting instead of showing a blank notification. Envelope/
ordering handler tests get a minimal statusMessage so they still post; added
explicit guard tests (template returns null + handler doesn't notify).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…drop on-demand register API - Rename MessagingPushModuleConfig.Builder.setLiveNotificationTypes → enableLiveNotificationTypes: the method gates the whole feature, so "enable" reads clearer than a plain setter. - Remove the public ModuleMessagingPushFCM.registerLiveNotificationToken API and the registrar's on-demand register(): push-to-start registration is already fully automatic (every enabled type registers when the user/token changes), so a manual single-type API was redundant. Enabling a type is the single path. - Drop the sample's "Register Push-to-Start Token" dropdown/button section. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pshot The snapshot version is branch-named and mutable (<branch>-SNAPSHOT), so Gradle's changing-module cache can shadow a freshly published snapshot with a stale copy from a previous commit. This made sample release builds compile against an old SDK whenever a public API the sample uses was renamed/added (e.g. setLiveNotificationTypes -> enableLiveNotificationTypes). Force --refresh-dependencies so the sample resolves the snapshot published from the current commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…er extras, revert CI workflow - Registrar: registration is a CDP track event, so the data pipeline owns batching/retry/delivery — drop the SDK-side retry loop (coroutine scope, mutex, attempt/backoff). Emit synchronously on token/user change, deduped per token|userId signature. - Stop clearing stored registration signatures on device-token delete: the routine delete+re-register token cycle on identify was re-sending every registration on each app launch. Dedup by signature already re-registers when the token or user actually changes. - Make LiveNotificationDismissReceiver.EXTRA_* constants internal — they're only set/read by the SDK and don't belong in the public API. - Revert the snapshot-release.yml --refresh-dependencies change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…key to notification_type
Inbound push handling, to match how the backend delivers live notifications:
- extractData now unwraps template fields nested under a `payload` object
(merged over any flattened top-level fields), so a push that delivers content
as `payload={...}` renders instead of being dropped as "no usable content".
Local-start's flattened shape still works.
- Rename the inbound envelope type key `activity_type` -> `notification_type`
(internal LiveNotificationHandler.NOTIFICATION_TYPE_KEY; no public API change),
plus the sample's push-simulation bundle and custom-render callback key.
Verified on a physical device: a deliveryTracking push with `notification_type`
+ nested `payload` renders on the live channel (title "Order #…", progress).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…I, asset management, typed config
- Emit `update` lifecycle events (start/update/end); report only on-device-initiated changes
- Add updateLiveNotification API mirroring local start
- Match iOS asset-management behavior + load image URLs; branding logoAssetKey large-icon fallback
- Typed enableLiveNotificationTypes(enum) + enableCustomLiveNotificationTypes + registerLiveNotificationAsset
- LiveScore renders a team/league logo natively via the single large-icon slot
- Align lifecycle event name with the CDP contract ("Live Notification Event")
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sample app builds 📱Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## feature/live-notifications #765 +/- ##
================================================================
+ Coverage 66.80% 67.65% +0.85%
- Complexity 1041 1087 +46
================================================================
Files 177 180 +3
Lines 5711 5911 +200
Branches 786 829 +43
================================================================
+ Hits 3815 3999 +184
+ Misses 1607 1585 -22
- Partials 289 327 +38 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
📏 SDK Binary Size Comparison Report
|
|
|
Build available to test |
…/update API - Regenerate messagingpush.api for the new public surface (typed enable + custom types, registerLiveNotificationAsset, updateLiveNotification, LiveNotificationAsset, branding logoAssetKey, LiveNotificationType enum) - java_layout demo start/update API buttons now use the typed LiveNotificationData overloads Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
- Host can programmatically end a live notification it started; only the activityId is needed — the SDK records the activity type at render time and uses it for the (payload-less) `end` event - Store activityId -> type in LiveNotificationStore (cleared on end + TTL trim); share the notification-id derivation with the handler - java_layout demo gets an "End via API" button; regenerate messagingpush.api Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
- On Event.ResetEvent (clearIdentify/logout), cancel every SDK-tracked live notification and clear its stored state, then clear registrations so the next identified user re-registers - No `end` event is emitted (user is being de-identified); mirrors iOS endAllActivities-on-reset behavior - Enumerate tracked activities via LiveNotificationStore (activityId -> type) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
…h iOS parity Rework live notifications to the finalized cross-platform contract and match the iOS SDK's presentation-role field model, wire envelope, and end behavior. Field model & templates - Presentation-role fields (header/title/subtitle/status/statusMessage/…) in LiveNotificationFields; drop SDK-composed strings (no "Order for <id>") - statusColor sent as a styling value; staleMessage rendered as body when present - Rework all 5 templates (LiveScore, DeliveryTracking, CountdownTimer, FlightStatus, AuctionBid) to read the new flat payload fields - Required-field errors logged; optional fields hidden gracefully Wire envelope - LiveNotificationData splits attributes() / contentState() for the local API - Lifecycle client emits attributes + contentState (no payload envelope); attributesType is not sent (iOS-only) Behavior - End no longer force-cancels when no dismissal_date: setOngoing(false) + setAutoCancel(true) so the ended notification stays dismissible (iOS parity) - Backend-initiated (push) end is not echoed as a lifecycle event; user dismissal reports end via LiveNotificationDismissReceiver Tooling & tests - Regenerate messagingpush public-API dump - Update templates/data/lifecycle/manager tests + sample demo screen (232 tests) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
…UUIDv4 The backend expects ULIDs for live notification instance IDs. Replace the locally-minted UUIDv4 with a dependency-free ULID generator: 48-bit ms timestamp + 80-bit SecureRandom randomness, Crockford Base32, 26-char uppercase canonical form. Mirrors the iOS SDK's ULID minting so both platforms share one id format. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
…entify race) On the session where the user identifies, the registrar's UserChangedEvent subscriber could run before the data pipeline's isUserIdentified flag settled (analytics.userId() is a cache updated asynchronously after identify), so every registration was dropped with no retry — the device+user went unregistered until the next app launch. The registrar is now the authoritative identity gate: it registers only while identified, deriving identity from UserChangedEvent.userId (carried synchronously) instead of the laggy pipeline flag. The client no longer re-checks isUserIdentified for the registration event (lifecycle events keep their gate). No delays/polling — attribution stays correct because the analytics store reducer is applied before the registration track is enqueued. Matches the in-app module's UserChangedEvent handling. Adds LiveNotificationRegistrarTest and updates the client gate tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
…iOS + backend Aligns the Android live-notifications contract with the finalized iOS SDK and the Customer.io backend push payload: - Route on `cioInstanceId` instead of `activity_id` (the inbound detection gate and local-start writer), matching the backend envelope and iOS attributes key. - `end` renders the final content-state and leaves it posted for the user to dismiss; the SDK never auto-removes it (dropped the `dismissal_date` scheduling machinery), matching iOS leaving an ended Live Activity on screen. - CDP lifecycle/token events report the instance id under `cioInstanceId`. - Field-model, envelope, timestamp (epoch seconds) and template rendering alignment, including nested delivery-tracking progress. Full :messagingpush:testDebugUnitTest suite passes; apiCheck passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
…eliveryTracking ctor - Reorder PROP_CIO_INSTANCE_ID import in LiveNotificationLifecycleClientTest to satisfy ktlint import-ordering (the CDP-key rename moved its lexicographic position). - Update the java_layout sample's DeliveryTracking construction to the new nested Progress(current, total) constructor (replaced the flat stepCurrent/stepTotal args), fixing the compileReleaseJavaWithJavac break. ktlint clean on the changed file; :samples:java_layout:compileReleaseJavaWithJavac and :messagingpush test sources compile. Co-Authored-By: Claude Opus 4.8 (1M context) <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.
Brings the Android live-notifications feature to parity with iOS and the CDP track contract: adds
updatelifecycle events (reported only for on-device-initiated changes), a localupdateLiveNotificationAPI, iOS-equivalent asset management (registered assets +http(s)image URLs) with a branding large-icon fallback, a typed enable/asset-registration config API, native single-slot logo rendering for LiveScore, and aligns the lifecycle event name with the CDP contract.🤖 Generated with Claude Code