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
package/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# react-native-cliqit
|
|
2
|
+
|
|
3
|
+
React Native bridge for **CliqIt** deferred deep linking.
|
|
4
|
+
|
|
5
|
+
- **iOS:** ships `CliqIt.xcframework` (closed-source native SDK)
|
|
6
|
+
- **Android:** Kotlin SDK + RN bridge included
|
|
7
|
+
- **No npm publish required** — install from Git
|
|
8
|
+
|
|
9
|
+
**Version:** `2.0.6`
|
|
10
|
+
|
|
11
|
+
## Install (Git)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install git+https://github.com/mindrootstech/react-native-cliqit.git#v2.0.6
|
|
15
|
+
# or yarn / pnpm equivalent
|
|
16
|
+
|
|
17
|
+
cd ios && pod install && cd ..
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`package.json`:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"react-native-cliqit": "git+https://github.com/mindrootstech/react-native-cliqit.git#v2.0.6"
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
All APIs use a `{ result, error }` callback object.
|
|
31
|
+
|
|
32
|
+
Register listeners **before** `configure` — deferred match can finish very fast.
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import { useEffect } from 'react';
|
|
36
|
+
import { Linking } from 'react-native';
|
|
37
|
+
import CliqIt from 'react-native-cliqit';
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
// onDeepLink — runs when the app should navigate:
|
|
41
|
+
// • Direct: user opens a SmartLink / App Link while app is installed (isDeferred: false)
|
|
42
|
+
// • Deferred: after a successful first-open match, SDK delivers the path (isDeferred: true)
|
|
43
|
+
const offDeepLink = CliqIt.onDeepLink(({ result, error }) => {
|
|
44
|
+
if (error) return;
|
|
45
|
+
console.log('deep link', result.path, result.isDeferred);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// onDeferredMatch — runs once on cold start / configure (first install attribution):
|
|
49
|
+
// Server fingerprint match result (matched / notMatched / alreadyReported + score/slug/path).
|
|
50
|
+
// Does NOT mean "navigate by itself" — if matched, onDeepLink usually fires next.
|
|
51
|
+
const offMatch = CliqIt.onDeferredMatch(({ result, error }) => {
|
|
52
|
+
if (error) return;
|
|
53
|
+
if (result?.status === 'matched') {
|
|
54
|
+
console.log('deferred', result.destinationPath);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// onLinkLookup — runs on direct SmartLink open when SDK resolves slug → destination via API.
|
|
59
|
+
// Not used for pure deferred-only first open (unless a URL was also handled).
|
|
60
|
+
const offLookup = CliqIt.onLinkLookup(({ result, error }) => {
|
|
61
|
+
if (error) return;
|
|
62
|
+
console.log('link lookup', result?.resolvedPath ?? result?.slug);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// onVerify — runs after configure (background): API key + package/bundle (/ SHA) identity check.
|
|
66
|
+
const offVerify = CliqIt.onVerify(({ result, error }) => {
|
|
67
|
+
console.log('verify', error || result?.status);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// configure — call once at startup (after listeners). Starts verify + deferred match.
|
|
71
|
+
CliqIt.configure({ apiKey: 'pk_live_…' }, ({ result, error }) => {
|
|
72
|
+
console.log('configured', result, error);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// handleUrl — pass Universal Links / App Links / custom-scheme URLs into the SDK.
|
|
76
|
+
// Cold start: Linking.getInitialURL(). Warm: Linking 'url' event.
|
|
77
|
+
Linking.getInitialURL().then((url) => {
|
|
78
|
+
if (url) CliqIt.handleUrl({ url }, ({ error }) => {});
|
|
79
|
+
});
|
|
80
|
+
const linkSub = Linking.addEventListener('url', ({ url }) => {
|
|
81
|
+
CliqIt.handleUrl({ url });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return () => {
|
|
85
|
+
offDeepLink();
|
|
86
|
+
offMatch();
|
|
87
|
+
offLookup();
|
|
88
|
+
offVerify();
|
|
89
|
+
linkSub.remove();
|
|
90
|
+
};
|
|
91
|
+
}, []);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
## Callback results
|
|
96
|
+
|
|
97
|
+
Every listener / action callback receives:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
{ result: object | null, error: string | null }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- On success: `error` is `null`, use `result`
|
|
104
|
+
- On failure: `result` is `null`, use `error`
|
|
105
|
+
|
|
106
|
+
### `configure({ apiKey }, cb)`
|
|
107
|
+
|
|
108
|
+
| Field | Type | Notes |
|
|
109
|
+
|-------|------|--------|
|
|
110
|
+
| `result.ok` | `boolean` | `true` when configure was accepted locally |
|
|
111
|
+
| `error` | `string` | Missing `apiKey`, or native throw |
|
|
112
|
+
|
|
113
|
+
Starts background **verify** + **deferred match** (listeners should be registered first).
|
|
114
|
+
|
|
115
|
+
### `handleUrl({ url }, cb)`
|
|
116
|
+
|
|
117
|
+
| Field | Type | Notes |
|
|
118
|
+
|-------|------|--------|
|
|
119
|
+
| `result.ok` | `boolean` | URL was passed into the native SDK |
|
|
120
|
+
| `result.url` | `string` | Same URL you passed |
|
|
121
|
+
| `error` | `string` | Missing / invalid `url` |
|
|
122
|
+
|
|
123
|
+
Use for Universal Links / App Links / custom schemes (cold start + warm).
|
|
124
|
+
|
|
125
|
+
### `onDeepLink(({ result, error }) => …)`
|
|
126
|
+
|
|
127
|
+
Navigation payload — **direct** opens and **deferred delivery**.
|
|
128
|
+
|
|
129
|
+
| Field | Type | Notes |
|
|
130
|
+
|-------|------|--------|
|
|
131
|
+
| `result.url` | `string` | Original or synthetic URL |
|
|
132
|
+
| `result.path` | `string` | In-app path (usually starts with `/`) |
|
|
133
|
+
| `result.pathComponents` | `string[]` | Path segments |
|
|
134
|
+
| `result.query` | `object` | Query key → value |
|
|
135
|
+
| `result.source` | `string` | e.g. `deferred`, `universalLink`, `customScheme` |
|
|
136
|
+
| `result.isDeferred` | `boolean` | `true` if from deferred match delivery |
|
|
137
|
+
| `error` | `string` | Rare bridge/payload issues |
|
|
138
|
+
|
|
139
|
+
### `onDeferredMatch(({ result, error }) => …)`
|
|
140
|
+
|
|
141
|
+
First-open **attribution** only (not navigation by itself).
|
|
142
|
+
|
|
143
|
+
| Field | Type | When |
|
|
144
|
+
|-------|------|------|
|
|
145
|
+
| `result.status` | `string` | `matched` \| `notMatched` \| `alreadyReported` |
|
|
146
|
+
| `result.destinationPath` | `string?` | Matched in-app destination (may omit leading `/`) |
|
|
147
|
+
| `result.slug` | `string?` | SmartLink slug |
|
|
148
|
+
| `result.score` | `number?` | Match score |
|
|
149
|
+
| `result.tier` | `string?` | e.g. `probabilistic` |
|
|
150
|
+
| `result.confidence` | `string?` | e.g. `medium` |
|
|
151
|
+
| `result.note` | `string?` | Present when `alreadyReported` |
|
|
152
|
+
| `error` | `string` | Match request / decode failure (`status: failed`) |
|
|
153
|
+
|
|
154
|
+
If `status === 'matched'`, `onDeepLink` usually fires next with `isDeferred: true`.
|
|
155
|
+
|
|
156
|
+
### `onLinkLookup(({ result, error }) => …)`
|
|
157
|
+
|
|
158
|
+
Direct SmartLink **slug → destination** API resolve.
|
|
159
|
+
|
|
160
|
+
| Field | Type | Notes |
|
|
161
|
+
|-------|------|--------|
|
|
162
|
+
| `result.status` | `string` | `resolved` on success |
|
|
163
|
+
| `result.resolvedPath` | `string?` | Platform path (`iosDestination` / `androidDestination` / `destination`) |
|
|
164
|
+
| `result.slug` | `string?` | Link slug |
|
|
165
|
+
| `result.destination` | `string?` | Default destination |
|
|
166
|
+
| `result.iosDestination` | `string?` | iOS-specific path |
|
|
167
|
+
| `result.androidDestination` | `string?` | Android-specific path |
|
|
168
|
+
| `result.ogTitle` / `ogDescription` / `ogImage` / `ogUrl` | `string?` | Open Graph fields |
|
|
169
|
+
| `result.webFallback` | `string?` | Web fallback URL |
|
|
170
|
+
| `result.showInterstitial` | `string?` | `"true"` / `"false"` when present |
|
|
171
|
+
| `result.isDeepLink` | `string?` | `"true"` / `"false"` when present |
|
|
172
|
+
| `result.appleTeamId` | `string?` | iOS team id |
|
|
173
|
+
| `result.iosBundleId` | `string?` | Expected iOS bundle |
|
|
174
|
+
| `result.androidPackageName` | `string?` | Expected Android package |
|
|
175
|
+
| `error` | `string` | Lookup failed |
|
|
176
|
+
|
|
177
|
+
Prefer `CliqIt.LinkField.resolvedPath` (and other `LinkField` keys) instead of raw strings.
|
|
178
|
+
|
|
179
|
+
### `onVerify(({ result, error }) => …)`
|
|
180
|
+
|
|
181
|
+
Runs after `configure` — API key / app identity check.
|
|
182
|
+
|
|
183
|
+
| Field | Type | Notes |
|
|
184
|
+
|-------|------|--------|
|
|
185
|
+
| `result.status` | `string` | `ok` \| `mismatch` |
|
|
186
|
+
| `result.ok` | `boolean` | Same as server `ok` |
|
|
187
|
+
| `result.appId` | `string?` | App id from admin |
|
|
188
|
+
| `result.appName` | `string?` | App display name |
|
|
189
|
+
| `result.message` | `string?` | Human-readable summary |
|
|
190
|
+
| `result.checks` | `object?` | Per-field `{ actual, expected, match }` (bundle / package / SHA) |
|
|
191
|
+
| `result.raw` | `string?` | Raw JSON body (if provided by native) |
|
|
192
|
+
| `error` | `string` | Network / decode / failed verify transport |
|
|
193
|
+
|
|
194
|
+
`mismatch` stays in `result` (identity problem, not a dropped callback). Transport failures use `error`.
|
|
195
|
+
|
|
196
|
+
## App setup
|
|
197
|
+
|
|
198
|
+
### iOS
|
|
199
|
+
- Associated Domains: `applinks:<your-smartlink-domain>`
|
|
200
|
+
- iOS 15+
|
|
201
|
+
|
|
202
|
+
### Android
|
|
203
|
+
- App Links intent-filter for your SmartLink host
|
|
204
|
+
- Autolinking registers `CliqItPackage` (RN 0.60+)
|
|
205
|
+
|
|
206
|
+
## Notes
|
|
207
|
+
|
|
208
|
+
- This repo is **SDK only** — no demo app code.
|
|
209
|
+
- Native iOS binary alone (without RN): https://github.com/mindrootstech/CliqIt
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.safeExtGet = { prop, fallback ->
|
|
3
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
apply plugin: 'com.android.library'
|
|
8
|
+
apply plugin: 'org.jetbrains.kotlin.android'
|
|
9
|
+
|
|
10
|
+
android {
|
|
11
|
+
namespace "com.cliqit"
|
|
12
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 35)
|
|
13
|
+
|
|
14
|
+
defaultConfig {
|
|
15
|
+
minSdkVersion safeExtGet('minSdkVersion', 24)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
sourceSets {
|
|
19
|
+
main {
|
|
20
|
+
java.srcDirs = ['src/main/java']
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
dependencies {
|
|
26
|
+
implementation "com.facebook.react:react-android"
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
package com.cliqit
|
|
2
|
+
|
|
3
|
+
import com.cliqit.sdk.CliqItSDK
|
|
4
|
+
import com.cliqit.sdk.DeferredMatchOutcome
|
|
5
|
+
import com.cliqit.sdk.LinkField
|
|
6
|
+
import com.cliqit.sdk.LinkLookupResult
|
|
7
|
+
import com.cliqit.sdk.VerifyOutcome
|
|
8
|
+
import com.facebook.react.bridge.Arguments
|
|
9
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
10
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
11
|
+
import com.facebook.react.bridge.ReactMethod
|
|
12
|
+
import com.facebook.react.bridge.WritableMap
|
|
13
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
14
|
+
|
|
15
|
+
class CliqItModule(private val reactContext: ReactApplicationContext) :
|
|
16
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
17
|
+
|
|
18
|
+
private var hasListeners = false
|
|
19
|
+
private var pendingDeepLink: WritableMap? = null
|
|
20
|
+
private var pendingDeferredMatch: WritableMap? = null
|
|
21
|
+
private var pendingLinkLookup: WritableMap? = null
|
|
22
|
+
private var pendingVerify: WritableMap? = null
|
|
23
|
+
private var handlersBound = false
|
|
24
|
+
|
|
25
|
+
override fun getName(): String = "CliqItModule"
|
|
26
|
+
|
|
27
|
+
override fun getConstants(): MutableMap<String, Any> = hashMapOf(
|
|
28
|
+
"LinkField" to hashMapOf(
|
|
29
|
+
"destination" to LinkField.destination,
|
|
30
|
+
"iosDestination" to LinkField.iosDestination,
|
|
31
|
+
"androidDestination" to LinkField.androidDestination,
|
|
32
|
+
"ogTitle" to LinkField.ogTitle,
|
|
33
|
+
"ogDescription" to LinkField.ogDescription,
|
|
34
|
+
"ogImage" to LinkField.ogImage,
|
|
35
|
+
"ogUrl" to LinkField.ogUrl,
|
|
36
|
+
"slug" to LinkField.slug,
|
|
37
|
+
"webFallback" to LinkField.webFallback,
|
|
38
|
+
"showInterstitial" to LinkField.showInterstitial,
|
|
39
|
+
"isDeepLink" to LinkField.isDeepLink,
|
|
40
|
+
"appleTeamId" to LinkField.appleTeamId,
|
|
41
|
+
"iosBundleId" to LinkField.iosBundleId,
|
|
42
|
+
"androidPackageName" to LinkField.androidPackageName,
|
|
43
|
+
"resolvedPath" to LinkField.resolvedPath,
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
@ReactMethod
|
|
48
|
+
fun addListener(eventName: String) {
|
|
49
|
+
hasListeners = true
|
|
50
|
+
flushPending()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@ReactMethod
|
|
54
|
+
fun removeListeners(count: Int) {
|
|
55
|
+
if (count > 0) hasListeners = false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@ReactMethod
|
|
59
|
+
fun configure(apiKey: String) {
|
|
60
|
+
CliqItSDK.init(reactContext)
|
|
61
|
+
bindHandlersIfNeeded()
|
|
62
|
+
CliqItSDK.configure(apiKey)
|
|
63
|
+
|
|
64
|
+
if (CliqItSDK.hasDeferredMatchBeenReported && !CliqItSDK.isDeferredMatchInFlight) {
|
|
65
|
+
emitOrBuffer(
|
|
66
|
+
"CliqItDeferredMatch",
|
|
67
|
+
Arguments.createMap().apply {
|
|
68
|
+
putString("status", "alreadyReported")
|
|
69
|
+
putString(
|
|
70
|
+
"note",
|
|
71
|
+
"Deferred match already ran on this install. Clear app data to retest.",
|
|
72
|
+
)
|
|
73
|
+
},
|
|
74
|
+
) { pendingDeferredMatch = it }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@ReactMethod
|
|
79
|
+
fun handleUrl(url: String) {
|
|
80
|
+
CliqItSDK.init(reactContext)
|
|
81
|
+
CliqItSDK.handle(url)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private fun bindHandlersIfNeeded() {
|
|
85
|
+
if (handlersBound) return
|
|
86
|
+
handlersBound = true
|
|
87
|
+
|
|
88
|
+
CliqItSDK.onDeepLink { payload ->
|
|
89
|
+
val query = Arguments.createMap()
|
|
90
|
+
payload.query.forEach { (k, v) -> query.putString(k, v) }
|
|
91
|
+
val components = Arguments.createArray()
|
|
92
|
+
payload.pathComponents.forEach { components.pushString(it) }
|
|
93
|
+
val map = Arguments.createMap().apply {
|
|
94
|
+
putString("url", payload.url)
|
|
95
|
+
putString("path", payload.path)
|
|
96
|
+
putArray("pathComponents", components)
|
|
97
|
+
putMap("query", query)
|
|
98
|
+
putString("source", payload.source)
|
|
99
|
+
putBoolean("isDeferred", payload.isDeferred)
|
|
100
|
+
}
|
|
101
|
+
emitOrBuffer("CliqItDeepLink", map) { pendingDeepLink = it }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
CliqItSDK.onDeferredMatch { outcome ->
|
|
105
|
+
val map = Arguments.createMap()
|
|
106
|
+
when (outcome) {
|
|
107
|
+
is DeferredMatchOutcome.Matched -> {
|
|
108
|
+
map.putString("status", "matched")
|
|
109
|
+
putOpt(map, "destinationPath", outcome.info.destinationPath)
|
|
110
|
+
putOpt(map, "slug", outcome.info.slug)
|
|
111
|
+
putOpt(map, "tier", outcome.info.tier)
|
|
112
|
+
putOpt(map, "confidence", outcome.info.confidence)
|
|
113
|
+
outcome.info.score?.let { map.putDouble("score", it) }
|
|
114
|
+
}
|
|
115
|
+
is DeferredMatchOutcome.NotMatched -> {
|
|
116
|
+
map.putString("status", "notMatched")
|
|
117
|
+
putOpt(map, "tier", outcome.info.tier)
|
|
118
|
+
outcome.info.score?.let { map.putDouble("score", it) }
|
|
119
|
+
}
|
|
120
|
+
is DeferredMatchOutcome.Failed -> {
|
|
121
|
+
map.putString("status", "failed")
|
|
122
|
+
map.putString("error", outcome.error)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
emitOrBuffer("CliqItDeferredMatch", map) { pendingDeferredMatch = it }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
CliqItSDK.onDirectLinkLookup { result ->
|
|
129
|
+
val map = Arguments.createMap()
|
|
130
|
+
when (result) {
|
|
131
|
+
is LinkLookupResult.Resolved -> {
|
|
132
|
+
val d = result.details
|
|
133
|
+
map.putString("status", "resolved")
|
|
134
|
+
putOpt(map, LinkField.destination, d.destination)
|
|
135
|
+
putOpt(map, LinkField.iosDestination, d.iosDestination)
|
|
136
|
+
putOpt(map, LinkField.androidDestination, d.androidDestination)
|
|
137
|
+
putOpt(map, LinkField.ogTitle, d.ogTitle)
|
|
138
|
+
putOpt(map, LinkField.ogDescription, d.ogDescription)
|
|
139
|
+
putOpt(map, LinkField.ogImage, d.ogImage)
|
|
140
|
+
putOpt(map, LinkField.ogUrl, d.ogUrl)
|
|
141
|
+
putOpt(map, LinkField.slug, d.slug)
|
|
142
|
+
putOpt(map, LinkField.webFallback, d.webFallback)
|
|
143
|
+
putOpt(map, LinkField.showInterstitial, d.field(LinkField.showInterstitial))
|
|
144
|
+
putOpt(map, LinkField.isDeepLink, d.field(LinkField.isDeepLink))
|
|
145
|
+
putOpt(map, LinkField.appleTeamId, d.appleTeamId)
|
|
146
|
+
putOpt(map, LinkField.iosBundleId, d.iosBundleId)
|
|
147
|
+
putOpt(map, LinkField.androidPackageName, d.androidPackageName)
|
|
148
|
+
putOpt(map, LinkField.resolvedPath, d.resolvedPath)
|
|
149
|
+
}
|
|
150
|
+
is LinkLookupResult.Failed -> {
|
|
151
|
+
map.putString("status", "failed")
|
|
152
|
+
map.putString("error", result.error)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
emitOrBuffer("CliqItLinkLookup", map) { pendingLinkLookup = it }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
CliqItSDK.onVerify { outcome ->
|
|
159
|
+
val map = Arguments.createMap()
|
|
160
|
+
when (outcome) {
|
|
161
|
+
is VerifyOutcome.Passed -> {
|
|
162
|
+
map.putString("status", "ok")
|
|
163
|
+
map.putBoolean("ok", true)
|
|
164
|
+
putOpt(map, "appId", outcome.result.appId)
|
|
165
|
+
putOpt(map, "appName", outcome.result.appName)
|
|
166
|
+
map.putString("message", outcome.result.mismatchMessage)
|
|
167
|
+
map.putMap("checks", checksMap(outcome.result.checks))
|
|
168
|
+
map.putString("raw", outcome.result.rawJSON)
|
|
169
|
+
}
|
|
170
|
+
is VerifyOutcome.Mismatched -> {
|
|
171
|
+
map.putString("status", "mismatch")
|
|
172
|
+
map.putBoolean("ok", false)
|
|
173
|
+
putOpt(map, "appId", outcome.result.appId)
|
|
174
|
+
putOpt(map, "appName", outcome.result.appName)
|
|
175
|
+
map.putString("message", outcome.result.mismatchMessage)
|
|
176
|
+
map.putMap("checks", checksMap(outcome.result.checks))
|
|
177
|
+
map.putString("raw", outcome.result.rawJSON)
|
|
178
|
+
}
|
|
179
|
+
is VerifyOutcome.Error -> {
|
|
180
|
+
map.putString("status", "failed")
|
|
181
|
+
map.putBoolean("ok", false)
|
|
182
|
+
map.putString("error", outcome.message)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
emitOrBuffer("CliqItVerify", map) { pendingVerify = it }
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private fun checksMap(checks: Map<String, com.cliqit.sdk.VerifyCheck>): WritableMap {
|
|
190
|
+
val out = Arguments.createMap()
|
|
191
|
+
checks.forEach { (key, check) ->
|
|
192
|
+
val item = Arguments.createMap()
|
|
193
|
+
putOpt(item, "actual", check.actual)
|
|
194
|
+
putOpt(item, "expected", check.expected)
|
|
195
|
+
item.putBoolean("match", check.match)
|
|
196
|
+
out.putMap(key, item)
|
|
197
|
+
}
|
|
198
|
+
return out
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private fun emitOrBuffer(
|
|
202
|
+
event: String,
|
|
203
|
+
body: WritableMap,
|
|
204
|
+
buffer: (WritableMap) -> Unit,
|
|
205
|
+
) {
|
|
206
|
+
if (hasListeners) {
|
|
207
|
+
sendEvent(event, body)
|
|
208
|
+
} else {
|
|
209
|
+
buffer(body)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private fun flushPending() {
|
|
214
|
+
pendingDeepLink?.let {
|
|
215
|
+
pendingDeepLink = null
|
|
216
|
+
sendEvent("CliqItDeepLink", it)
|
|
217
|
+
}
|
|
218
|
+
pendingDeferredMatch?.let {
|
|
219
|
+
pendingDeferredMatch = null
|
|
220
|
+
sendEvent("CliqItDeferredMatch", it)
|
|
221
|
+
}
|
|
222
|
+
pendingLinkLookup?.let {
|
|
223
|
+
pendingLinkLookup = null
|
|
224
|
+
sendEvent("CliqItLinkLookup", it)
|
|
225
|
+
}
|
|
226
|
+
pendingVerify?.let {
|
|
227
|
+
pendingVerify = null
|
|
228
|
+
sendEvent("CliqItVerify", it)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private fun sendEvent(event: String, params: WritableMap) {
|
|
233
|
+
if (!reactContext.hasActiveReactInstance()) return
|
|
234
|
+
reactContext
|
|
235
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
236
|
+
.emit(event, params)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private fun putOpt(map: WritableMap, key: String, value: String?) {
|
|
240
|
+
if (value != null) map.putString(key, value) else map.putNull(key)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package com.cliqit
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class CliqItPackage : ReactPackage {
|
|
9
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
|
|
10
|
+
listOf(CliqItModule(reactContext))
|
|
11
|
+
|
|
12
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
|
|
13
|
+
emptyList()
|
|
14
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package com.cliqit.sdk
|
|
2
|
+
|
|
3
|
+
object CliqItDefaults {
|
|
4
|
+
const val SERVER_URL = "https://api.theblockyapp.com"
|
|
5
|
+
const val DEFERRED_MATCH_PATH = "api/v1/sdk/app/match"
|
|
6
|
+
const val LINK_LOOKUP_PATH = "api/v1/sdk/link"
|
|
7
|
+
const val VERIFY_PATH = "api/v1/sdk/verify"
|
|
8
|
+
const val API_KEY_HEADER = "x-api-key"
|
|
9
|
+
const val MAX_RETRY = 3
|
|
10
|
+
const val RETRY_INITIAL_DELAY_MS = 500L
|
|
11
|
+
|
|
12
|
+
const val PREFS = "cliqit_sdk"
|
|
13
|
+
const val KEY_MATCH_REPORTED = "com.cliqit.deferred.match.reported"
|
|
14
|
+
const val KEY_DEFERRED_DELIVERED = "com.cliqit.deferred.delivered"
|
|
15
|
+
/** When no explicit domain is configured, only this host + subdomains are accepted. */
|
|
16
|
+
const val ALLOWED_LINK_DOMAIN = "theblockyapp.com"
|
|
17
|
+
}
|