react-native-cliqit 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +209 -0
- package/android/build.gradle +27 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/com/cliqit/CliqItModule.kt +242 -0
- package/android/src/main/java/com/cliqit/CliqItPackage.kt +14 -0
- package/android/src/main/java/com/cliqit/sdk/CliqItDefaults.kt +17 -0
- package/android/src/main/java/com/cliqit/sdk/CliqItDeviceInfo.kt +196 -0
- package/android/src/main/java/com/cliqit/sdk/CliqItHttp.kt +98 -0
- package/android/src/main/java/com/cliqit/sdk/CliqItModels.kt +130 -0
- package/android/src/main/java/com/cliqit/sdk/CliqItSDK.kt +514 -0
- package/android/src/main/java/com/cliqit/sdk/CliqItWebFingerprint.kt +230 -0
- package/ios/CliqItModule.m +14 -0
- package/ios/CliqItModule.swift +238 -0
- package/ios/Frameworks/CliqIt.xcframework/Info.plist +44 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64/CliqIt.framework/CliqIt +0 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64/CliqIt.framework/Headers/CliqIt-Swift.h +382 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64/CliqIt.framework/Info.plist +0 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64/CliqIt.framework/Modules/CliqIt.swiftmodule/arm64-apple-ios.abi.json +12111 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64/CliqIt.framework/Modules/CliqIt.swiftmodule/arm64-apple-ios.private.swiftinterface +419 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64/CliqIt.framework/Modules/CliqIt.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64/CliqIt.framework/Modules/CliqIt.swiftmodule/arm64-apple-ios.swiftinterface +419 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64/CliqIt.framework/Modules/module.modulemap +3 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/CliqIt +0 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Headers/CliqIt-Swift.h +760 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Info.plist +0 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Modules/CliqIt.swiftmodule/arm64-apple-ios-simulator.abi.json +12111 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Modules/CliqIt.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +419 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Modules/CliqIt.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Modules/CliqIt.swiftmodule/arm64-apple-ios-simulator.swiftinterface +419 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Modules/CliqIt.swiftmodule/x86_64-apple-ios-simulator.abi.json +12111 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Modules/CliqIt.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +419 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Modules/CliqIt.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Modules/CliqIt.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +419 -0
- package/ios/Frameworks/CliqIt.xcframework/ios-arm64_x86_64-simulator/CliqIt.framework/Modules/module.modulemap +3 -0
- package/package.json +48 -0
- package/react-native-cliqit.podspec +27 -0
- package/react-native.config.js +11 -0
- package/src/index.d.ts +92 -0
- package/src/index.js +152 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
package com.cliqit.sdk
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.os.Handler
|
|
6
|
+
import android.os.Looper
|
|
7
|
+
import android.webkit.WebView
|
|
8
|
+
import android.webkit.WebViewClient
|
|
9
|
+
import org.json.JSONObject
|
|
10
|
+
import java.util.concurrent.CountDownLatch
|
|
11
|
+
import java.util.concurrent.TimeUnit
|
|
12
|
+
import java.util.concurrent.atomic.AtomicReference
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Hidden WebView probe — same signals as iOS CliqItWebFingerprintCollector
|
|
16
|
+
* (canvas / WebGL / audio / clock skew). Runs on main thread; blocks caller briefly.
|
|
17
|
+
*/
|
|
18
|
+
internal object CliqItWebFingerprint {
|
|
19
|
+
data class Result(
|
|
20
|
+
val canvasHash: String?,
|
|
21
|
+
val webglHash: String?,
|
|
22
|
+
val webglVendor: String?,
|
|
23
|
+
val gpuRenderer: String?,
|
|
24
|
+
val audioFingerprint: String?,
|
|
25
|
+
val clockSkewMs: Int?,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
private val htmlPage = """
|
|
29
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"></head><body>
|
|
30
|
+
<canvas id="c" width="280" height="80"></canvas>
|
|
31
|
+
<script>
|
|
32
|
+
function __cliqItHash(str) {
|
|
33
|
+
var h = 2166136261 >>> 0;
|
|
34
|
+
for (var i = 0; i < str.length; i++) {
|
|
35
|
+
h ^= str.charCodeAt(i);
|
|
36
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
37
|
+
}
|
|
38
|
+
return (h >>> 0).toString(16);
|
|
39
|
+
}
|
|
40
|
+
function __cliqItCanvas() {
|
|
41
|
+
try {
|
|
42
|
+
var c = document.getElementById('c') || document.createElement('canvas');
|
|
43
|
+
c.width = 280; c.height = 80;
|
|
44
|
+
var ctx = c.getContext('2d');
|
|
45
|
+
if (!ctx) return null;
|
|
46
|
+
ctx.textBaseline = 'alphabetic';
|
|
47
|
+
ctx.fillStyle = '#f60';
|
|
48
|
+
ctx.fillRect(10, 1, 140, 24);
|
|
49
|
+
var grad = ctx.createLinearGradient(0, 0, 200, 60);
|
|
50
|
+
grad.addColorStop(0, '#069');
|
|
51
|
+
grad.addColorStop(1, 'rgba(102,204,0,0.7)');
|
|
52
|
+
ctx.fillStyle = grad;
|
|
53
|
+
ctx.font = '16px Arial';
|
|
54
|
+
ctx.fillText('CliqIt,fp', 2, 20);
|
|
55
|
+
ctx.font = '14px "Courier New"';
|
|
56
|
+
ctx.fillText('mmmmmmmmmlli', 2, 42);
|
|
57
|
+
ctx.font = '12px Georgia';
|
|
58
|
+
ctx.fillText('Cwm fjord bank', 2, 60);
|
|
59
|
+
ctx.beginPath();
|
|
60
|
+
ctx.arc(220, 40, 18, 0, Math.PI * 2);
|
|
61
|
+
ctx.strokeStyle = '#c33';
|
|
62
|
+
ctx.stroke();
|
|
63
|
+
return __cliqItHash(c.toDataURL());
|
|
64
|
+
} catch (e) { return null; }
|
|
65
|
+
}
|
|
66
|
+
function __cliqItWebGL() {
|
|
67
|
+
try {
|
|
68
|
+
var c = document.createElement('canvas');
|
|
69
|
+
c.width = 16; c.height = 16;
|
|
70
|
+
var gl = c.getContext('webgl') || c.getContext('experimental-webgl');
|
|
71
|
+
if (!gl) return { hash: null, vendor: null, renderer: null };
|
|
72
|
+
var dbg = gl.getExtension('WEBGL_debug_renderer_info');
|
|
73
|
+
var vendor = dbg ? String(gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL)) : String(gl.getParameter(gl.VENDOR));
|
|
74
|
+
var renderer = dbg ? String(gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL)) : String(gl.getParameter(gl.RENDERER));
|
|
75
|
+
var params = [
|
|
76
|
+
String(gl.getParameter(gl.VERSION) || ''),
|
|
77
|
+
String(gl.getParameter(gl.SHADING_LANGUAGE_VERSION) || ''),
|
|
78
|
+
vendor || '',
|
|
79
|
+
renderer || '',
|
|
80
|
+
String(gl.getParameter(gl.MAX_TEXTURE_SIZE) || ''),
|
|
81
|
+
String(gl.getParameter(gl.MAX_RENDERBUFFER_SIZE) || ''),
|
|
82
|
+
(gl.getSupportedExtensions() || []).join(',')
|
|
83
|
+
].join('|');
|
|
84
|
+
return { hash: __cliqItHash(params), vendor: vendor || null, renderer: renderer || null };
|
|
85
|
+
} catch (e) {
|
|
86
|
+
return { hash: null, vendor: null, renderer: null };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function __cliqItAudio() {
|
|
90
|
+
return new Promise(function(resolve) {
|
|
91
|
+
var settled = false;
|
|
92
|
+
function done(v) { if (settled) return; settled = true; resolve(v); }
|
|
93
|
+
try {
|
|
94
|
+
var AC = window.OfflineAudioContext || window.webkitOfflineAudioContext;
|
|
95
|
+
if (!AC) { done(null); return; }
|
|
96
|
+
var ctx = new AC(1, 44100, 44100);
|
|
97
|
+
var osc = ctx.createOscillator();
|
|
98
|
+
var comp = ctx.createDynamicsCompressor();
|
|
99
|
+
osc.type = 'triangle';
|
|
100
|
+
osc.frequency.value = 10000;
|
|
101
|
+
comp.threshold.value = -50;
|
|
102
|
+
comp.knee.value = 40;
|
|
103
|
+
comp.ratio.value = 12;
|
|
104
|
+
comp.attack.value = 0;
|
|
105
|
+
comp.release.value = 0.25;
|
|
106
|
+
osc.connect(comp);
|
|
107
|
+
comp.connect(ctx.destination);
|
|
108
|
+
osc.start(0);
|
|
109
|
+
ctx.oncomplete = function(ev) {
|
|
110
|
+
try {
|
|
111
|
+
var data = ev.renderedBuffer.getChannelData(0);
|
|
112
|
+
var sum = 0;
|
|
113
|
+
for (var i = 4500; i < 5000; i++) sum += Math.abs(data[i]);
|
|
114
|
+
done(__cliqItHash(String(sum)));
|
|
115
|
+
} catch (e) { done(null); }
|
|
116
|
+
};
|
|
117
|
+
ctx.startRendering();
|
|
118
|
+
setTimeout(function() { done(null); }, 700);
|
|
119
|
+
} catch (e) { done(null); }
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
window.__cliqItCollectFingerprint = async function() {
|
|
123
|
+
var gl = __cliqItWebGL();
|
|
124
|
+
var skew = null;
|
|
125
|
+
try {
|
|
126
|
+
if (window.performance && typeof performance.now === 'function' && performance.timeOrigin) {
|
|
127
|
+
skew = Date.now() - (performance.timeOrigin + performance.now());
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {}
|
|
130
|
+
var audio = await __cliqItAudio();
|
|
131
|
+
return {
|
|
132
|
+
canvasHash: __cliqItCanvas(),
|
|
133
|
+
webglHash: gl.hash,
|
|
134
|
+
webglVendor: gl.vendor,
|
|
135
|
+
webglRenderer: gl.renderer,
|
|
136
|
+
audioHash: audio,
|
|
137
|
+
clockSkewMs: skew
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
</script></body></html>
|
|
141
|
+
""".trimIndent()
|
|
142
|
+
|
|
143
|
+
@SuppressLint("SetJavaScriptEnabled")
|
|
144
|
+
fun collect(context: Context, timeoutMs: Long = 3500L): Result? {
|
|
145
|
+
val latch = CountDownLatch(1)
|
|
146
|
+
val holder = AtomicReference<Result?>(null)
|
|
147
|
+
val appCtx = context.applicationContext
|
|
148
|
+
|
|
149
|
+
Handler(Looper.getMainLooper()).post {
|
|
150
|
+
var webView: WebView? = null
|
|
151
|
+
try {
|
|
152
|
+
webView = WebView(appCtx).apply {
|
|
153
|
+
settings.javaScriptEnabled = true
|
|
154
|
+
settings.domStorageEnabled = false
|
|
155
|
+
// Keep off-screen; do not attach to a window.
|
|
156
|
+
webViewClient = object : WebViewClient() {
|
|
157
|
+
override fun onPageFinished(view: WebView?, url: String?) {
|
|
158
|
+
view?.evaluateJavascript(
|
|
159
|
+
"(async function(){ try { return JSON.stringify(await window.__cliqItCollectFingerprint()); } catch(e) { return null; } })()",
|
|
160
|
+
) { value ->
|
|
161
|
+
holder.set(parseJsResult(value))
|
|
162
|
+
try {
|
|
163
|
+
view.destroy()
|
|
164
|
+
} catch (_: Exception) {
|
|
165
|
+
}
|
|
166
|
+
latch.countDown()
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
loadDataWithBaseURL(
|
|
171
|
+
"https://localhost/",
|
|
172
|
+
htmlPage,
|
|
173
|
+
"text/html",
|
|
174
|
+
"UTF-8",
|
|
175
|
+
null,
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
} catch (_: Exception) {
|
|
179
|
+
try {
|
|
180
|
+
webView?.destroy()
|
|
181
|
+
} catch (_: Exception) {
|
|
182
|
+
}
|
|
183
|
+
latch.countDown()
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
latch.await(timeoutMs, TimeUnit.MILLISECONDS)
|
|
188
|
+
return holder.get()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private fun parseJsResult(raw: String?): Result? {
|
|
192
|
+
if (raw.isNullOrBlank() || raw == "null") return null
|
|
193
|
+
// evaluateJavascript wraps strings in JSON quotes
|
|
194
|
+
val unquoted = try {
|
|
195
|
+
org.json.JSONTokener(raw).nextValue()?.let { v ->
|
|
196
|
+
when (v) {
|
|
197
|
+
is String -> v
|
|
198
|
+
else -> raw.trim().removeSurrounding("\"")
|
|
199
|
+
.replace("\\\"", "\"")
|
|
200
|
+
.replace("\\\\", "\\")
|
|
201
|
+
}
|
|
202
|
+
} ?: return null
|
|
203
|
+
} catch (_: Exception) {
|
|
204
|
+
raw.trim().removeSurrounding("\"")
|
|
205
|
+
.replace("\\\"", "\"")
|
|
206
|
+
.replace("\\\\", "\\")
|
|
207
|
+
}
|
|
208
|
+
return try {
|
|
209
|
+
val json = JSONObject(unquoted)
|
|
210
|
+
fun opt(key: String): String? =
|
|
211
|
+
if (!json.has(key) || json.isNull(key)) null
|
|
212
|
+
else json.optString(key, "").takeIf { it.isNotEmpty() && it != "null" }
|
|
213
|
+
|
|
214
|
+
val skew = when {
|
|
215
|
+
!json.has("clockSkewMs") || json.isNull("clockSkewMs") -> null
|
|
216
|
+
else -> json.optDouble("clockSkewMs").takeUnless { it.isNaN() }?.toInt()
|
|
217
|
+
}
|
|
218
|
+
Result(
|
|
219
|
+
canvasHash = opt("canvasHash"),
|
|
220
|
+
webglHash = opt("webglHash"),
|
|
221
|
+
webglVendor = opt("webglVendor"),
|
|
222
|
+
gpuRenderer = opt("webglRenderer"),
|
|
223
|
+
audioFingerprint = opt("audioHash"),
|
|
224
|
+
clockSkewMs = skew,
|
|
225
|
+
)
|
|
226
|
+
} catch (_: Exception) {
|
|
227
|
+
null
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
3
|
+
|
|
4
|
+
@interface RCT_EXTERN_MODULE(CliqItModule, RCTEventEmitter)
|
|
5
|
+
|
|
6
|
+
RCT_EXTERN_METHOD(configure:(NSString *)apiKey)
|
|
7
|
+
RCT_EXTERN_METHOD(handleUrl:(NSString *)urlString)
|
|
8
|
+
|
|
9
|
+
+ (BOOL)requiresMainQueueSetup
|
|
10
|
+
{
|
|
11
|
+
return YES;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@end
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import CliqIt
|
|
2
|
+
import Foundation
|
|
3
|
+
import React
|
|
4
|
+
|
|
5
|
+
@objc(CliqItModule)
|
|
6
|
+
class CliqItModule: RCTEventEmitter {
|
|
7
|
+
private var hasListeners = false
|
|
8
|
+
// ponytail: RN listeners attach after configure; buffer one shot so events aren't dropped
|
|
9
|
+
private var pendingDeepLink: [String: Any]?
|
|
10
|
+
private var pendingDeferredMatch: [String: Any]?
|
|
11
|
+
private var pendingLinkLookup: [String: Any]?
|
|
12
|
+
private var pendingVerify: [String: Any]?
|
|
13
|
+
|
|
14
|
+
override static func requiresMainQueueSetup() -> Bool { true }
|
|
15
|
+
|
|
16
|
+
override func supportedEvents() -> [String]! {
|
|
17
|
+
["CliqItDeepLink", "CliqItDeferredMatch", "CliqItLinkLookup", "CliqItVerify"]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override func startObserving() {
|
|
21
|
+
hasListeners = true
|
|
22
|
+
flushPending()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
override func stopObserving() {
|
|
26
|
+
hasListeners = false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@objc
|
|
30
|
+
func configure(_ apiKey: String) {
|
|
31
|
+
// Handlers that may fire during configure must be registered first where possible.
|
|
32
|
+
CliqItSDK.shared.onVerify { [weak self] result in
|
|
33
|
+
self?.emitVerify(result)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// SDK requires configure() before onDeepLink / onDeferredMatch.
|
|
37
|
+
CliqItSDK.shared.configure(apiKey: apiKey)
|
|
38
|
+
|
|
39
|
+
CliqItSDK.shared.onDeepLink { [weak self] payload in
|
|
40
|
+
self?.emitDeepLink(payload)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
CliqItSDK.shared.onDeferredMatch { [weak self] outcome in
|
|
44
|
+
self?.emitDeferred(outcome)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
CliqItSDK.shared.onDirectLinkLookup { [weak self] result in
|
|
48
|
+
self?.emitLinkLookup(result)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Cold start after a prior match: SDK won't run again — tell JS instead of hanging forever.
|
|
52
|
+
if CliqItSDK.shared.hasDeferredMatchBeenReported,
|
|
53
|
+
!CliqItSDK.shared.isDeferredMatchInFlight
|
|
54
|
+
{
|
|
55
|
+
emitBody(
|
|
56
|
+
event: "CliqItDeferredMatch",
|
|
57
|
+
body: [
|
|
58
|
+
"status": "alreadyReported",
|
|
59
|
+
"note": "Deferred match already ran on this install. Delete the app (or clear UserDefaults) to retest.",
|
|
60
|
+
],
|
|
61
|
+
pendingKey: \.pendingDeferredMatch
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@objc
|
|
67
|
+
func handleUrl(_ urlString: String) {
|
|
68
|
+
guard let url = URL(string: urlString) else { return }
|
|
69
|
+
_ = CliqItSDK.shared.handle(url: url)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
override func constantsToExport() -> [AnyHashable: Any]! {
|
|
73
|
+
[
|
|
74
|
+
"LinkField": [
|
|
75
|
+
"destination": CliqItLinkField.destination.rawValue,
|
|
76
|
+
"iosDestination": CliqItLinkField.iosDestination.rawValue,
|
|
77
|
+
"androidDestination": CliqItLinkField.androidDestination.rawValue,
|
|
78
|
+
"ogTitle": CliqItLinkField.ogTitle.rawValue,
|
|
79
|
+
"ogDescription": CliqItLinkField.ogDescription.rawValue,
|
|
80
|
+
"ogImage": CliqItLinkField.ogImage.rawValue,
|
|
81
|
+
"ogUrl": CliqItLinkField.ogUrl.rawValue,
|
|
82
|
+
"slug": CliqItLinkField.slug.rawValue,
|
|
83
|
+
"webFallback": CliqItLinkField.webFallback.rawValue,
|
|
84
|
+
"showInterstitial": CliqItLinkField.showInterstitial.rawValue,
|
|
85
|
+
"isDeepLink": CliqItLinkField.isDeepLink.rawValue,
|
|
86
|
+
"appleTeamId": CliqItLinkField.appleTeamId.rawValue,
|
|
87
|
+
"iosBundleId": CliqItLinkField.iosBundleId.rawValue,
|
|
88
|
+
"androidPackageName": CliqItLinkField.androidPackageName.rawValue,
|
|
89
|
+
"resolvedPath": CliqItLinkField.resolvedPath.rawValue,
|
|
90
|
+
],
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// MARK: - Emit / buffer
|
|
95
|
+
|
|
96
|
+
private func emitDeepLink(_ payload: CliqItPayload) {
|
|
97
|
+
let body: [String: Any] = [
|
|
98
|
+
"url": payload.url.absoluteString,
|
|
99
|
+
"path": payload.path,
|
|
100
|
+
"pathComponents": payload.pathComponents,
|
|
101
|
+
"query": payload.queryParameters,
|
|
102
|
+
"source": payload.source.rawValue,
|
|
103
|
+
"isDeferred": payload.isDeferred,
|
|
104
|
+
]
|
|
105
|
+
emitBody(event: "CliqItDeepLink", body: body, pendingKey: \.pendingDeepLink)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private func emitDeferred(_ outcome: CliqItDeferredMatchOutcome) {
|
|
109
|
+
let body: [String: Any]
|
|
110
|
+
switch outcome {
|
|
111
|
+
case .matched(let info):
|
|
112
|
+
body = [
|
|
113
|
+
"status": "matched",
|
|
114
|
+
"destinationPath": info.destinationPath as Any,
|
|
115
|
+
"slug": info.slug as Any,
|
|
116
|
+
"tier": info.tier as Any,
|
|
117
|
+
"score": info.score as Any,
|
|
118
|
+
"confidence": info.confidence as Any,
|
|
119
|
+
]
|
|
120
|
+
case .notMatched(let info):
|
|
121
|
+
body = [
|
|
122
|
+
"status": "notMatched",
|
|
123
|
+
"tier": info.tier as Any,
|
|
124
|
+
"score": info.score as Any,
|
|
125
|
+
]
|
|
126
|
+
case .failed(let error):
|
|
127
|
+
body = [
|
|
128
|
+
"status": "failed",
|
|
129
|
+
"error": error.localizedDescription,
|
|
130
|
+
]
|
|
131
|
+
@unknown default:
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
emitBody(event: "CliqItDeferredMatch", body: body, pendingKey: \.pendingDeferredMatch)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private func emitLinkLookup(_ result: Result<CliqItLinkDetails, CliqItDeferredMatchError>) {
|
|
138
|
+
let body: [String: Any]
|
|
139
|
+
switch result {
|
|
140
|
+
case .success(let details):
|
|
141
|
+
body = [
|
|
142
|
+
"status": "resolved",
|
|
143
|
+
"destination": details[.destination] as Any,
|
|
144
|
+
"iosDestination": details[.iosDestination] as Any,
|
|
145
|
+
"androidDestination": details[.androidDestination] as Any,
|
|
146
|
+
"ogTitle": details[.ogTitle] as Any,
|
|
147
|
+
"ogDescription": details[.ogDescription] as Any,
|
|
148
|
+
"ogImage": details[.ogImage] as Any,
|
|
149
|
+
"ogUrl": details[.ogUrl] as Any,
|
|
150
|
+
"slug": details[.slug] as Any,
|
|
151
|
+
"webFallback": details[.webFallback] as Any,
|
|
152
|
+
"showInterstitial": details[.showInterstitial] as Any,
|
|
153
|
+
"isDeepLink": details[.isDeepLink] as Any,
|
|
154
|
+
"appleTeamId": details[.appleTeamId] as Any,
|
|
155
|
+
"iosBundleId": details[.iosBundleId] as Any,
|
|
156
|
+
"androidPackageName": details[.androidPackageName] as Any,
|
|
157
|
+
"resolvedPath": details[.resolvedPath] as Any,
|
|
158
|
+
]
|
|
159
|
+
case .failure(let error):
|
|
160
|
+
body = [
|
|
161
|
+
"status": "failed",
|
|
162
|
+
"error": error.localizedDescription,
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
emitBody(event: "CliqItLinkLookup", body: body, pendingKey: \.pendingLinkLookup)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private func emitVerify(_ outcome: CliqItVerifyOutcome) {
|
|
169
|
+
var body: [String: Any] = [:]
|
|
170
|
+
switch outcome {
|
|
171
|
+
case .passed(let r):
|
|
172
|
+
body = verifyBody(status: "ok", result: r)
|
|
173
|
+
case .mismatched(let r):
|
|
174
|
+
body = verifyBody(status: "mismatch", result: r)
|
|
175
|
+
body["message"] = r.mismatchMessage
|
|
176
|
+
case .error(let error):
|
|
177
|
+
body = [
|
|
178
|
+
"status": "failed",
|
|
179
|
+
"ok": false,
|
|
180
|
+
"error": error.localizedDescription,
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
if let raw = CliqItSDK.shared.currentVerifyJSON {
|
|
184
|
+
body["raw"] = raw
|
|
185
|
+
}
|
|
186
|
+
emitBody(event: "CliqItVerify", body: body, pendingKey: \.pendingVerify)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private func verifyBody(status: String, result: CliqItVerifyResult) -> [String: Any] {
|
|
190
|
+
var checks: [String: Any] = [:]
|
|
191
|
+
for (key, check) in result.checks {
|
|
192
|
+
checks[key] = [
|
|
193
|
+
"actual": check.actual as Any,
|
|
194
|
+
"expected": check.expected as Any,
|
|
195
|
+
"match": check.match,
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
return [
|
|
199
|
+
"status": status,
|
|
200
|
+
"ok": result.ok,
|
|
201
|
+
"appId": result.appId as Any,
|
|
202
|
+
"appName": result.appName as Any,
|
|
203
|
+
"checks": checks,
|
|
204
|
+
"message": result.mismatchMessage,
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private func emitBody(
|
|
209
|
+
event: String,
|
|
210
|
+
body: [String: Any],
|
|
211
|
+
pendingKey: ReferenceWritableKeyPath<CliqItModule, [String: Any]?>
|
|
212
|
+
) {
|
|
213
|
+
if hasListeners {
|
|
214
|
+
sendEvent(withName: event, body: body)
|
|
215
|
+
} else {
|
|
216
|
+
self[keyPath: pendingKey] = body
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private func flushPending() {
|
|
221
|
+
if let deep = pendingDeepLink {
|
|
222
|
+
pendingDeepLink = nil
|
|
223
|
+
sendEvent(withName: "CliqItDeepLink", body: deep)
|
|
224
|
+
}
|
|
225
|
+
if let match = pendingDeferredMatch {
|
|
226
|
+
pendingDeferredMatch = nil
|
|
227
|
+
sendEvent(withName: "CliqItDeferredMatch", body: match)
|
|
228
|
+
}
|
|
229
|
+
if let lookup = pendingLinkLookup {
|
|
230
|
+
pendingLinkLookup = nil
|
|
231
|
+
sendEvent(withName: "CliqItLinkLookup", body: lookup)
|
|
232
|
+
}
|
|
233
|
+
if let verify = pendingVerify {
|
|
234
|
+
pendingVerify = nil
|
|
235
|
+
sendEvent(withName: "CliqItVerify", body: verify)
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>AvailableLibraries</key>
|
|
6
|
+
<array>
|
|
7
|
+
<dict>
|
|
8
|
+
<key>BinaryPath</key>
|
|
9
|
+
<string>CliqIt.framework/CliqIt</string>
|
|
10
|
+
<key>LibraryIdentifier</key>
|
|
11
|
+
<string>ios-arm64_x86_64-simulator</string>
|
|
12
|
+
<key>LibraryPath</key>
|
|
13
|
+
<string>CliqIt.framework</string>
|
|
14
|
+
<key>SupportedArchitectures</key>
|
|
15
|
+
<array>
|
|
16
|
+
<string>arm64</string>
|
|
17
|
+
<string>x86_64</string>
|
|
18
|
+
</array>
|
|
19
|
+
<key>SupportedPlatform</key>
|
|
20
|
+
<string>ios</string>
|
|
21
|
+
<key>SupportedPlatformVariant</key>
|
|
22
|
+
<string>simulator</string>
|
|
23
|
+
</dict>
|
|
24
|
+
<dict>
|
|
25
|
+
<key>BinaryPath</key>
|
|
26
|
+
<string>CliqIt.framework/CliqIt</string>
|
|
27
|
+
<key>LibraryIdentifier</key>
|
|
28
|
+
<string>ios-arm64</string>
|
|
29
|
+
<key>LibraryPath</key>
|
|
30
|
+
<string>CliqIt.framework</string>
|
|
31
|
+
<key>SupportedArchitectures</key>
|
|
32
|
+
<array>
|
|
33
|
+
<string>arm64</string>
|
|
34
|
+
</array>
|
|
35
|
+
<key>SupportedPlatform</key>
|
|
36
|
+
<string>ios</string>
|
|
37
|
+
</dict>
|
|
38
|
+
</array>
|
|
39
|
+
<key>CFBundlePackageType</key>
|
|
40
|
+
<string>XFWK</string>
|
|
41
|
+
<key>XCFrameworkFormatVersion</key>
|
|
42
|
+
<string>1.0</string>
|
|
43
|
+
</dict>
|
|
44
|
+
</plist>
|