react-native-shield-full-plugin 2.3.0
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/LICENSE +20 -0
- package/README.md +237 -0
- package/android/build.gradle +109 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/com/shieldfraudplugin/ShieldFraudPluginModule.java +441 -0
- package/android/src/main/java/com/shieldfraudplugin/ShieldFraudPluginPackage.java +78 -0
- package/android/src/newarch/java/com/shieldfraudplugin/ShieldFraudPluginSpec.java +41 -0
- package/android/src/oldarch/java/com/shieldfraudplugin/ShieldFraudPluginSpec.java +36 -0
- package/ios/ShieldFraudPlugin.h +24 -0
- package/ios/ShieldFraudPlugin.mm +295 -0
- package/ios/ShieldFraudPlugin.xcodeproj/project.pbxproj +282 -0
- package/ios/ShieldFraudPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata +4 -0
- package/lib/commonjs/NativeShieldFraudPlugin.js +15 -0
- package/lib/commonjs/NativeShieldFraudPlugin.js.map +1 -0
- package/lib/commonjs/index.js +256 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/module/NativeShieldFraudPlugin.js +10 -0
- package/lib/module/NativeShieldFraudPlugin.js.map +1 -0
- package/lib/module/index.js +253 -0
- package/lib/module/index.js.map +1 -0
- package/lib/typescript/src/NativeShieldFraudPlugin.d.ts +53 -0
- package/lib/typescript/src/NativeShieldFraudPlugin.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +143 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +169 -0
- package/react-native-shield-fraud-plugin.podspec +29 -0
- package/react-native-shield-full-plugin.podspec +29 -0
- package/src/NativeShieldFraudPlugin.ts +87 -0
- package/src/index.tsx +334 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
package com.shieldfraudplugin;
|
|
2
|
+
|
|
3
|
+
import android.app.Application;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
import androidx.annotation.Nullable;
|
|
7
|
+
|
|
8
|
+
import com.facebook.react.bridge.Arguments;
|
|
9
|
+
import com.facebook.react.bridge.Callback;
|
|
10
|
+
import com.facebook.react.bridge.Promise;
|
|
11
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
12
|
+
import com.facebook.react.bridge.ReactMethod;
|
|
13
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
14
|
+
import com.facebook.react.bridge.WritableArray;
|
|
15
|
+
import com.facebook.react.bridge.WritableMap;
|
|
16
|
+
import com.facebook.react.module.annotations.ReactModule;
|
|
17
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
18
|
+
|
|
19
|
+
import com.shield.android.BlockedDialog;
|
|
20
|
+
import com.shield.android.DeviceIntelligence;
|
|
21
|
+
import com.shield.android.Environment;
|
|
22
|
+
import com.shield.android.LogLevel;
|
|
23
|
+
import com.shield.android.Result;
|
|
24
|
+
import com.shield.android.Shield;
|
|
25
|
+
import com.shield.android.ShieldConfig;
|
|
26
|
+
import com.shield.android.ShieldCrossPlatformHelper;
|
|
27
|
+
import com.shield.android.ShieldCrossPlatformParams;
|
|
28
|
+
import com.shield.android.ShieldError;
|
|
29
|
+
import com.shield.android.ShieldFactory;
|
|
30
|
+
import com.shield.android.ShieldUserData;
|
|
31
|
+
|
|
32
|
+
import org.json.JSONArray;
|
|
33
|
+
import org.json.JSONObject;
|
|
34
|
+
|
|
35
|
+
import java.util.HashMap;
|
|
36
|
+
import java.util.Iterator;
|
|
37
|
+
import java.util.Map;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* ShieldFraudPlugin native module — Shield SDK 2.x (pure Java)
|
|
41
|
+
*
|
|
42
|
+
* SDK 2.x migration summary
|
|
43
|
+
* ─────────────────────────
|
|
44
|
+
* 1. Initialisation : Shield.Builder → ShieldConfig + ShieldFactory
|
|
45
|
+
* 2. Instance access : Shield.getInstance() → stored `shield` member
|
|
46
|
+
* 3. Session ID : Shield.getInstance().getSessionId() → shield.getSessionId()
|
|
47
|
+
* 4. Device results : setDeviceResultStateListener(callback)
|
|
48
|
+
* → ShieldFactory.createShieldWithCallback (SHIELD Sentinel)
|
|
49
|
+
* 5. sendAttributes : void return
|
|
50
|
+
* → shield.sendAttributesWithCallback (Result<String> callback)
|
|
51
|
+
* 6. LogLevel enum : Shield.LogLevel.VERBOSE/DEBUG/INFO/NONE
|
|
52
|
+
* → LogLevel.VERBOSE / DEBUG / INFO / NONE
|
|
53
|
+
* 7. Environment enum : String constants ENVIRONMENT_PROD / DEV / STAGING
|
|
54
|
+
* → Environment.PROD / DEV / STAGING
|
|
55
|
+
*
|
|
56
|
+
* Architecture segmentation
|
|
57
|
+
* ─────────────────────────
|
|
58
|
+
* Handled by Gradle source sets (not #ifdef).
|
|
59
|
+
* src/oldarch/ShieldFraudPluginSpec.java → extends ReactContextBaseJavaModule
|
|
60
|
+
* src/newarch/ShieldFraudPluginSpec.java → extends NativeShieldFraudPluginSpec (codegen)
|
|
61
|
+
* This module always extends ShieldFraudPluginSpec.
|
|
62
|
+
*/
|
|
63
|
+
@ReactModule(name = ShieldFraudPluginModule.NAME)
|
|
64
|
+
public class ShieldFraudPluginModule extends com.shieldfraudplugin.ShieldFraudPluginSpec {
|
|
65
|
+
|
|
66
|
+
public static final String NAME = "ShieldFraudPlugin";
|
|
67
|
+
|
|
68
|
+
private final ReactApplicationContext reactContext;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Stored Shield instance — created once by ShieldFactory in initShield().
|
|
72
|
+
* All subsequent calls use this reference instead of a singleton accessor.
|
|
73
|
+
*/
|
|
74
|
+
@Nullable
|
|
75
|
+
private Shield shield = null;
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
public ShieldFraudPluginModule(ReactApplicationContext reactContext) {
|
|
79
|
+
super(reactContext);
|
|
80
|
+
this.reactContext = reactContext;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@Override
|
|
84
|
+
@NonNull
|
|
85
|
+
public String getName() {
|
|
86
|
+
return NAME;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// =========================================================================
|
|
90
|
+
// Synchronous state queries
|
|
91
|
+
// =========================================================================
|
|
92
|
+
|
|
93
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
94
|
+
public boolean isShieldInitialized() {
|
|
95
|
+
return shield != null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
99
|
+
public String getSessionId() {
|
|
100
|
+
return shield != null ? shield.getSessionId() : "";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// =========================================================================
|
|
104
|
+
// SDK initialisation (Shield SDK 2.x — ShieldConfig + ShieldFactory)
|
|
105
|
+
//
|
|
106
|
+
// createShieldWithCallback both initialises the SDK and acts as the
|
|
107
|
+
// SHIELD Sentinel callback — it fires on the initial fingerprint and on
|
|
108
|
+
// every subsequent device intelligence update during the session.
|
|
109
|
+
//
|
|
110
|
+
// logLevel / environmentInfo arrive as `double` from both architectures:
|
|
111
|
+
// • Old Arch — JS bridge maps JS numbers to double.
|
|
112
|
+
// • New Arch — codegen generates double for TypeScript number params.
|
|
113
|
+
// =========================================================================
|
|
114
|
+
|
|
115
|
+
@ReactMethod
|
|
116
|
+
public void initShield(
|
|
117
|
+
String siteID,
|
|
118
|
+
String secretKey,
|
|
119
|
+
boolean isOptimizedListener,
|
|
120
|
+
@Nullable ReadableMap blockedDialog,
|
|
121
|
+
double logLevel,
|
|
122
|
+
double environmentInfo,
|
|
123
|
+
boolean blockScreenRecording,
|
|
124
|
+
Promise promise) {
|
|
125
|
+
|
|
126
|
+
if (isShieldInitialized()) {
|
|
127
|
+
promise.resolve(null);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
Application application = (Application) reactContext.getApplicationContext();
|
|
132
|
+
|
|
133
|
+
ShieldConfig config = new ShieldConfig(siteID, secretKey);
|
|
134
|
+
config.setLogLevel(getLogLevelFromInt((int) logLevel));
|
|
135
|
+
config.setEnvironment(getEnvironmentFromInt((int) environmentInfo));
|
|
136
|
+
|
|
137
|
+
if (blockedDialog != null) {
|
|
138
|
+
String title = blockedDialog.hasKey("title") ? blockedDialog.getString("title") : null;
|
|
139
|
+
String body = blockedDialog.hasKey("body") ? blockedDialog.getString("body") : null;
|
|
140
|
+
config.setBlockedDialog(new BlockedDialog(title, body));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// blockScreenRecording is Android-only. JS always sends a real boolean
|
|
144
|
+
// (true/false, never null) so the Old Arch bridge can safely read it as
|
|
145
|
+
// a primitive. Defaults to false when the user doesn't set it in Config.
|
|
146
|
+
config.setBlockScreenRecording(blockScreenRecording);
|
|
147
|
+
|
|
148
|
+
if (isOptimizedListener) {
|
|
149
|
+
// SDK 2.x: createShieldWithCallback initialises + acts as the Sentinel.
|
|
150
|
+
// Unlike 1.x (which required a separate setDeviceResultStateListener() call
|
|
151
|
+
// on the SDK), 2.x fires this callback automatically when device intelligence
|
|
152
|
+
// is ready and on every subsequent risk-profile change.
|
|
153
|
+
// The callback may arrive on a background thread — always post to main looper.
|
|
154
|
+
shield = ShieldFactory.createShieldWithCallback(
|
|
155
|
+
application,
|
|
156
|
+
config,
|
|
157
|
+
result -> new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
|
158
|
+
if (result instanceof Result.Success) {
|
|
159
|
+
DeviceIntelligence di =
|
|
160
|
+
((Result.Success<DeviceIntelligence>) result).getData();
|
|
161
|
+
JSONObject json = di != null ? di.getData() : null;
|
|
162
|
+
emitEvent("success", json != null ? json.toString() : null);
|
|
163
|
+
} else if (result instanceof Result.Failure) {
|
|
164
|
+
ShieldError error =
|
|
165
|
+
((Result.Failure<DeviceIntelligence>) result).getError();
|
|
166
|
+
emitEvent("error", error.getErrorMessage());
|
|
167
|
+
}
|
|
168
|
+
}));
|
|
169
|
+
} else {
|
|
170
|
+
// createShield = initialise without the real-time Sentinel callback.
|
|
171
|
+
// Use getLatestDeviceResult() to poll on demand instead.
|
|
172
|
+
shield = ShieldFactory.createShield(application, config);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
promise.resolve(null);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// =========================================================================
|
|
179
|
+
// Cross-platform metadata
|
|
180
|
+
// =========================================================================
|
|
181
|
+
|
|
182
|
+
@ReactMethod
|
|
183
|
+
public void setCrossPlatformParameters(String crossPlatformName, String crossPlatformVersion) {
|
|
184
|
+
ShieldCrossPlatformParams params =
|
|
185
|
+
new ShieldCrossPlatformParams(crossPlatformName, crossPlatformVersion);
|
|
186
|
+
ShieldCrossPlatformHelper.setCrossPlatformParameters(params);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// =========================================================================
|
|
190
|
+
// setDeviceResultStateListener — no-op stub (SDK 2.x)
|
|
191
|
+
//
|
|
192
|
+
// SDK 1.x required a manual subscription call + Handler.postDelayed workaround.
|
|
193
|
+
// SDK 2.x fires device result events automatically via createShieldWithCallback
|
|
194
|
+
// when isOptimizedListener == true — no subscription call needed.
|
|
195
|
+
//
|
|
196
|
+
// The method is kept as a no-op stub so the shared TypeScript codegen spec
|
|
197
|
+
// and iOS (which still calls the SDK method) remain unaffected.
|
|
198
|
+
// =========================================================================
|
|
199
|
+
|
|
200
|
+
@ReactMethod
|
|
201
|
+
public void setDeviceResultStateListener() {
|
|
202
|
+
// No-op on Android SDK 2.x — device result events are delivered
|
|
203
|
+
// automatically through the createShieldWithCallback Sentinel.
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// =========================================================================
|
|
207
|
+
// Retrieve the latest device intelligence result
|
|
208
|
+
//
|
|
209
|
+
// Returns Shield SDK's latest device result payload.
|
|
210
|
+
// =========================================================================
|
|
211
|
+
|
|
212
|
+
@ReactMethod
|
|
213
|
+
public void getLatestDeviceResult(Callback successCallback, Callback errorCallback) {
|
|
214
|
+
if (shield == null) {
|
|
215
|
+
errorCallback.invoke("Shield SDK is not initialized.");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
JSONObject json = shield.getLatestDeviceResult();
|
|
220
|
+
if (json == null) {
|
|
221
|
+
errorCallback.invoke("No device result available yet.");
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
successCallback.invoke(toWritableMap(json));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// =========================================================================
|
|
229
|
+
// Send user / screen attributes (Shield SDK 2.x — sendAttributesWithCallback)
|
|
230
|
+
//
|
|
231
|
+
// sendAttributesWithCallback delivers a Result<String> where the String
|
|
232
|
+
// is the sessionId on success.
|
|
233
|
+
// =========================================================================
|
|
234
|
+
|
|
235
|
+
@ReactMethod
|
|
236
|
+
public void sendAttributes(String screenName, ReadableMap json) {
|
|
237
|
+
if (shield == null) return;
|
|
238
|
+
|
|
239
|
+
Map<String, String> data = toStringMap(json);
|
|
240
|
+
|
|
241
|
+
shield.sendAttributesWithCallback(screenName, data, result -> {
|
|
242
|
+
if (result instanceof Result.Failure) {
|
|
243
|
+
ShieldError error = ((Result.Failure<String>) result).getError();
|
|
244
|
+
emitEvent("error", error.getErrorMessage());
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@ReactMethod
|
|
250
|
+
public void sendAttributesWithCallback(
|
|
251
|
+
String screenName,
|
|
252
|
+
ReadableMap json,
|
|
253
|
+
Callback successCallback,
|
|
254
|
+
Callback errorCallback) {
|
|
255
|
+
if (shield == null) {
|
|
256
|
+
errorCallback.invoke("Shield SDK is not initialized.");
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
Map<String, String> data = toStringMap(json);
|
|
261
|
+
shield.sendAttributesWithCallback(screenName, data, result ->
|
|
262
|
+
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
|
263
|
+
if (result instanceof Result.Success) {
|
|
264
|
+
successCallback.invoke(true);
|
|
265
|
+
} else if (result instanceof Result.Failure) {
|
|
266
|
+
ShieldError error = ((Result.Failure<String>) result).getError();
|
|
267
|
+
String errorMessage = error != null
|
|
268
|
+
? error.getErrorMessage()
|
|
269
|
+
: "Failed to send attributes.";
|
|
270
|
+
errorCallback.invoke(errorMessage);
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// =========================================================================
|
|
277
|
+
// Send device signature
|
|
278
|
+
//
|
|
279
|
+
// Triggers a device signature computation for the given screen name.
|
|
280
|
+
// On success the SDK calls back with the session ID (String); the latest
|
|
281
|
+
// device result JSONObject is then retrieved via shield.getLatestDeviceResult().
|
|
282
|
+
// =========================================================================
|
|
283
|
+
|
|
284
|
+
@ReactMethod
|
|
285
|
+
public void sendDeviceSignature(
|
|
286
|
+
String screenName,
|
|
287
|
+
@Nullable String userId,
|
|
288
|
+
Callback successCallback,
|
|
289
|
+
Callback errorCallback) {
|
|
290
|
+
if (shield == null) {
|
|
291
|
+
errorCallback.invoke("Shield SDK is not initialized.");
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
ShieldUserData userData = new ShieldUserData(screenName);
|
|
296
|
+
if (userId != null) {
|
|
297
|
+
userData.setUserId(userId);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
shield.sendDeviceSignatureWithCallback(userData, result ->
|
|
301
|
+
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
|
302
|
+
if (result instanceof Result.Success) {
|
|
303
|
+
JSONObject json = shield.getLatestDeviceResult();
|
|
304
|
+
successCallback.invoke(json != null ? toWritableMap(json) : null);
|
|
305
|
+
} else if (result instanceof Result.Failure) {
|
|
306
|
+
ShieldError error = ((Result.Failure<String>) result).getError();
|
|
307
|
+
errorCallback.invoke(error != null
|
|
308
|
+
? error.getErrorMessage()
|
|
309
|
+
: "Failed to send device signature.");
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// =========================================================================
|
|
316
|
+
// RCTEventEmitter stubs — required for compatibility on both architectures
|
|
317
|
+
// =========================================================================
|
|
318
|
+
|
|
319
|
+
@ReactMethod
|
|
320
|
+
public void addListener(String eventName) {}
|
|
321
|
+
|
|
322
|
+
@ReactMethod
|
|
323
|
+
public void removeListeners(double count) {}
|
|
324
|
+
|
|
325
|
+
// =========================================================================
|
|
326
|
+
// Module teardown
|
|
327
|
+
// =========================================================================
|
|
328
|
+
|
|
329
|
+
@Override
|
|
330
|
+
public void invalidate() {
|
|
331
|
+
// Do not call super.invalidate() — ReactContextBaseJavaModule does not
|
|
332
|
+
// declare invalidate() as a concrete method in older React Native versions
|
|
333
|
+
// (it is only on the NativeModule interface), so super.invalidate() fails
|
|
334
|
+
// to compile. Our own cleanup is all that is needed here.
|
|
335
|
+
shield = null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// =========================================================================
|
|
339
|
+
// Internal helpers
|
|
340
|
+
// =========================================================================
|
|
341
|
+
|
|
342
|
+
private void emitEvent(String eventName, Object data) {
|
|
343
|
+
reactContext
|
|
344
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
345
|
+
.emit(eventName, data);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
private Map<String, String> toStringMap(ReadableMap json) {
|
|
349
|
+
Map<String, String> data = new HashMap<>();
|
|
350
|
+
for (Map.Entry<String, Object> entry : json.toHashMap().entrySet()) {
|
|
351
|
+
if (entry.getValue() instanceof String) {
|
|
352
|
+
data.put(entry.getKey(), (String) entry.getValue());
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return data;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
private WritableMap toWritableMap(JSONObject jsonObject) {
|
|
359
|
+
WritableMap map = Arguments.createMap();
|
|
360
|
+
Iterator<String> keys = jsonObject.keys();
|
|
361
|
+
while (keys.hasNext()) {
|
|
362
|
+
String key = keys.next();
|
|
363
|
+
putValueInMap(map, key, jsonObject.opt(key));
|
|
364
|
+
}
|
|
365
|
+
return map;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
private WritableArray toWritableArray(JSONArray jsonArray) {
|
|
369
|
+
WritableArray array = Arguments.createArray();
|
|
370
|
+
for (int i = 0; i < jsonArray.length(); i++) {
|
|
371
|
+
pushValueInArray(array, jsonArray.opt(i));
|
|
372
|
+
}
|
|
373
|
+
return array;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
private void putValueInMap(WritableMap map, String key, Object value) {
|
|
377
|
+
if (value == null || value == JSONObject.NULL) {
|
|
378
|
+
map.putNull(key);
|
|
379
|
+
} else if (value instanceof Boolean) {
|
|
380
|
+
map.putBoolean(key, (Boolean) value);
|
|
381
|
+
} else if (value instanceof Number) {
|
|
382
|
+
map.putDouble(key, ((Number) value).doubleValue());
|
|
383
|
+
} else if (value instanceof JSONObject) {
|
|
384
|
+
map.putMap(key, toWritableMap((JSONObject) value));
|
|
385
|
+
} else if (value instanceof JSONArray) {
|
|
386
|
+
map.putArray(key, toWritableArray((JSONArray) value));
|
|
387
|
+
} else {
|
|
388
|
+
map.putString(key, String.valueOf(value));
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
private void pushValueInArray(WritableArray array, Object value) {
|
|
393
|
+
if (value == null || value == JSONObject.NULL) {
|
|
394
|
+
array.pushNull();
|
|
395
|
+
} else if (value instanceof Boolean) {
|
|
396
|
+
array.pushBoolean((Boolean) value);
|
|
397
|
+
} else if (value instanceof Number) {
|
|
398
|
+
array.pushDouble(((Number) value).doubleValue());
|
|
399
|
+
} else if (value instanceof JSONObject) {
|
|
400
|
+
array.pushMap(toWritableMap((JSONObject) value));
|
|
401
|
+
} else if (value instanceof JSONArray) {
|
|
402
|
+
array.pushArray(toWritableArray((JSONArray) value));
|
|
403
|
+
} else {
|
|
404
|
+
array.pushString(String.valueOf(value));
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Maps JS logLevel integer → Shield SDK LogLevel enum.
|
|
410
|
+
*
|
|
411
|
+
* JS LogLevel enum values (src/index.tsx):
|
|
412
|
+
* LogLevelVerbose = 4 → LogLevel.VERBOSE
|
|
413
|
+
* LogLevelDebug = 3 → LogLevel.DEBUG
|
|
414
|
+
* LogLevelInfo = 2 → LogLevel.INFO
|
|
415
|
+
* LogLevelNone = 1 → LogLevel.NONE (default)
|
|
416
|
+
*/
|
|
417
|
+
private LogLevel getLogLevelFromInt(int logLevel) {
|
|
418
|
+
switch (logLevel) {
|
|
419
|
+
case 4: return LogLevel.VERBOSE;
|
|
420
|
+
case 3: return LogLevel.DEBUG;
|
|
421
|
+
case 2: return LogLevel.INFO;
|
|
422
|
+
default: return LogLevel.NONE;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Maps JS environmentInfo integer → Shield SDK Environment enum.
|
|
428
|
+
*
|
|
429
|
+
* JS EnvironmentInfo enum values (src/index.tsx):
|
|
430
|
+
* EnvironmentProd = 0 → Environment.PROD (default)
|
|
431
|
+
* EnvironmentDev = 1 → Environment.DEV
|
|
432
|
+
* EnvironmentStaging = 2 → Environment.STAGING
|
|
433
|
+
*/
|
|
434
|
+
private Environment getEnvironmentFromInt(int environment) {
|
|
435
|
+
switch (environment) {
|
|
436
|
+
case 1: return Environment.DEV;
|
|
437
|
+
case 2: return Environment.STAGING;
|
|
438
|
+
default: return Environment.PROD;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
package com.shieldfraudplugin;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
|
|
5
|
+
import com.facebook.react.TurboReactPackage;
|
|
6
|
+
import com.facebook.react.bridge.NativeModule;
|
|
7
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
8
|
+
import com.facebook.react.module.model.ReactModuleInfo;
|
|
9
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider;
|
|
10
|
+
|
|
11
|
+
import java.util.HashMap;
|
|
12
|
+
import java.util.Map;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Package registration for ShieldFraudPlugin — works on both architectures.
|
|
16
|
+
*
|
|
17
|
+
* Why TurboReactPackage instead of ReactPackage
|
|
18
|
+
* ─────────────────────────────────────────────
|
|
19
|
+
* TurboReactPackage is a drop-in replacement for the legacy ReactPackage that
|
|
20
|
+
* adds support for Turbo Modules (New Architecture) while remaining fully
|
|
21
|
+
* backward-compatible with the Old Architecture bridge.
|
|
22
|
+
*
|
|
23
|
+
* On Old Architecture the isTurboModule flag in ReactModuleInfo is simply
|
|
24
|
+
* ignored and the module is loaded via the bridge as normal.
|
|
25
|
+
* On New Architecture the flag tells the runtime to resolve the module through
|
|
26
|
+
* the Turbo Module system (JSI) instead of the bridge.
|
|
27
|
+
*
|
|
28
|
+
* The isTurboModule flag is driven by BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
|
|
29
|
+
* which build.gradle sets to true/false based on the newArchEnabled property:
|
|
30
|
+
*
|
|
31
|
+
* buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED",
|
|
32
|
+
* isNewArchitectureEnabled().toString()
|
|
33
|
+
*/
|
|
34
|
+
public class ShieldFraudPluginPackage extends TurboReactPackage {
|
|
35
|
+
|
|
36
|
+
// =========================================================================
|
|
37
|
+
// Module instantiation
|
|
38
|
+
// =========================================================================
|
|
39
|
+
|
|
40
|
+
@Override
|
|
41
|
+
public NativeModule getModule(@NonNull String name,
|
|
42
|
+
@NonNull ReactApplicationContext reactContext) {
|
|
43
|
+
if (name.equals(ShieldFraudPluginModule.NAME)) {
|
|
44
|
+
return new ShieldFraudPluginModule(reactContext);
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// =========================================================================
|
|
50
|
+
// Module metadata
|
|
51
|
+
//
|
|
52
|
+
// ReactModuleInfoProvider returns the metadata the runtime needs to decide
|
|
53
|
+
// how to load the module:
|
|
54
|
+
// • Old Arch → isTurboModule=false → loaded via JS bridge
|
|
55
|
+
// • New Arch → isTurboModule=true → loaded via JSI (Turbo Module)
|
|
56
|
+
// =========================================================================
|
|
57
|
+
|
|
58
|
+
@Override
|
|
59
|
+
public ReactModuleInfoProvider getReactModuleInfoProvider() {
|
|
60
|
+
return () -> {
|
|
61
|
+
final boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
|
62
|
+
Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
|
|
63
|
+
moduleInfos.put(
|
|
64
|
+
ShieldFraudPluginModule.NAME,
|
|
65
|
+
new ReactModuleInfo(
|
|
66
|
+
ShieldFraudPluginModule.NAME, // name
|
|
67
|
+
ShieldFraudPluginModule.NAME, // className
|
|
68
|
+
false, // canOverrideExistingModule
|
|
69
|
+
false, // needsEagerInit
|
|
70
|
+
false, // hasConstants
|
|
71
|
+
false, // isCxxModule
|
|
72
|
+
isTurboModule // isTurboModule
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
return moduleInfos;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package com.shieldfraudplugin;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* New Architecture base class for ShieldFraudPluginModule.
|
|
7
|
+
*
|
|
8
|
+
* Selected by Gradle when newArchEnabled=true.
|
|
9
|
+
* Extends NativeShieldFraudPluginSpec — the abstract class generated by React
|
|
10
|
+
* Native's codegen from the TypeScript spec at src/NativeShieldFraudPlugin.ts.
|
|
11
|
+
*
|
|
12
|
+
* How the source-set swap works
|
|
13
|
+
* ─────────────────────────────
|
|
14
|
+
* build.gradle adds either src/oldarch or src/newarch to the Java source
|
|
15
|
+
* directories depending on the newArchEnabled project property:
|
|
16
|
+
*
|
|
17
|
+
* sourceSets {
|
|
18
|
+
* main {
|
|
19
|
+
* if (isNewArchitectureEnabled()) {
|
|
20
|
+
* java.srcDirs += ['src/newarch'] // this file is included
|
|
21
|
+
* } else {
|
|
22
|
+
* java.srcDirs += ['src/oldarch'] // this file is excluded
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* ShieldFraudPluginModule (in src/main/) always extends ShieldFraudPluginSpec,
|
|
28
|
+
* so it compiles correctly regardless of which shim is selected.
|
|
29
|
+
*
|
|
30
|
+
* NativeShieldFraudPluginSpec is generated at build time by the React Native
|
|
31
|
+
* Gradle plugin (com.facebook.react) when New Architecture is enabled.
|
|
32
|
+
* It declares all methods from the TypeScript spec as abstract — this shim
|
|
33
|
+
* exists purely to bridge the inheritance chain so ShieldFraudPluginModule
|
|
34
|
+
* does not need to import the codegen class directly.
|
|
35
|
+
*/
|
|
36
|
+
abstract class ShieldFraudPluginSpec extends NativeShieldFraudPluginSpec {
|
|
37
|
+
|
|
38
|
+
protected ShieldFraudPluginSpec(ReactApplicationContext context) {
|
|
39
|
+
super(context);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package com.shieldfraudplugin;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
4
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Old Architecture base class for ShieldFraudPluginModule.
|
|
8
|
+
*
|
|
9
|
+
* Selected by Gradle when newArchEnabled=false (the default).
|
|
10
|
+
* Extends ReactContextBaseJavaModule — the standard base class for modules
|
|
11
|
+
* that communicate with JS over the legacy bridge.
|
|
12
|
+
*
|
|
13
|
+
* How the source-set swap works
|
|
14
|
+
* ─────────────────────────────
|
|
15
|
+
* build.gradle adds either src/oldarch or src/newarch to the Java source
|
|
16
|
+
* directories depending on the newArchEnabled project property:
|
|
17
|
+
*
|
|
18
|
+
* sourceSets {
|
|
19
|
+
* main {
|
|
20
|
+
* if (isNewArchitectureEnabled()) {
|
|
21
|
+
* java.srcDirs += ['src/newarch'] // this file is excluded
|
|
22
|
+
* } else {
|
|
23
|
+
* java.srcDirs += ['src/oldarch'] // this file is included
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* ShieldFraudPluginModule (in src/main/) always extends ShieldFraudPluginSpec,
|
|
29
|
+
* so it compiles correctly regardless of which shim is selected.
|
|
30
|
+
*/
|
|
31
|
+
abstract class ShieldFraudPluginSpec extends ReactContextBaseJavaModule {
|
|
32
|
+
|
|
33
|
+
protected ShieldFraudPluginSpec(ReactApplicationContext context) {
|
|
34
|
+
super(context);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
3
|
+
// New Architecture: conform to the codegen-generated spec protocol.
|
|
4
|
+
// RCTEventEmitter is still used as the base so that sendEventWithName: works.
|
|
5
|
+
#import <React/RCTEventEmitter.h>
|
|
6
|
+
#import "RNShieldFraudPluginSpec.h"
|
|
7
|
+
|
|
8
|
+
// Forward-declare the protocol — the full definition is imported in the .mm file.
|
|
9
|
+
// A forward declaration is sufficient for the @interface conformance declaration.
|
|
10
|
+
@protocol DeviceShieldCallback;
|
|
11
|
+
|
|
12
|
+
@interface ShieldFraudPlugin : RCTEventEmitter <NativeShieldFraudPluginSpec, DeviceShieldCallback>
|
|
13
|
+
#else
|
|
14
|
+
// Old Architecture: standard bridge module + event emitter.
|
|
15
|
+
#import <React/RCTBridgeModule.h>
|
|
16
|
+
#import <React/RCTEventEmitter.h>
|
|
17
|
+
|
|
18
|
+
// Forward-declare the protocol — full definition imported in the .mm file.
|
|
19
|
+
@protocol DeviceShieldCallback;
|
|
20
|
+
|
|
21
|
+
@interface ShieldFraudPlugin : RCTEventEmitter <RCTBridgeModule, DeviceShieldCallback>
|
|
22
|
+
#endif
|
|
23
|
+
|
|
24
|
+
@end
|