Package 

Object AegisPushTracker


  • 
    public class AegisPushTracker
    
                        

    Push 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-only push.permission_denied / subscribed / resubscribed — unused on Android but kept symmetric in the API surface) to POST /v1/push/engagement with 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 object because the FCM service + click activity + dismiss receiver all live in different processes/components and share state via SharedPreferences. configure() is called once from Aegis.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/events with a bare-word event_type (delivered, opened, dismissed). Phase 2 (2026-05-27) migrates to the canonical /v1/push/engagement endpoint + push.<event> event_type. The forbidden-path drift guard catches any regression.

    • Method Detail

      • 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 back push.silent_ack to /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_count until 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 trackX methods — that behavior is untouched. This optional callback is a SEPARATE, side-effect-free relay channel: when set (the RN bridge sets it in startPush), those three sites ALSO invoke it so the bridge can re-emit the same lifecycle moments to JS via RCTDeviceEventEmitter.

        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's trackX) 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 trackX methods — that behavior is untouched. This optional callback is a SEPARATE, side-effect-free relay channel: when set (the RN bridge sets it in startPush), those three sites ALSO invoke it so the bridge can re-emit the same lifecycle moments to JS via RCTDeviceEventEmitter.

        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's trackX) 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? }