Open
Conversation
Sources/SuperwallKit/Analytics/Superwall Placement/SuperwallEventObjc.swift
Outdated
Show resolved
Hide resolved
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
attribution_matchevent and write sharedacquisition_*user attributesChecklist
CHANGELOG.mdfor any breaking changes, enhancements, or bug fixes.swiftlintin the main directory and fixed any issues.Greptile Summary
This PR adds full install attribution matching support to the iOS SDK. It introduces two parallel attribution paths — Apple Search Ads (via the existing
AttributionPoster) and a new MMP fingerprinting flow — and emits a typedattribution_matchevent for both. User attributes withacquisition_*keys are written when a match is found.\n\nKey implementation highlights:\n- ATrackingPermissionMMPRetryGateactor serializes the post-ATT retry, preventing duplicate in-flight requests when both thesuperwallTrackingPermissionGrantednotification andapplicationDidBecomeActivefire in quick succession.\n- Three new persistent cache flags drive eligibility, completion, and ATT-retry state, with a 7-day attribution window check.\n- Prior review concerns (stray compile error inEndpoint.swift,debugPrintlint violations,rawStringcomparison fragility,attributionMatchObjC enum ordering) are all resolved in this revision.\n\nRemaining items to consider:\n-shouldAttemptTrackingPermissionMMPInstallAttributionMatchdoes not checkDidCompleteMMPInstallAttributionRequest, so the ATT-retry fires even when the initial match already succeeded. This may be intentional (to upgrade a confidence-less match with the now-available IDFA), but it is undocumented.\n- The newscreenWidth,screenHeight, anddevicePixelRatioproperties inDeviceHelperaccessUIScreen.mainwithout the#if os(visionOS)guard that the existinginterfaceStyleproperty uses.Confidence Score: 4/5
Safe to merge after clarifying the intentionality of the post-ATT retry firing even when the initial match succeeded.
All prior P0/P1 issues from earlier review rounds are resolved. The one remaining P1 flag (shouldAttemptTrackingPermissionMMPInstallAttributionMatch not gating on DidCompleteMMPInstallAttributionRequest) either reflects intentional product design or is a logic gap — a comment or small guard would close it. The UIScreen.main visionOS concern is P2. No data-loss, auth, or crash risks remain.
Sources/SuperwallKit/Storage/Storage.swift (shouldAttemptTrackingPermissionMMPInstallAttributionMatch eligibility logic), Sources/SuperwallKit/Network/Device Helper/DeviceHelper.swift (UIScreen.main visionOS guards)
Important Files Changed
Sequence Diagram
sequenceDiagram participant App participant Superwall participant Storage participant Network participant ATTHandler App->>Superwall: configure() Superwall->>Storage: hasTrackedAppInstall() Superwall->>Storage: recordAppInstall() Superwall->>Superwall: await configureIdentity Superwall->>Storage: shouldAttemptInitialMMPInstallAttributionMatch() Storage-->>Superwall: true (new install or prior failure) Superwall->>Storage: recordMMPInstallAttributionMatch { matchMMPInstall } Note over Storage: starts background Task Storage->>Network: matchMMPInstall(idfa, advertiserTracking) Network-->>Storage: true/false Storage->>Storage: save DidCompleteMMPInstallAttributionRequest (if true) Superwall->>Superwall: await fetchConfig ATTHandler->>Superwall: superwallTrackingPermissionGranted / appDidBecomeActive Superwall->>Superwall: retryMMPInstallAttributionMatchAfterTrackingPermissionIfNeeded Superwall->>Superwall: await trackingPermissionMMPRetryGate.tryBegin() Superwall->>Storage: shouldAttemptTrackingPermissionMMPInstallAttributionMatch() Storage-->>Superwall: true (eligible, window open, not yet retried) Superwall->>Network: matchMMPInstall(idfa with ATT, ...) Network-->>Superwall: true/false Superwall->>Storage: save DidCompleteMMPInstallAttributionRequestAfterTrackingPermission (if true) Superwall->>Superwall: trackingPermissionMMPRetryGate.finish()Comments Outside Diff (3)
Sources/SuperwallKit/Network/Network.swift, line 592-596 (link)info: ["payload": request]passes the fullMMPMatchRequeststruct, which includesidfa,idfv, anddeviceId, into the structured log on every failed/api/matchcall. Once the user grants ATT — exactly when the retry fires — a real IDFA will appear in crash/debug logs captured by any connected logging tool.The existing
sendTokenfailure already follows this same pattern (info: ["payload": token]), so this isn't unique to the new code, but it's worth flagging as the IDFA is a more sensitive identifier than an AdServices token. Consider redacting or omitting the identifier fields from the error payload:Prompt To Fix With AI
Sources/SuperwallKit/Network/Network.swift, line 587-588 (link)matchMMPInstallreturnstrueeven on server-side "no match"matchMMPInstallreturnstruewhenever the HTTP request succeeds (regardless of whetherresponse.matchedistrueorfalse), andfalseonly on a network error. This causesDidCompleteMMPInstallAttributionMatchto be saved even when the server returnsmatched: falsewith no attribution, which permanently prevents the initial match path from retrying on future launches.The tracking-permission retry path (
shouldAttemptTrackingPermissionMMPInstallAttributionMatch) uses a different gate (IsEligibleForMMPInstallAttributionMatch) and will still fire correctly after ATT is granted — so the retry does work. The namingdidCompleteMatchand the stored flagDidCompleteMMPInstallAttributionMatchare ambiguous because they conflate "HTTP request completed" with "attribution was found."Consider renaming the return value and the flag to
DidCompleteMMPInstallAttributionRequestto make the intent explicit, or leaving a comment at thereturn truesite clarifying that success here means "request processed; no need to retry the initial path."Prompt To Fix With AI
Sources/SuperwallKit/Storage/Storage.swift, line 716-731 (link)shouldAttemptInitialMMPInstallAttributionMatchskips only when BOTH conditions are trueThe early-exit guard is:
This means a fresh install (
hadTrackedAppInstallBeforeConfigure == false) will always fall through to check the attribution window — even ifDidCompleteMMPInstallAttributionMatchwas somehow already persisted (e.g. from a previous install that wasn't fully cleaned up). In that edge case, an extra MMP request is fired unnecessarily.A more defensive guard would check
didCompleteMatchindependently ofhadTrackedAppInstallBeforeConfigure:The
hadTrackedAppInstallBeforeConfigure == falsepath always hasdidCompleteMatch == falsein practice, so removing the conjunction doesn't change real-world behavior while making the intent clearer.Prompt To Fix With AI
Prompt To Fix All With AI
Reviews (8): Last reviewed commit: "Bugfix for sdk upgraders" | Re-trigger Greptile