Skip to content

Commit 7b6b110

Browse files
author
WarpLink
committed
feat: implement deferred deep link resolution
1 parent d1d2c94 commit 7b6b110

1 file changed

Lines changed: 148 additions & 0 deletions

File tree

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package app.warplink.internal
2+
3+
import app.warplink.MatchType
4+
import app.warplink.WarpLink
5+
import app.warplink.WarpLinkDeepLink
6+
7+
internal fun performDeferredCheck(
8+
storage: Storage,
9+
fingerprintCollector: FingerprintCollector,
10+
apiClient: ApiClient,
11+
installReferrerReader: InstallReferrerReader?,
12+
logger: Logger?,
13+
callback: (Result<WarpLinkDeepLink?>) -> Unit
14+
) {
15+
if (!storage.isFirstLaunch) {
16+
val cached = storage.cachedAttribution
17+
logger?.log(
18+
"Not first launch, returning cached attribution"
19+
)
20+
callback(Result.success(cached))
21+
return
22+
}
23+
24+
storage.isFirstLaunch = false
25+
26+
if (installReferrerReader != null) {
27+
logger?.log("First launch — trying Play Install Referrer")
28+
tryReferrerThenFallback(
29+
installReferrerReader, fingerprintCollector,
30+
apiClient, storage, logger, callback
31+
)
32+
} else {
33+
logger?.log("First launch — collecting device signals")
34+
collectAndMatch(
35+
fingerprintCollector, apiClient,
36+
storage, logger, callback
37+
)
38+
}
39+
}
40+
41+
private fun tryReferrerThenFallback(
42+
reader: InstallReferrerReader,
43+
fingerprintCollector: FingerprintCollector,
44+
apiClient: ApiClient,
45+
storage: Storage,
46+
logger: Logger?,
47+
callback: (Result<WarpLinkDeepLink?>) -> Unit
48+
) {
49+
reader.readReferrer { referrerResult ->
50+
val linkId = referrerResult.getOrNull()
51+
if (linkId != null) {
52+
logger?.log("Referrer found: $linkId")
53+
matchWithReferrer(
54+
linkId, apiClient, storage, logger, callback
55+
)
56+
} else {
57+
logger?.log(
58+
"No WarpLink referrer, falling back to fingerprint"
59+
)
60+
collectAndMatch(
61+
fingerprintCollector, apiClient,
62+
storage, logger, callback
63+
)
64+
}
65+
}
66+
}
67+
68+
private fun matchWithReferrer(
69+
linkId: String,
70+
apiClient: ApiClient,
71+
storage: Storage,
72+
logger: Logger?,
73+
callback: (Result<WarpLinkDeepLink?>) -> Unit
74+
) {
75+
apiClient.matchAttribution(
76+
null, WarpLink.SDK_VERSION, null, referrer = linkId
77+
) { attrResult ->
78+
attrResult.onFailure { callback(Result.failure(it)) }
79+
attrResult.onSuccess { response ->
80+
handleAttributionResponse(
81+
response, storage, logger, callback
82+
)
83+
}
84+
}
85+
}
86+
87+
private fun collectAndMatch(
88+
fingerprintCollector: FingerprintCollector,
89+
apiClient: ApiClient,
90+
storage: Storage,
91+
logger: Logger?,
92+
callback: (Result<WarpLinkDeepLink?>) -> Unit
93+
) {
94+
fingerprintCollector.collectFingerprint { signalResult ->
95+
signalResult.onFailure { error ->
96+
callback(Result.failure(error))
97+
return@collectFingerprint
98+
}
99+
signalResult.onSuccess { signals ->
100+
apiClient.matchAttribution(
101+
signals, WarpLink.SDK_VERSION, null
102+
) { attrResult ->
103+
attrResult.onFailure { error ->
104+
callback(Result.failure(error))
105+
}
106+
attrResult.onSuccess { response ->
107+
handleAttributionResponse(
108+
response, storage, logger, callback
109+
)
110+
}
111+
}
112+
}
113+
}
114+
}
115+
116+
private fun handleAttributionResponse(
117+
response: AttributionResponse,
118+
storage: Storage,
119+
logger: Logger?,
120+
callback: (Result<WarpLinkDeepLink?>) -> Unit
121+
) {
122+
if (!response.matched ||
123+
response.linkId == null ||
124+
response.destinationUrl == null
125+
) {
126+
callback(Result.success(null))
127+
return
128+
}
129+
val matchType = when (response.matchType?.lowercase()) {
130+
"deterministic" -> MatchType.DETERMINISTIC
131+
"probabilistic" -> MatchType.PROBABILISTIC
132+
else -> null
133+
}
134+
val deepLink = WarpLinkDeepLink(
135+
linkId = response.linkId,
136+
destination = response.destinationUrl,
137+
deepLinkUrl = response.deepLinkUrl,
138+
customParams = response.customParams ?: emptyMap(),
139+
isDeferred = true,
140+
matchType = matchType,
141+
matchConfidence = response.matchConfidence
142+
)
143+
storage.cachedAttribution = deepLink
144+
logger?.log(
145+
"Deferred deep link matched: ${response.linkId}"
146+
)
147+
callback(Result.success(deepLink))
148+
}

0 commit comments

Comments
 (0)