Skip to content

fix: [SDK-4757] recover startup when initialized before UIApplicationMain#1677

Open
nan-li wants to merge 5 commits into
mainfrom
nan/sdk-4757
Open

fix: [SDK-4757] recover startup when initialized before UIApplicationMain#1677
nan-li wants to merge 5 commits into
mainfrom
nan/sdk-4757

Conversation

@nan-li

@nan-li nan-li commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Description

One Line Summary

Fix anonymous user creation when OneSignal initializes from SwiftUI App.init() before UIApplicationMain exists.

Details

Motivation

OneSignal iOS SDK 5.5.2 could permanently gate startup on clean installs when initialized from a pure SwiftUI App.init(). In that lifecycle, UIApplication.sharedApplication is nil before UIApplicationMain; the previous protected-data readiness check silently treated that as false, deferred the user manager/session startup, and could wait forever for a protected-data notification that never fires on an already-unlocked device. The result was no anonymous user or push subscription creation.

Scope

This change is limited to SDK startup readiness around protected-data availability. It explicitly handles pre-UIApplicationMain initialization, distinguishes actual iOS prewarm using ActivePrewarm, and adds lifecycle-based recovery once UIApplication exists and reports protected data is available. It does not change public APIs.

Other

The branch history intentionally includes a temporary demo repro commit followed by a restore commit, so reviewers can check out the repro state if needed. The net PR diff only changes iOS_SDK/OneSignalSDK/Source/OneSignal.m.

Testing

Unit testing

No new unit tests were added for the UIKit/SwiftUI launch-order path.

Manual testing

Manually verified on an iOS 26.5 iPhone 17 Pro simulator:

  • Reproduced the issue by initializing the demo app from SwiftUI App.init(): before the fix, UIApplication.sharedApplication was nil, startup stayed gated, and OSRequestCreateUser did not fire.
  • Verified the fixed SwiftUI-init repro: ActivePrewarm=0 was treated as readable, OSRequestCreateUser returned 201, and an onesignal_id was hydrated.
  • Verified the normal AppDelegate-based demo path still creates the user normally.
  • Verified deferred recovery by preserving onesignal_identity.json while removing UserDefaults-backed state, then relaunching and observing the lifecycle recovery path start deferred OneSignal components and send OSRequestCreateUser.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

Made with Cursor

nan-li and others added 5 commits June 12, 2026 12:08
Temporarily remove the demo's AppDelegate and call OneSignal.initialize
from the SwiftUI App initializer, before UIApplicationMain runs. On a
clean install this reproduces the 5.5.2 regression: no
OSRequestCreateUser is ever sent, so no anonymous user or push
subscription is created.

Reverted at the end of this branch; kept in history for reference.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tionMain

ComputeInitialStorageReadable read
UIApplication.sharedApplication.isProtectedDataAvailable, which messages
nil before UIApplicationMain has run (e.g. SwiftUI App.init()) and
silently returns NO. On a fresh install the storage-readiness latch
therefore seeded NO and every gated component (user manager, operation
repo, session) no-opped. Because the device is never locked in this
flow, UIApplicationProtectedDataDidBecomeAvailable never posts, so the
SDK stayed gated forever and OSRequestCreateUser was never sent.

Handle nil sharedApplication explicitly: a user-initiated launch implies
the device is unlocked, so storage is readable. Only a prewarm-created
process can reach this point while storage may still be locked, and iOS
marks those with the ActivePrewarm environment variable, so defer only
in that case. The variable is cleared after launch completes, but
pre-UIApplicationMain always precedes that, so the read is reliable.

Co-authored-by: Cursor <cursoragent@cursor.com>
When init defers because storage is not yet readable, recovery
previously hinged solely on UIApplicationProtectedDataDidBecomeAvailable,
which only posts on a lock-to-unlock transition. If storage was
readable all along — a prewarm-created process the user later
foregrounds, or a prior-session sentinel present while UserDefaults
content was lost — the notification never posts and the deferral is
permanent.

Also observe didFinishLaunching and didBecomeActive: once
UIApplicationMain has run, sharedApplication exists, so consult the
real isProtectedDataAvailable and run the same once-only recovery
(start user manager, resend push token, start Live Activities and IAM,
new session). The live re-check keeps background launches before first
unlock deferred until the unlock notification posts, as before.

Co-authored-by: Cursor <cursoragent@cursor.com>
Undo the temporary SwiftUI App.init() repro setup now that the fix is in
place; the demo initializes OneSignal from
application(_:didFinishLaunchingWithOptions:) again, matching main.

Co-authored-by: Cursor <cursoragent@cursor.com>
@nan-li nan-li marked this pull request as ready for review June 15, 2026 16:46
@nan-li nan-li requested a review from a team June 15, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants