-
public class AegisPushTrackerPush lifecycle tracker for Android. Parity port of libs/web-sdk/src/push/AegisWebPush.ts
createBuiltinEventTracker(web SDK ≥1.12.0).Posts
push.delivered/push.clicked/push.dismissed(plus the web-onlypush.permission_denied/subscribed/resubscribed— unused on Android but kept symmetric in the API surface) toPOST /v1/push/engagementwith the canonical wire shape pinned by libs/mobile-sdk/tests/drift/push-engagement-payload.json.Token rotations are sent to
POST /v1/devices/register.The class is an
objectbecause the FCM service + click activity + dismiss receiver all live in different processes/components and share state via SharedPreferences.configure()is called once fromAegis.initialize(); thereafter any push-side caller can invoke the track methods without a context-bound singleton.Best-effort — POST failures are logged but never thrown back to the caller (push callbacks must not reject because the analytics POST failed; the OS already showed the notification).
Phase 2 migration note: pre-Phase-2 this object posted to
/v1/devices/push/eventswith a bare-word event_type (delivered,opened,dismissed). Phase 2 (2026-05-27) migrates to the canonical/v1/push/engagementendpoint +push.<event>event_type. The forbidden-path drift guard catches any regression.
-
-
Field Summary
Fields Modifier and Type Field Description private volatile Function2<String, Map<String, Object>, Unit>onLifecycleRelaypublic final static AegisPushTrackerINSTANCE
-
Method Summary
Modifier and Type Method Description final Unitconfigure(Context context, String writeKey, String baseUrl, String propertyId, String organizationId, String anonymousId)Persist tracker configuration. final UnitsetContactId(Context context, String contactId)Update the resolved contact id after a successful identify(). final UnittrackDelivered(Context context, String campaignId, String messageId, Map<String, Object> metadata)final UnittrackClicked(Context context, String campaignId, String messageId, Map<String, Object> metadata)final UnittrackDismissed(Context context, String campaignId, String messageId, Map<String, Object> metadata)final UnittrackSilentAck(Context context, String campaignId, String messageId, Map<String, Object> metadata)SDK_PUSH_INAPP_PARITY_TRACKER P7 — silent uninstall-probe ack. final UnitreRegisterToken(Context context, String token)Re-register the FCM device token after Firebase rotates it. final UnitdeactivateToken(Context context, String token, String reason)SDK_PUSH_INAPP_PARITY_TRACKER P4 — Dead-token recovery. final Function2<String, Map<String, Object>, Unit>getOnLifecycleRelay()ADDITIVE relay hook for the React Native bridge ( AegisPushModule.kt).final UnitsetOnLifecycleRelay(Function2<String, Map<String, Object>, Unit> onLifecycleRelay)ADDITIVE relay hook for the React Native bridge ( AegisPushModule.kt).-
-
Method Detail
-
configure
final Unit configure(Context context, String writeKey, String baseUrl, String propertyId, String organizationId, String anonymousId)
Persist tracker configuration. Called from
Aegis.initialize(). Idempotent.
-
setContactId
final Unit setContactId(Context context, String contactId)
Update the resolved contact id after a successful identify().
-
trackDelivered
final Unit trackDelivered(Context context, String campaignId, String messageId, Map<String, Object> metadata)
-
trackClicked
final Unit trackClicked(Context context, String campaignId, String messageId, Map<String, Object> metadata)
-
trackDismissed
final Unit trackDismissed(Context context, String campaignId, String messageId, Map<String, Object> metadata)
-
trackSilentAck
final Unit trackSilentAck(Context context, String campaignId, String messageId, Map<String, Object> metadata)
SDK_PUSH_INAPP_PARITY_TRACKER P7 — silent uninstall-probe ack.
Server periodically sends silent probe pushes (data-only with
aegis_silent_probe=1). On receipt we POST backpush.silent_ackto /v1/push/engagement. Absence of acks after N probes is what marks the token as uninstalled server-side (CleverTap pattern).
-
reRegisterToken
final Unit reRegisterToken(Context context, String token)
Re-register the FCM device token after Firebase rotates it. Without this hook the server keeps sending to the stale token and incrementing
bounce_countuntil the token is forced inactive.
-
deactivateToken
final Unit deactivateToken(Context context, String token, String reason)
SDK_PUSH_INAPP_PARITY_TRACKER P4 — Dead-token recovery.
Call when FCM returns INVALID_ARGUMENT / UNREGISTERED / NOT_REGISTERED (token is no longer valid). Posts to /v1/devices/deactivate so the server can flip device_tokens.is_active=false + soft-quarantine for 7 days. The next reRegisterToken with a fresh token reactivates.
Web SDK's equivalent (404/410 → web_push_subscriptions.expired) has been live since DLR_ATTRIBUTION; this closes the mobile gap.
-
getOnLifecycleRelay
final Function2<String, Map<String, Object>, Unit> getOnLifecycleRelay()
ADDITIVE relay hook for the React Native bridge (
AegisPushModule.kt).The FCM service / click activity / dismiss receiver already POST engagement directly via this object's
trackXmethods — that behavior is untouched. This optional callback is a SEPARATE, side-effect-free relay channel: when set (the RN bridge sets it instartPush), those three sites ALSO invoke it so the bridge can re-emit the same lifecycle moments to JS viaRCTDeviceEventEmitter.IMPORTANT: this relay must NOT POST anything. On React Native the JS facade (
src/AegisPush.ts) owns the engagement POST; to avoid double-counting, the RN host should rely on EITHER the native auto-POST (this object'strackX) OR the JS facade POST, never both. The relay only carries the event up to JS; it does not duplicate the network call.Event names match the bridge's emitted events:
aegis.token_refresh{ token }aegis.push_delivered{ campaign_id, message_id, metadata? }aegis.push_clicked{ campaign_id, message_id, action_url?, action_id?, metadata? }aegis.push_dismissed{ campaign_id, message_id, metadata? }
-
setOnLifecycleRelay
final Unit setOnLifecycleRelay(Function2<String, Map<String, Object>, Unit> onLifecycleRelay)
ADDITIVE relay hook for the React Native bridge (
AegisPushModule.kt).The FCM service / click activity / dismiss receiver already POST engagement directly via this object's
trackXmethods — that behavior is untouched. This optional callback is a SEPARATE, side-effect-free relay channel: when set (the RN bridge sets it instartPush), those three sites ALSO invoke it so the bridge can re-emit the same lifecycle moments to JS viaRCTDeviceEventEmitter.IMPORTANT: this relay must NOT POST anything. On React Native the JS facade (
src/AegisPush.ts) owns the engagement POST; to avoid double-counting, the RN host should rely on EITHER the native auto-POST (this object'strackX) OR the JS facade POST, never both. The relay only carries the event up to JS; it does not duplicate the network call.Event names match the bridge's emitted events:
aegis.token_refresh{ token }aegis.push_delivered{ campaign_id, message_id, metadata? }aegis.push_clicked{ campaign_id, message_id, action_url?, action_id?, metadata? }aegis.push_dismissed{ campaign_id, message_id, metadata? }
-
-
-
-