Skip to content

fix: tolerate empty deepLinkData object in InstallResponse - #4

Open
onamfc wants to merge 1 commit into
mainfrom
fix/install-response-empty-deep-link-data
Open

fix: tolerate empty deepLinkData object in InstallResponse#4
onamfc wants to merge 1 commit into
mainfrom
fix/install-response-empty-deep-link-data

Conversation

@onamfc

@onamfc onamfc commented Aug 15, 2026

Copy link
Copy Markdown
Member

Ports the iOS SDK fix (mobile-sdk-ios#4) to Android. The bug was reported against iOS, but Android has the same defect.

Problem

The install endpoint returns deepLinkData: {} rather than null for organic (unattributed) installs:

{
  "installId": "<some_id>",
  "attributed": false,
  "confidenceScore": 0,
  "matchedFactors": [],
  "deepLinkData": {}
}

DeepLinkData.shortCode has no default, so the generated Moshi adapter threw JsonDataException: Required value 'shortCode' missing. That happened while decoding the enclosing InstallResponse, so the whole response failed and initialize() surfaced a LinkFortyError.DecodingError for every organic install — not just the deep link part of it.

Fix

A LenientDeepLinkDataAdapter registered on the network Moshi instance. It reads the value, delegates to the generated adapter, and returns null if the payload isn't a usable deep link — so {}, a non-object, and a short-code-less object all mean "no deep link", the same as null and absent. The failure is logged when debug logging is on rather than propagated, since a deep link the SDK can't parse is never worth aborting attribution over.

Deliberately unchanged:

  • DeepLinkData.shortCode stays non-null. Making it nullable (or defaulting it to "") would be a breaking change for callers that route on it, and a defaulted short code would produce a fake non-null deep link for organic installs — worse than the bug.
  • Top-level fields stay strict. installId, attributed, confidenceScore, and matchedFactors are always returned, and installId is required for the SDK to work at all.
  • Stored deep link data stays strict. The adapter is registered only on NetworkManager's Moshi; StorageManager and AttributionContext decode data the SDK itself wrote.

The adapter lives in com.linkforty.sdk.models, which consumer-rules.pro already keeps in full, so R8 won't strip the reflectively-invoked @FromJson/@ToJson methods.

Fixing this SDK-side rather than only backend-side is what actually unblocks integrators: self-hosted deployments and already-deployed backends will keep sending {}, and the SDK has to survive that.

Tests

New InstallResponseTest covers {}, null, absent, and short-code-less deepLinkData, the attributed path, a missing-installId failure, and encode/decode round trips. A NetworkManagerTest case decodes an organic response end-to-end, so the adapter registration itself is guarded — I verified that test fails without it. Full suite: 146 tests passing, lintDebug clean.

The install endpoint returns `deepLinkData: {}` rather than `null` for
organic (unattributed) installs. `DeepLinkData.shortCode` is required, so
Moshi threw `JsonDataException` and the whole install response failed to
decode, surfacing as a DecodingError out of `initialize()`.

Register a lenient `DeepLinkData` adapter on the network Moshi instance: an
empty object — or any payload without a usable short code — decodes to null
instead of throwing, matching the `null` and absent cases. The failure is
logged when debug logging is on, since a deep link we cannot decode is never
worth aborting attribution over. Required top-level fields stay strict, and
locally stored deep link data (written by the SDK) keeps its strict adapter.

Ports the iOS SDK fix (LinkForty/mobile-sdk-ios#4) to Android.
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.

1 participant