feat: app-lifecycle [android]#29
Closed
choudlet wants to merge 1 commit into
Closed
Conversation
Adds automatic emission of the four application-lifecycle events, gated behind a new `InitOptions.trackLifecycleEvents` flag (default true). Events flow through the existing track() path. Persisted (version, build) state lives in a dedicated SharedPreferences file so it survives reset(). Closes sc-36799.
Collaborator
Author
|
Superseded by stacked PRs #30 (sc-38233), #31 (sc-38234), #32 (sc-38235), #33 (sc-38236). The work has been split per the iOS slicing pattern (parity with sc-36764) and reorganized to incorporate post-PR refinements: Each new PR is reviewable in isolation; merge in numeric order (#30 → #31 → #32 → #33) and they will auto-retarget to |
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
Implements the four application-lifecycle events for the Android SDK (Shortcut sc-36799):
Application Installed— emitted on first launch with no prior(version, build)and no identity storage.Application Updated— emitted on first launch after(version, build)changes, OR when no(version, build)is stored but identity storage already exists (existing user upgrading from a pre-lifecycle SDK build); previous values default to"unknown"in that upgrade case.Application Opened— emitted on cold launch (afterInstalled/Updatedif applicable) withfrom_background:false, and on everybackground → activetransition withfrom_background:true. Skipped when the process is woken in the background (push, JobScheduler, WorkManager) — the next true foreground entry emits the cold-launch-style event instead. Optionalurlandreferring_applicationproperties are populated when the host app calls the newhandleDeepLink(...)method before the next emit.Application Backgrounded— emitted onactive → background, before the existing flush, so it lands in the same drain.All four flow through the existing
track()path (enrichment + dispatcher).Public API
InitOptions.trackLifecycleEvents: Boolean = true— opt-out flag.AnalyticsInterface.handleDeepLink(uri: Uri, sourceApplication: String? = null)— host hook for populating optional deep-link properties on the nextApplication Opened. Buffer is one-shot and cleared after emit.Storage
(version, build)are persisted in a dedicatedSharedPreferencesfile (com.metarouter.analytics.lifecycle) soIdentityManager.reset()andMetaRouterAnalyticsClient.reset()cannot wipe install/update state. Keys:metarouter:lifecycle:version,metarouter:lifecycle:build.Test plan
./gradlew :metarouter-sdk:test— 511 tests, 0 failures (debug + release variants).LifecycleEventTrackerTestcovers all eleven emission rules from the plan: install/update detection, cold-launch foreground vs deferred, dedup against the imminentProcessLifecycleOwner.onStart, multiple background↔foreground cycles,Application Backgroundedempty payload,enabled=falseno-op, and one-shot deep-link buffer.LifecycleStorageTestcovers round-trip, persistence across instances, isolation fromIdentityStorage.clear(), and key-name parity with the cross-platform contract.MetaRouterAnalyticsClientTestintegration cases: cold launch persists(version, build)and enqueues at least theInstalledevent;trackLifecycleEvents=falseproduces zero lifecycle events;client.reset()does NOT clear lifecycle storage.InitOptionsTestcovers default + explicit flag values.Notes for reviewers
AtomicBooleans:suppressNextForeground(set when cold-launch emitsOpened, suppresses imminent observer-drivenonStart) andcoldLaunchOpenedDeferred(set when process started in background, consumed by first true foreground entry).buildis serialized as a string in the wire payload to match the cross-platform schema; stored as a string inLifecycleStorage. (context.app.buildretains its existing numeric Android type — these two fields intentionally diverge.)MetaRouterAnalyticsClientTestsettrackLifecycleEvents = falseso existing assertions onqueueLengthare not affected by the new automatic emission. Lifecycle integration cases re-enable explicitly viaoptions.copy(trackLifecycleEvents = true).