Repository navigation
Conversation
The demo's Identity Verification controls now follow one contract shared with the Android demo. - The JWT invalidated listener lived on the view model. AppDelegate now registers it right after init, since the SDK doesn't replay the event. It hands each event to an app-wide JwtAskStore that the view model mirrors into jwtAskExternalId. The stored token stays, since the SDK fires the same event when requests park without a token. - An invalidation for any user cleared the one stored token, and an A to B to A switch lost A's. The demo now keeps a token per external id. A login with a token or updateUserJwt stores it, and logout clears them all. - The REST fetch row kept the previous user's result after a switch or logout, and a fetch for the old user could land afterwards and write the old external id back. A switch or logout now bumps requestSequence and resets the row, and a skipped fetch resets it too. - The Update User JWT dialog laid the id and a several-hundred-character token side by side and confirmed with "Add". UpdateJwtDialog stacks them full width and confirms with "Update". AddItemType loses its updateUserJwt case and AddItemDialog its initialKey. - build.md gains an Identity Verification controls section, including the behavior that still differs because the SDKs differ.
|
Please adds screenshots |
abdulraqeeb33
left a comment
There was a problem hiding this comment.
The token map and not clearing a token on invalidation match Android. The simulator failure is FileLogStoreRecordDatingTests, which this diff does not touch.
|
|
||
| if useIdentityVerification { | ||
| guard let externalId = externalUserId ?? service.externalId, !externalId.isEmpty else { | ||
| userFetchStatus = nil |
There was a problem hiding this comment.
The missing-id returns clear userFetchStatus and return before requestSequence increments, so an in-flight fetch still writes the row. Bump the sequence first, the way Android does. Same at the onesignal-id guard below.
| - **Stored tokens.** `PreferencesService` keeps every JWT the tester hands the SDK, keyed by external id, as a dictionary under `onesignal.demo.jwtTokens`. A login with a token or an `updateUserJwt` stores it for that id, whoever it is for. A login with the field blank changes nothing, and neither does an invalidation event. Logout clears them all. Plaintext UserDefaults is fine for a demo and not a pattern for real apps. | ||
| - **JWT field in `LoginUserDialog`** (`login_user_jwt_input`). Optional. A same-user login refetches, because the SDK fires no user-state event for it. | ||
| - **UPDATE USER JWT button** (`update_user_jwt_button`). Always enabled. Opens `UpdateJwtDialog`, which stacks the External User Id and JWT Token fields full width, prefills the id from the pending ask and then the current user, and confirms with `Update`. Calls `OneSignal.updateUserJwt` and refetches when the id is the current user's. | ||
| - **JWT ask banner** (`jwt_ask_banner`, with `jwt_ask_external_id_value` and `jwt_ask_provide_button`). `AppDelegate` registers `JwtInvalidatedHandler` right after init, because the SDK doesn't replay the event. The handler hands the asked id to `JwtAskStore`. It leaves the stored token alone, because the SDK also fires this event when requests park without a token, so the event doesn't prove the token is bad. A bad token shows up as a 401 in the REST fetch row. `OneSignalViewModel.jwtAskExternalId` mirrors it, and `UserSection` shows the banner plus a toast once per ask. A token for that id, from `updateUserJwt` or a login, clears the ask, and so does logout. The demo never answers the ask with a stored token on its own. PROVIDE JWT is always enabled. |
There was a problem hiding this comment.
UserSection only toasts from onChange(of: jwtAskExternalId), which does not run for a value already set when the section appears. A launch ask that lands in JwtAskStore first shows the banner and skips the toast.
| // Initialize OneSignal | ||
| OneSignalService.shared.initialize(launchOptions: launchOptions) | ||
|
|
||
| // Here rather than in the view model. The SDK doesn't replay this event, so a |
There was a problem hiding this comment.
The SDK does replay pending JWT asks from addUserJwtInvalidatedListener. The same claim is on JwtAskStore and in build.md. Registering in AppDelegate is still right. Drop the "does not replay" sentence.
|
can we remove fetch row, doesn't seem that useful |
Description
One Line Summary
Make the demo's Identity Verification controls behave the same as the Android demo (OneSignal/OneSignal-Android-SDK#2784).
Details
Motivation
A review of both demos found that their JWT controls behaved differently, and found bugs. The REST fetch row kept the previous user's
OKafter a switch or logout. A late fetch could bring back the previous user. The demo stored a single token, so any invalidation or some user switches lost it. The Update User JWT dialog squeezed a long token into a half-width field.Scope
❗️Demo app only. No SDK changes.
AppDelegateat launch and feeds an app-wideJwtAskStore. The banner and toast are unchanged.UpdateJwtDialogstacks its fields and confirms with "Update".build.mddocuments the controls and the remaining SDK differences.No new Swift files, so
project.pbxprojis unchanged.Testing
Unit testing
None. Demo UI only.
Manual testing
Ran 13 scenarios on an iPhone 17 Pro simulator against a test app with Identity Verification on. They covered login with and without a token, user switches, expired tokens, PROVIDE JWT, and logout. All behaved as expected.
Screenshots
iOS on the left, Android on the right, both demos on an app with Identity Verification on.
alicewith an expired token. The REST fetch row shows the 401 and the banner names the user the SDK is waiting on. Android also shows the snackbar.Affected code checklist
Checklist
Overview
Testing
Final pass
🤖 Generated with Claude Code