react-native-shield-fraud-plugin 1.0.11 → 2.0.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.
@@ -15,9 +15,6 @@ def isNewArchitectureEnabled() {
15
15
 
16
16
  apply plugin: "com.android.library"
17
17
 
18
-
19
- def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
20
-
21
18
  if (isNewArchitectureEnabled()) {
22
19
  apply plugin: "com.facebook.react"
23
20
  }
@@ -43,6 +40,7 @@ android {
43
40
  targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
44
41
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
45
42
  }
43
+
46
44
  buildTypes {
47
45
  release {
48
46
  minifyEnabled false
@@ -58,6 +56,18 @@ android {
58
56
  targetCompatibility JavaVersion.VERSION_1_8
59
57
  }
60
58
 
59
+ sourceSets {
60
+ main {
61
+ // Select the architecture-specific ShieldFraudPluginSpec shim at build time.
62
+ // - oldarch: extends ReactContextBaseJavaModule (Old Architecture / bridge)
63
+ // - newarch: extends the codegen-generated NativeShieldFraudPluginSpec (New Architecture)
64
+ if (isNewArchitectureEnabled()) {
65
+ java.srcDirs += ['src/newarch']
66
+ } else {
67
+ java.srcDirs += ['src/oldarch']
68
+ }
69
+ }
70
+ }
61
71
 
62
72
  if (isNewArchitectureEnabled()) {
63
73
  react {
@@ -70,27 +80,24 @@ android {
70
80
 
71
81
  rootProject.allprojects {
72
82
  repositories {
73
- mavenCentral()
74
- google()
75
- maven {
76
- url "https://cashshield-sdk.s3.amazonaws.com/release/"
77
- content {
78
- // Does only include this group
79
- includeGroup "com.shield.android"
80
- includeGroup "com.shield.android.module"
81
-
82
- }
83
- }
83
+ mavenCentral()
84
+ google()
85
+ maven {
86
+ url "https://cashshield-sdk.s3.amazonaws.com/release/"
87
+ content {
88
+ includeGroup "com.shield.android"
89
+ includeGroup "com.shield.android.module"
90
+ }
91
+ }
84
92
  }
85
93
  }
86
94
 
87
-
88
-
89
95
  dependencies {
90
96
  // For < 0.71, this will be from the local maven repo
91
97
  // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
92
98
  //noinspection GradleDynamicVersion
93
99
  implementation "com.facebook.react:react-native:+"
94
- implementation 'com.shield.android:shield-fraud:1.6.+'
95
- }
96
100
 
101
+ // Shield Fraud SDK 2.x — factory-based init, callback-based device intelligence
102
+ implementation 'com.shield.android:shield-fraud:2.4.0'
103
+ }
@@ -1,42 +1,79 @@
1
1
  package com.shieldfraudplugin;
2
2
 
3
- import android.app.Activity;
4
- import android.os.Handler;
5
- import android.os.Looper;
3
+ import android.app.Application;
6
4
 
7
5
  import androidx.annotation.NonNull;
6
+ import androidx.annotation.Nullable;
8
7
 
9
8
  import com.facebook.react.bridge.Arguments;
9
+ import com.facebook.react.bridge.Callback;
10
10
  import com.facebook.react.bridge.Promise;
11
11
  import com.facebook.react.bridge.ReactApplicationContext;
12
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
13
12
  import com.facebook.react.bridge.ReactMethod;
13
+ import com.facebook.react.bridge.ReadableMap;
14
+ import com.facebook.react.bridge.WritableArray;
14
15
  import com.facebook.react.bridge.WritableMap;
15
16
  import com.facebook.react.module.annotations.ReactModule;
16
-
17
- import com.facebook.react.bridge.Callback;
18
- import com.facebook.react.bridge.ReadableMap;
19
17
  import com.facebook.react.modules.core.DeviceEventManagerModule;
18
+
20
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;
21
24
  import com.shield.android.Shield;
22
- import com.shield.android.ShieldCallback;
23
- import com.shield.android.ShieldException;
24
- import com.shield.android.ShieldCrossPlatformParams;
25
+ import com.shield.android.ShieldConfig;
25
26
  import com.shield.android.ShieldCrossPlatformHelper;
27
+ import com.shield.android.ShieldCrossPlatformParams;
28
+ import com.shield.android.ShieldError;
29
+ import com.shield.android.ShieldFactory;
26
30
 
31
+ import org.json.JSONArray;
27
32
  import org.json.JSONObject;
28
33
 
29
34
  import java.util.HashMap;
35
+ import java.util.Iterator;
30
36
  import java.util.Map;
31
37
 
32
- import javax.annotation.Nonnull;
33
- import javax.annotation.Nullable;
34
-
38
+ /**
39
+ * ShieldFraudPlugin native module — Shield SDK 2.x (pure Java)
40
+ *
41
+ * SDK 2.x migration summary
42
+ * ─────────────────────────
43
+ * 1. Initialisation : Shield.Builder → ShieldConfig + ShieldFactory
44
+ * 2. Instance access : Shield.getInstance() → stored `shield` member
45
+ * 3. Session ID : Shield.getInstance().getSessionId() → shield.getSessionId()
46
+ * 4. Device results : setDeviceResultStateListener(callback)
47
+ * → ShieldFactory.createShieldWithCallback (SHIELD Sentinel)
48
+ * 5. sendAttributes : void return
49
+ * → shield.sendAttributesWithCallback (Result<String> callback)
50
+ * 6. LogLevel enum : Shield.LogLevel.VERBOSE/DEBUG/INFO/NONE
51
+ * → LogLevel.DEBUG / INFO / NONE (VERBOSE removed)
52
+ * 7. Environment enum : String constants ENVIRONMENT_PROD / DEV / STAGING
53
+ * → Environment.PROD / DEV (STAGING removed)
54
+ *
55
+ * Architecture segmentation
56
+ * ─────────────────────────
57
+ * Handled by Gradle source sets (not #ifdef).
58
+ * src/oldarch/ShieldFraudPluginSpec.java → extends ReactContextBaseJavaModule
59
+ * src/newarch/ShieldFraudPluginSpec.java → extends NativeShieldFraudPluginSpec (codegen)
60
+ * This module always extends ShieldFraudPluginSpec.
61
+ */
35
62
  @ReactModule(name = ShieldFraudPluginModule.NAME)
36
- public class ShieldFraudPluginModule extends ReactContextBaseJavaModule implements ShieldCallback<JSONObject> {
63
+ public class ShieldFraudPluginModule extends com.shieldfraudplugin.ShieldFraudPluginSpec {
64
+
37
65
  public static final String NAME = "ShieldFraudPlugin";
66
+
38
67
  private final ReactApplicationContext reactContext;
39
68
 
69
+ /**
70
+ * Stored Shield instance — created once by ShieldFactory in initShield().
71
+ * All subsequent calls use this reference instead of a singleton accessor.
72
+ */
73
+ @Nullable
74
+ private Shield shield = null;
75
+
76
+
40
77
  public ShieldFraudPluginModule(ReactApplicationContext reactContext) {
41
78
  super(reactContext);
42
79
  this.reactContext = reactContext;
@@ -48,164 +85,350 @@ public class ShieldFraudPluginModule extends ReactContextBaseJavaModule implemen
48
85
  return NAME;
49
86
  }
50
87
 
88
+ // =========================================================================
89
+ // Synchronous state queries
90
+ // =========================================================================
91
+
51
92
  @ReactMethod(isBlockingSynchronousMethod = true)
52
93
  public boolean isShieldInitialized() {
53
- try {
54
- return Shield.getInstance() != null;
55
- } catch (IllegalStateException e) {
56
- return false;
57
- }
94
+ return shield != null;
95
+ }
96
+
97
+ @ReactMethod(isBlockingSynchronousMethod = true)
98
+ public String getSessionId() {
99
+ return shield != null ? shield.getSessionId() : "";
58
100
  }
59
101
 
102
+ // =========================================================================
103
+ // SDK initialisation (Shield SDK 2.x — ShieldConfig + ShieldFactory)
104
+ //
105
+ // createShieldWithCallback both initialises the SDK and acts as the
106
+ // SHIELD Sentinel callback — it fires on the initial fingerprint and on
107
+ // every subsequent device intelligence update during the session.
108
+ //
109
+ // logLevel / environmentInfo arrive as `double` from both architectures:
110
+ // • Old Arch — JS bridge maps JS numbers to double.
111
+ // • New Arch — codegen generates double for TypeScript number params.
112
+ // =========================================================================
113
+
60
114
  @ReactMethod
61
- public void initShield(String siteID, String secretKey, Boolean isOptimizedListener, ReadableMap blockedDialog, Integer logLevel, Integer environment) {
115
+ public void initShield(
116
+ String siteID,
117
+ String secretKey,
118
+ boolean isOptimizedListener,
119
+ @Nullable ReadableMap blockedDialog,
120
+ double logLevel,
121
+ double environmentInfo,
122
+ boolean blockScreenRecording,
123
+ Promise promise) {
124
+
62
125
  if (isShieldInitialized()) {
126
+ promise.resolve(null);
63
127
  return;
64
128
  }
65
- Activity currentActivity = getCurrentActivity();
66
- if (currentActivity != null) {
67
- Shield.Builder builder = new Shield.Builder(currentActivity, siteID, secretKey)
68
- .setAutoBlockDialog(getBlockedDialogFromReadableMap(blockedDialog));
69
129
 
70
- if (isOptimizedListener) {
71
- builder.registerDeviceShieldCallback(this);
72
- }
130
+ Application application = (Application) reactContext.getApplicationContext();
131
+
132
+ ShieldConfig config = new ShieldConfig(siteID, secretKey);
133
+ config.setLogLevel(getLogLevelFromInt((int) logLevel));
134
+ config.setEnvironment(getEnvironmentFromInt((int) environmentInfo));
73
135
 
74
- String environmentString = getEnvironmentStringFromInteger(environment);
75
- builder.setEnvironment(environmentString);
136
+ if (blockedDialog != null) {
137
+ String title = blockedDialog.hasKey("title") ? blockedDialog.getString("title") : null;
138
+ String body = blockedDialog.hasKey("body") ? blockedDialog.getString("body") : null;
139
+ config.setBlockedDialog(new BlockedDialog(title, body));
140
+ }
76
141
 
77
- Shield.LogLevel logLevelEnum = getLogLevelEnumFromInteger(logLevel);
78
- builder.setLogLevel(logLevelEnum);
142
+ // blockScreenRecording is Android-only. JS always sends a real boolean
143
+ // (true/false, never null) so the Old Arch bridge can safely read it as
144
+ // a primitive. Defaults to false when the user doesn't set it in Config.
145
+ config.setBlockScreenRecording(blockScreenRecording);
79
146
 
80
- Shield shield = builder.build();
81
- Shield.setSingletonInstance(shield);
147
+ if (isOptimizedListener) {
148
+ // SDK 2.x: createShieldWithCallback initialises + acts as the Sentinel.
149
+ // Unlike 1.x (which required a separate setDeviceResultStateListener() call
150
+ // on the SDK), 2.x fires this callback automatically when device intelligence
151
+ // is ready and on every subsequent risk-profile change.
152
+ // The callback may arrive on a background thread — always post to main looper.
153
+ shield = ShieldFactory.createShieldWithCallback(
154
+ application,
155
+ config,
156
+ result -> new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
157
+ if (result instanceof Result.Success) {
158
+ DeviceIntelligence di =
159
+ ((Result.Success<DeviceIntelligence>) result).getData();
160
+ JSONObject json = di != null ? di.getData() : null;
161
+ emitEvent("success", json != null ? json.toString() : null);
162
+ } else if (result instanceof Result.Failure) {
163
+ ShieldError error =
164
+ ((Result.Failure<DeviceIntelligence>) result).getError();
165
+ emitEvent("error", error.getErrorMessage());
166
+ }
167
+ }));
168
+ } else {
169
+ // createShield = initialise without the real-time Sentinel callback.
170
+ // Use getLatestDeviceResult() to poll on demand instead.
171
+ shield = ShieldFactory.createShield(application, config);
82
172
  }
173
+
174
+ promise.resolve(null);
83
175
  }
84
176
 
177
+ // =========================================================================
178
+ // Cross-platform metadata
179
+ // =========================================================================
180
+
85
181
  @ReactMethod
86
182
  public void setCrossPlatformParameters(String crossPlatformName, String crossPlatformVersion) {
87
- ShieldCrossPlatformParams params = new ShieldCrossPlatformParams(crossPlatformName, crossPlatformVersion);
183
+ ShieldCrossPlatformParams params =
184
+ new ShieldCrossPlatformParams(crossPlatformName, crossPlatformVersion);
88
185
  ShieldCrossPlatformHelper.setCrossPlatformParameters(params);
89
186
  }
90
187
 
91
- private BlockedDialog getBlockedDialogFromReadableMap(ReadableMap blockedDialog) {
92
- if (blockedDialog != null) {
93
- String title = blockedDialog.hasKey("title") ? blockedDialog.getString("title") : null;
94
- String body = blockedDialog.hasKey("body") ? blockedDialog.getString("body") : null;
95
- return new BlockedDialog(title, body);
96
- }
97
- return null;
188
+ // =========================================================================
189
+ // setDeviceResultStateListener — no-op stub (SDK 2.x)
190
+ //
191
+ // SDK 1.x required a manual subscription call + Handler.postDelayed workaround.
192
+ // SDK 2.x fires device result events automatically via createShieldWithCallback
193
+ // when isOptimizedListener == true — no subscription call needed.
194
+ //
195
+ // The method is kept as a no-op stub so the shared TypeScript codegen spec
196
+ // and iOS (which still calls the SDK method) remain unaffected.
197
+ // =========================================================================
198
+
199
+ @ReactMethod
200
+ public void setDeviceResultStateListener() {
201
+ // No-op on Android SDK 2.x — device result events are delivered
202
+ // automatically through the createShieldWithCallback Sentinel.
98
203
  }
99
204
 
100
- private String getEnvironmentStringFromInteger(Integer environment) {
101
- String environmentString;
102
- switch (environment) {
103
- case 1:
104
- environmentString = Shield.ENVIRONMENT_DEV;
105
- break;
106
- case 2:
107
- environmentString = Shield.ENVIRONMENT_STAGING;
108
- break;
109
- default:
110
- environmentString = Shield.ENVIRONMENT_PROD;
111
- break;
205
+ // =========================================================================
206
+ // Retrieve the latest device intelligence result
207
+ //
208
+ // Returns Shield SDK's latest device result payload.
209
+ // =========================================================================
210
+
211
+ @ReactMethod
212
+ public void getLatestDeviceResult(Callback successCallback, Callback errorCallback) {
213
+ if (shield == null) {
214
+ errorCallback.invoke("Shield SDK is not initialized.");
215
+ return;
112
216
  }
113
- return environmentString;
114
- }
115
217
 
116
- private Shield.LogLevel getLogLevelEnumFromInteger(Integer logLevel) {
117
- Shield.LogLevel logLevelEnum;
118
- switch (logLevel) {
119
- case 1:
120
- logLevelEnum = Shield.LogLevel.NONE;
121
- break;
122
- case 2:
123
- logLevelEnum = Shield.LogLevel.INFO;
124
- break;
125
- case 3:
126
- logLevelEnum = Shield.LogLevel.DEBUG;
127
- break;
128
- default:
129
- logLevelEnum = Shield.LogLevel.VERBOSE;
130
- break;
218
+ JSONObject json = shield.getLatestDeviceResult();
219
+ if (json == null) {
220
+ errorCallback.invoke("No device result available yet.");
221
+ return;
131
222
  }
132
- return logLevelEnum;
223
+
224
+ successCallback.invoke(toWritableMap(json));
133
225
  }
134
226
 
227
+ // =========================================================================
228
+ // Send user / screen attributes (Shield SDK 2.x — sendAttributesWithCallback)
229
+ //
230
+ // sendAttributesWithCallback delivers a Result<String> where the String
231
+ // is the sessionId on success.
232
+ // =========================================================================
233
+
135
234
  @ReactMethod
136
- public void setDeviceResultStateListener() {
137
- new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
138
- @Override
139
- public void run() {
140
- Shield.getInstance().setDeviceResultStateListener(new Shield.DeviceResultStateListener() {
141
- @Override
142
- public void isReady() {
143
- // Emit an event when the device is ready
144
- WritableMap params = Arguments.createMap();
145
- params.putString("status", "isSDKReady");
146
- reactContext
147
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
148
- .emit("device_result_state", params);
149
- }
150
- });
235
+ public void sendAttributes(String screenName, ReadableMap json) {
236
+ if (shield == null) return;
237
+
238
+ Map<String, String> data = toStringMap(json);
239
+
240
+ shield.sendAttributesWithCallback(screenName, data, result -> {
241
+ if (result instanceof Result.Failure) {
242
+ ShieldError error = ((Result.Failure<String>) result).getError();
243
+ emitEvent("error", error.getErrorMessage());
151
244
  }
152
- }, 1500);
245
+ });
153
246
  }
154
247
 
248
+ @ReactMethod
249
+ public void sendAttributesWithCallback(
250
+ String screenName,
251
+ ReadableMap json,
252
+ Callback successCallback,
253
+ Callback errorCallback) {
254
+ if (shield == null) {
255
+ errorCallback.invoke("Shield SDK is not initialized.");
256
+ return;
257
+ }
155
258
 
156
- @ReactMethod(isBlockingSynchronousMethod = true)
157
- public String getSessionId() {
158
- return Shield.getInstance().getSessionId();
259
+ Map<String, String> data = toStringMap(json);
260
+ shield.sendAttributesWithCallback(screenName, data, result ->
261
+ new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
262
+ if (result instanceof Result.Success) {
263
+ successCallback.invoke(true);
264
+ } else if (result instanceof Result.Failure) {
265
+ ShieldError error = ((Result.Failure<String>) result).getError();
266
+ String errorMessage = error != null
267
+ ? error.getErrorMessage()
268
+ : "Failed to send attributes.";
269
+ errorCallback.invoke(errorMessage);
270
+ }
271
+ })
272
+ );
159
273
  }
160
274
 
161
- @Override
162
- public void onSuccess(@Nullable JSONObject jsonObject) {
163
- if (jsonObject != null) {
164
- reactContext
165
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
166
- .emit("success", jsonObject.toString());
275
+ // =========================================================================
276
+ // Send device signature
277
+ //
278
+ // Triggers a device signature computation for the given screen name.
279
+ // On success the SDK calls back with the session ID (String); the latest
280
+ // device result JSONObject is then retrieved via shield.getLatestDeviceResult().
281
+ // =========================================================================
282
+
283
+ @ReactMethod
284
+ public void sendDeviceSignature(
285
+ String screenName,
286
+ Callback successCallback,
287
+ Callback errorCallback) {
288
+ if (shield == null) {
289
+ errorCallback.invoke("Shield SDK is not initialized.");
290
+ return;
167
291
  }
292
+
293
+ shield.sendDeviceSignatureWithCallback(screenName, result ->
294
+ new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
295
+ if (result instanceof Result.Success) {
296
+ JSONObject json = shield.getLatestDeviceResult();
297
+ successCallback.invoke(json != null ? toWritableMap(json) : null);
298
+ } else if (result instanceof Result.Failure) {
299
+ ShieldError error = ((Result.Failure<String>) result).getError();
300
+ errorCallback.invoke(error != null
301
+ ? error.getErrorMessage()
302
+ : "Failed to send device signature.");
303
+ }
304
+ })
305
+ );
168
306
  }
169
307
 
308
+ // =========================================================================
309
+ // RCTEventEmitter stubs — required for compatibility on both architectures
310
+ // =========================================================================
311
+
312
+ @ReactMethod
313
+ public void addListener(String eventName) {}
314
+
315
+ @ReactMethod
316
+ public void removeListeners(double count) {}
317
+
318
+ // =========================================================================
319
+ // Module teardown
320
+ // =========================================================================
321
+
170
322
  @Override
171
- public void onFailure(@Nullable ShieldException e) {
172
- if (e != null) {
173
- reactContext
174
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
175
- .emit("error", e.getLocalizedMessage());
176
- }
323
+ public void invalidate() {
324
+ // Do not call super.invalidate() — ReactContextBaseJavaModule does not
325
+ // declare invalidate() as a concrete method in older React Native versions
326
+ // (it is only on the NativeModule interface), so super.invalidate() fails
327
+ // to compile. Our own cleanup is all that is needed here.
328
+ shield = null;
329
+ }
330
+
331
+ // =========================================================================
332
+ // Internal helpers
333
+ // =========================================================================
177
334
 
335
+ private void emitEvent(String eventName, Object data) {
336
+ reactContext
337
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
338
+ .emit(eventName, data);
178
339
  }
179
340
 
180
- @ReactMethod
181
- public void sendAttributes(String screenName, ReadableMap json) {
182
- HashMap<String, String> data = new HashMap<String, String>();
341
+ private Map<String, String> toStringMap(ReadableMap json) {
342
+ Map<String, String> data = new HashMap<>();
183
343
  for (Map.Entry<String, Object> entry : json.toHashMap().entrySet()) {
184
- data.put(entry.getKey(), (String) entry.getValue());
344
+ if (entry.getValue() instanceof String) {
345
+ data.put(entry.getKey(), (String) entry.getValue());
346
+ }
185
347
  }
186
- Shield.getInstance().sendAttributes(screenName, data);
348
+ return data;
187
349
  }
188
350
 
189
- @ReactMethod
190
- public void getLatestDeviceResult(Callback successCallback, Callback errorCallback) {
191
- Shield shieldInstance = Shield.getInstance();
192
- JSONObject deviceResult = shieldInstance.getLatestDeviceResult();
193
-
194
- if (deviceResult != null) {
195
- successCallback.invoke(deviceResult.toString());
351
+ private WritableMap toWritableMap(JSONObject jsonObject) {
352
+ WritableMap map = Arguments.createMap();
353
+ Iterator<String> keys = jsonObject.keys();
354
+ while (keys.hasNext()) {
355
+ String key = keys.next();
356
+ putValueInMap(map, key, jsonObject.opt(key));
357
+ }
358
+ return map;
359
+ }
360
+
361
+ private WritableArray toWritableArray(JSONArray jsonArray) {
362
+ WritableArray array = Arguments.createArray();
363
+ for (int i = 0; i < jsonArray.length(); i++) {
364
+ pushValueInArray(array, jsonArray.opt(i));
365
+ }
366
+ return array;
367
+ }
368
+
369
+ private void putValueInMap(WritableMap map, String key, Object value) {
370
+ if (value == null || value == JSONObject.NULL) {
371
+ map.putNull(key);
372
+ } else if (value instanceof Boolean) {
373
+ map.putBoolean(key, (Boolean) value);
374
+ } else if (value instanceof Number) {
375
+ map.putDouble(key, ((Number) value).doubleValue());
376
+ } else if (value instanceof JSONObject) {
377
+ map.putMap(key, toWritableMap((JSONObject) value));
378
+ } else if (value instanceof JSONArray) {
379
+ map.putArray(key, toWritableArray((JSONArray) value));
196
380
  } else {
197
- ShieldException error = shieldInstance.getResponseError();
198
- String errorMessage = (error != null) ? error.getMessage() : "unknown error";
199
- errorCallback.invoke(errorMessage);
381
+ map.putString(key, String.valueOf(value));
200
382
  }
201
- }
202
- @ReactMethod
203
- public void addListener(String eventName) {
204
- // Code to handle adding listeners
205
383
  }
206
-
207
- @ReactMethod
208
- public void removeListeners(int count) {
209
- // Code to handle removing listeners
384
+
385
+ private void pushValueInArray(WritableArray array, Object value) {
386
+ if (value == null || value == JSONObject.NULL) {
387
+ array.pushNull();
388
+ } else if (value instanceof Boolean) {
389
+ array.pushBoolean((Boolean) value);
390
+ } else if (value instanceof Number) {
391
+ array.pushDouble(((Number) value).doubleValue());
392
+ } else if (value instanceof JSONObject) {
393
+ array.pushMap(toWritableMap((JSONObject) value));
394
+ } else if (value instanceof JSONArray) {
395
+ array.pushArray(toWritableArray((JSONArray) value));
396
+ } else {
397
+ array.pushString(String.valueOf(value));
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Maps JS logLevel integer → Shield SDK LogLevel enum.
403
+ *
404
+ * JS LogLevel enum values (src/index.tsx):
405
+ * LogLevelVerbose = 4 → LogLevel.VERBOSE
406
+ * LogLevelDebug = 3 → LogLevel.DEBUG
407
+ * LogLevelInfo = 2 → LogLevel.INFO
408
+ * LogLevelNone = 1 → LogLevel.NONE (default)
409
+ */
410
+ private LogLevel getLogLevelFromInt(int logLevel) {
411
+ switch (logLevel) {
412
+ case 4: return LogLevel.VERBOSE;
413
+ case 3: return LogLevel.DEBUG;
414
+ case 2: return LogLevel.INFO;
415
+ default: return LogLevel.NONE;
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Maps JS environmentInfo integer → Shield SDK Environment enum.
421
+ *
422
+ * JS EnvironmentInfo enum values (src/index.tsx):
423
+ * EnvironmentProd = 0 → Environment.PROD (default)
424
+ * EnvironmentDev = 1 → Environment.DEV
425
+ * EnvironmentStaging = 2 → Environment.STAGING
426
+ */
427
+ private Environment getEnvironmentFromInt(int environment) {
428
+ switch (environment) {
429
+ case 1: return Environment.DEV;
430
+ case 2: return Environment.STAGING;
431
+ default: return Environment.PROD;
432
+ }
210
433
  }
211
434
  }