fix(deeplink): keep URL parameters on a direct open - #5
Merged
Conversation
A link shared as ?slug=titanic delivered that value to the app after a deferred install but not when the app was already installed. resolveUrl returned the server payload and dropped the local parse — and that payload is the link's stored configuration, which cannot know what was appended to the URL that was tapped. customParameters now carries both, with URL values winning on a collision: the precedence the server already applies on the deferred path. mergingUrlParameters is a copy() touching customParameters alone. linkId, deepLinkPath, appScheme, the store URLs and utmParameters stay server truth; a local parse cannot know them. Also aligns the reserved-name filter with the server's. It excluded the five UTM keys but not fp_ or lf_click, so fingerprint signals and the click-correlation id could reach an app as if the customer had set them — already possible on the resolve-failure path, which returns the local parse directly. The predicate matches on prefix rather than an exact set, so utm_* and fp_* are covered whatever the suffix.
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
A link shared as
?slug=titanicreached the app after a deferred install but not on a direct open. This fixes that, socustomParameterscarries URL parameters on both paths.Fourth of five. React Native is LinkForty/mobile-sdk-react-native#7, Expo is LinkForty/mobile-sdk-expo#6, iOS is LinkForty/mobile-sdk-ios#6; Flutter still to come.
What was happening
resolveUrl(uri, fallback)returned the server payload on success and used the local parse only as a failure fallback — so a successful resolve discarded the parsed URL parameters entirely.That payload is the link's stored configuration. The server cannot know what was appended to the URL that was actually tapped; only the SDK does, having just parsed it.
The value was never lost from the callback — the
Uriis still delivered — but it was absent from the field the deferred path teaches people to read, so the two open types disagreed.The rules it follows
mergingUrlParametersis acopy()touchingcustomParametersalone.linkId,deepLinkPath,appScheme, the store URLs andutmParametersremain server truth.A live leak this also closes
extractCustomParametersexcluded the five UTM keys by exact match but notfp_orlf_click.Those are LinkForty plumbing:
fp_*are fingerprint signals the redirect reads server-side for attribution,lf_clickis the id the redirect appends to a destination URL for downstream analytics. Neither is the customer's data, and the server's extractor excludes both.Not hypothetical — the resolve-failure path already returns the local parse directly, so an app hitting it today can receive
fp_tzandlf_clickinsidecustomParametersas though the customer had set them.The new predicate matches on prefix rather than an exact set, so
utm_*andfp_*are covered whatever the suffix — the previous exact-match set would have missedutm_idorfp_anything. Tests pin the near-misses (utmost,fps,lf_clicks) as not reserved.Confirmed unaffected: the fingerprint is built server-side from the query string, and
lf_clickis consumed on the landing page. Neither readscustomParameters.Verification
./gradlew :sdk:testDebugUnitTest— 144 tests, 0 failures, 0 errors, 0 skippedOne thing worth a look in review
The merge extension initially landed between
@JsonClass(generateAdapter = true)and thedata classit annotates, which would have detached the annotation and broken Moshi's generated adapter. It is now below the class. Worth confirming the generatedDeepLinkDataJsonAdapterstill looks right after a clean build.Part of SIT-429