@truewatchtech/react-native-mobile 0.3.15 → 0.3.16

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.
Files changed (43) hide show
  1. package/FTMobileReactNativeSDK.podspec +1 -1
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/ft/sdk/reactnative/FTMobileImpl.java +424 -5
  4. package/android/src/main/java/com/ft/sdk/reactnative/FTRUMImpl.java +12 -0
  5. package/android/src/newarch/java/com/ft/sdk/reactnative/FTMobileModule.java +23 -1
  6. package/android/src/oldarch/java/com/ft/sdk/reactnative/FTMobileModule.java +24 -2
  7. package/ios/FTMobileReactNative.h +2 -2
  8. package/ios/FTMobileReactNative.m +358 -4
  9. package/ios/FTReactNativeRUM.m +9 -0
  10. package/lib/commonjs/ft_logger.js +5 -2
  11. package/lib/commonjs/ft_logger.js.map +1 -1
  12. package/lib/commonjs/ft_mobile_agent.js +142 -3
  13. package/lib/commonjs/ft_mobile_agent.js.map +1 -1
  14. package/lib/commonjs/ft_rum.js +40 -13
  15. package/lib/commonjs/ft_rum.js.map +1 -1
  16. package/lib/commonjs/ft_tracing.js.map +1 -1
  17. package/lib/commonjs/index.js +30 -0
  18. package/lib/commonjs/index.js.map +1 -1
  19. package/lib/commonjs/version.js +1 -1
  20. package/lib/commonjs/version.js.map +1 -1
  21. package/lib/module/ft_logger.js +5 -2
  22. package/lib/module/ft_logger.js.map +1 -1
  23. package/lib/module/ft_mobile_agent.js +142 -3
  24. package/lib/module/ft_mobile_agent.js.map +1 -1
  25. package/lib/module/ft_rum.js +39 -9
  26. package/lib/module/ft_rum.js.map +1 -1
  27. package/lib/module/ft_tracing.js.map +1 -1
  28. package/lib/module/index.js +3 -3
  29. package/lib/module/index.js.map +1 -1
  30. package/lib/module/version.js +1 -1
  31. package/lib/module/version.js.map +1 -1
  32. package/lib/typescript/ft_mobile_agent.d.ts +140 -2
  33. package/lib/typescript/ft_rum.d.ts +24 -0
  34. package/lib/typescript/index.d.ts +3 -3
  35. package/lib/typescript/version.d.ts +1 -1
  36. package/package.json +1 -1
  37. package/src/ft_logger.tsx +6 -2
  38. package/src/ft_mobile_agent.tsx +217 -8
  39. package/src/ft_rum.tsx +66 -9
  40. package/src/ft_tracing.tsx +21 -2
  41. package/src/index.tsx +6 -5
  42. package/src/version.ts +1 -1
  43. package/android/src/main/java/com/ft/sdk/InnerClassProxy.java +0 -8
@@ -18,5 +18,5 @@ Pod::Spec.new do |s|
18
18
 
19
19
 
20
20
  s.dependency "React-Core"
21
- s.dependency 'FTMobileSDK', '1.5.18'
21
+ s.dependency 'FTMobileSDK', '1.5.20'
22
22
  end
@@ -177,7 +177,7 @@ repositories {
177
177
  dependencies {
178
178
  // noinspection GradleDynamicVersion
179
179
  implementation 'com.facebook.react:react-native:+'
180
- implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-sdk:1.6.13'
180
+ implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-sdk:1.6.17'
181
181
  implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-native:1.1.2'
182
182
  implementation 'com.google.code.gson:gson:2.8.5'
183
183
  }
@@ -2,23 +2,341 @@ package com.ft.sdk.reactnative;
2
2
 
3
3
  import static com.ft.sdk.garble.utils.Constants.FT_LOG_DEFAULT_MEASUREMENT;
4
4
 
5
+ import androidx.annotation.Nullable;
6
+
7
+ import com.facebook.react.bridge.Arguments;
5
8
  import com.facebook.react.bridge.Promise;
9
+ import com.facebook.react.bridge.ReactApplicationContext;
10
+ import com.facebook.react.bridge.ReadableArray;
6
11
  import com.facebook.react.bridge.ReadableMap;
12
+ import com.facebook.react.bridge.ReadableType;
13
+ import com.facebook.react.bridge.WritableArray;
14
+ import com.facebook.react.bridge.WritableMap;
15
+ import com.facebook.react.modules.core.DeviceEventManagerModule;
7
16
  import com.ft.sdk.DBCacheDiscard;
8
17
  import com.ft.sdk.EnvType;
18
+ import com.ft.sdk.FTRemoteConfigManager;
9
19
  import com.ft.sdk.FTSDKConfig;
10
20
  import com.ft.sdk.FTSdk;
11
- import com.ft.sdk.InnerClassProxy;
12
21
  import com.ft.sdk.LineDataModifier;
22
+ import com.ft.sdk.garble.bean.RemoteConfigBean;
13
23
  import com.ft.sdk.garble.bean.UserData;
14
24
  import com.ft.sdk.DataModifier;
15
25
  import com.ft.sdk.reactnative.utils.ReactNativeUtils;
16
26
 
17
27
  import java.util.HashMap;
28
+ import java.util.ArrayList;
29
+ import java.util.List;
18
30
  import java.util.Map;
31
+ import org.json.JSONArray;
32
+ import org.json.JSONException;
33
+ import org.json.JSONObject;
19
34
 
20
35
  public class FTMobileImpl {
21
36
  public static final String NAME = "FTMobileReactNative";
37
+ private static final String REMOTE_CONFIG_EVENT = "ft_remote_config_callback";
38
+ private final ReactApplicationContext reactContext;
39
+ private boolean remoteConfigurationEnabled = false;
40
+ private int remoteConfigMiniUpdateInterval = 12 * 60 * 60;
41
+ @Nullable
42
+ private ReadableArray remoteConfigOverrideRules;
43
+
44
+ public FTMobileImpl(ReactApplicationContext reactContext) {
45
+ this.reactContext = reactContext;
46
+ }
47
+
48
+ private static class RemoteConfigOverrideResult {
49
+ final RemoteConfigBean configBean;
50
+ final List<String> appliedRuleIds;
51
+
52
+ RemoteConfigOverrideResult(RemoteConfigBean configBean, List<String> appliedRuleIds) {
53
+ this.configBean = configBean;
54
+ this.appliedRuleIds = appliedRuleIds;
55
+ }
56
+ }
57
+
58
+ private WritableMap createRemoteConfigPayload(String triggerType,
59
+ boolean success,
60
+ @Nullable String rawJson,
61
+ @Nullable List<String> appliedRuleIds,
62
+ @Nullable String errorCode,
63
+ @Nullable String errorMessage) {
64
+ WritableMap payload = Arguments.createMap();
65
+ payload.putString("triggerType", triggerType);
66
+ payload.putBoolean("success", success);
67
+ payload.putString("platform", "android");
68
+ payload.putDouble("timestamp", System.currentTimeMillis());
69
+ if (rawJson != null) {
70
+ payload.putString("rawJson", rawJson);
71
+ }
72
+ if (appliedRuleIds != null && !appliedRuleIds.isEmpty()) {
73
+ WritableArray ids = Arguments.createArray();
74
+ for (String ruleId : appliedRuleIds) {
75
+ ids.pushString(ruleId);
76
+ }
77
+ payload.putArray("appliedOverrideRuleIds", ids);
78
+ }
79
+ if (errorCode != null) {
80
+ payload.putString("errorCode", errorCode);
81
+ }
82
+ if (errorMessage != null) {
83
+ payload.putString("errorMessage", errorMessage);
84
+ }
85
+ return payload;
86
+ }
87
+
88
+ private void emitRemoteConfigEvent(boolean success, @Nullable String rawJson,
89
+ @Nullable List<String> appliedRuleIds,
90
+ @Nullable String errorCode, @Nullable String errorMessage) {
91
+ if (!reactContext.hasActiveCatalystInstance()) {
92
+ return;
93
+ }
94
+ reactContext
95
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
96
+ .emit(REMOTE_CONFIG_EVENT, createRemoteConfigPayload("auto", success, rawJson, appliedRuleIds, errorCode, errorMessage));
97
+ }
98
+
99
+ private RemoteConfigOverrideResult applyRemoteConfigOverrideRules(RemoteConfigBean configBean,
100
+ @Nullable String jsonConfig) {
101
+ return applyRemoteConfigOverrideRules(configBean, jsonConfig, this.remoteConfigOverrideRules);
102
+ }
103
+
104
+ private RemoteConfigOverrideResult applyRemoteConfigOverrideRules(RemoteConfigBean configBean,
105
+ @Nullable String jsonConfig,
106
+ @Nullable ReadableArray rules) {
107
+ if (configBean == null || jsonConfig == null || rules == null || rules.size() == 0) {
108
+ return new RemoteConfigOverrideResult(configBean, new ArrayList<>());
109
+ }
110
+ List<String> appliedRuleIds = new ArrayList<>();
111
+ try {
112
+ JSONObject jsonObject = new JSONObject(jsonConfig);
113
+ for (int i = 0; i < rules.size(); i++) {
114
+ if (rules.getType(i) != ReadableType.Map) {
115
+ continue;
116
+ }
117
+ ReadableMap rule = rules.getMap(i);
118
+ boolean enabled = !rule.hasKey("enabled") || rule.isNull("enabled") || rule.getBoolean("enabled");
119
+ if (!enabled) {
120
+ continue;
121
+ }
122
+ ReadableMap match = rule.hasKey("match") && !rule.isNull("match") ? rule.getMap("match") : null;
123
+ ReadableMap customKeys = match != null && match.hasKey("customKeys") && !match.isNull("customKeys")
124
+ ? match.getMap("customKeys") : null;
125
+ if (customKeys == null) {
126
+ continue;
127
+ }
128
+ HashMap<String, Object> keyMap = customKeys.toHashMap();
129
+ if (keyMap.isEmpty()) {
130
+ continue;
131
+ }
132
+ boolean matches = true;
133
+ for (Map.Entry<String, Object> entry : keyMap.entrySet()) {
134
+ Object expectedValue = entry.getValue();
135
+ Object actualValue = getJsonValue(jsonObject, entry.getKey());
136
+
137
+ if (!matchesCustomKey(actualValue, expectedValue)) {
138
+ matches = false;
139
+ break;
140
+ }
141
+ }
142
+ if (!matches) {
143
+ continue;
144
+ }
145
+ ReadableMap override = rule.hasKey("override") && !rule.isNull("override") ? rule.getMap("override") : null;
146
+ if (override == null) {
147
+ continue;
148
+ }
149
+
150
+ // Basic configuration properties
151
+ if (override.hasKey("env") && !override.isNull("env")) {
152
+ configBean.setEnv(override.getString("env"));
153
+ }
154
+ if (override.hasKey("serviceName") && !override.isNull("serviceName")) {
155
+ configBean.setServiceName(override.getString("serviceName"));
156
+ }
157
+ if (override.hasKey("autoSync") && !override.isNull("autoSync")) {
158
+ configBean.setAutoSync(override.getBoolean("autoSync"));
159
+ }
160
+ if (override.hasKey("compressIntakeRequests") && !override.isNull("compressIntakeRequests")) {
161
+ configBean.setCompressIntakeRequests(override.getBoolean("compressIntakeRequests"));
162
+ }
163
+ if (override.hasKey("syncPageSize") && !override.isNull("syncPageSize")) {
164
+ configBean.setSyncPageSize(override.getInt("syncPageSize"));
165
+ }
166
+ if (override.hasKey("syncSleepTime") && !override.isNull("syncSleepTime")) {
167
+ configBean.setSyncSleepTime(override.getInt("syncSleepTime"));
168
+ }
169
+
170
+ // Log configuration properties
171
+ if (override.hasKey("logSampleRate") && !override.isNull("logSampleRate")) {
172
+ configBean.setLogSampleRate((float) override.getDouble("logSampleRate"));
173
+ }
174
+ if (override.hasKey("logLevelFilters") && !override.isNull("logLevelFilters")) {
175
+ ReadableArray filtersArray = override.getArray("logLevelFilters");
176
+ String[] filters = new String[filtersArray.size()];
177
+ for (int j = 0; j < filtersArray.size(); j++) {
178
+ filters[j] = filtersArray.getString(j);
179
+ }
180
+ configBean.setLogLevelFilters(filters);
181
+ }
182
+ if (override.hasKey("logEnableCustomLog") && !override.isNull("logEnableCustomLog")) {
183
+ configBean.setLogEnableCustomLog(override.getBoolean("logEnableCustomLog"));
184
+ }
185
+ if (override.hasKey("logEnableConsoleLog") && !override.isNull("logEnableConsoleLog")) {
186
+ configBean.setLogEnableConsoleLog(override.getBoolean("logEnableConsoleLog"));
187
+ }
188
+
189
+ // RUM configuration properties
190
+ if (override.hasKey("rumSampleRate") && !override.isNull("rumSampleRate")) {
191
+ configBean.setRumSampleRate((float) override.getDouble("rumSampleRate"));
192
+ }
193
+ if (override.hasKey("rumSessionOnErrorSampleRate") && !override.isNull("rumSessionOnErrorSampleRate")) {
194
+ configBean.setRumSessionOnErrorSampleRate((float) override.getDouble("rumSessionOnErrorSampleRate"));
195
+ }
196
+ if (override.hasKey("rumEnableTraceUserAction") && !override.isNull("rumEnableTraceUserAction")) {
197
+ configBean.setRumEnableTraceUserAction(override.getBoolean("rumEnableTraceUserAction"));
198
+ }
199
+ if (override.hasKey("rumEnableTraceUserView") && !override.isNull("rumEnableTraceUserView")) {
200
+ configBean.setRumEnableTraceUserView(override.getBoolean("rumEnableTraceUserView"));
201
+ }
202
+ if (override.hasKey("rumEnableTraceUserResource") && !override.isNull("rumEnableTraceUserResource")) {
203
+ configBean.setRumEnableTraceUserResource(override.getBoolean("rumEnableTraceUserResource"));
204
+ }
205
+ if (override.hasKey("rumEnableResourceHostIP") && !override.isNull("rumEnableResourceHostIP")) {
206
+ configBean.setRumEnableResourceHostIP(override.getBoolean("rumEnableResourceHostIP"));
207
+ }
208
+ if (override.hasKey("rumEnableTrackAppUIBlock") && !override.isNull("rumEnableTrackAppUIBlock")) {
209
+ configBean.setRumEnableTrackAppUIBlock(override.getBoolean("rumEnableTrackAppUIBlock"));
210
+ }
211
+ if (override.hasKey("rumBlockDurationMs") && !override.isNull("rumBlockDurationMs")) {
212
+ configBean.setRumBlockDurationMs((long) override.getInt("rumBlockDurationMs"));
213
+ }
214
+ if (override.hasKey("rumEnableTrackAppCrash") && !override.isNull("rumEnableTrackAppCrash")) {
215
+ configBean.setRumEnableTrackAppCrash(override.getBoolean("rumEnableTrackAppCrash"));
216
+ }
217
+ if (override.hasKey("rumEnableTrackAppANR") && !override.isNull("rumEnableTrackAppANR")) {
218
+ configBean.setRumEnableTrackAppANR(override.getBoolean("rumEnableTrackAppANR"));
219
+ }
220
+ if (override.hasKey("rumEnableTraceWebView") && !override.isNull("rumEnableTraceWebView")) {
221
+ configBean.setRumEnableTraceWebView(override.getBoolean("rumEnableTraceWebView"));
222
+ }
223
+ if (override.hasKey("rumAllowWebViewHost") && !override.isNull("rumAllowWebViewHost")) {
224
+ ReadableArray hostsArray = override.getArray("rumAllowWebViewHost");
225
+ String[] hosts = new String[hostsArray.size()];
226
+ for (int j = 0; j < hostsArray.size(); j++) {
227
+ hosts[j] = hostsArray.getString(j);
228
+ }
229
+ configBean.setRumAllowWebViewHost(hosts);
230
+ }
231
+
232
+ // Trace configuration properties
233
+ if (override.hasKey("traceSampleRate") && !override.isNull("traceSampleRate")) {
234
+ configBean.setTraceSampleRate((float) override.getDouble("traceSampleRate"));
235
+ }
236
+ if (override.hasKey("traceEnableAutoTrace") && !override.isNull("traceEnableAutoTrace")) {
237
+ configBean.setTraceEnableAutoTrace(override.getBoolean("traceEnableAutoTrace"));
238
+ }
239
+ if (override.hasKey("traceType") && !override.isNull("traceType")) {
240
+ configBean.setTraceType(override.getString("traceType"));
241
+ }
242
+
243
+ String ruleId = rule.hasKey("id") && !rule.isNull("id") ? rule.getString("id") : null;
244
+ appliedRuleIds.add(ruleId != null ? ruleId : "rule_" + i);
245
+ }
246
+ } catch (JSONException ignored) {
247
+ }
248
+ return new RemoteConfigOverrideResult(configBean, appliedRuleIds);
249
+ }
250
+
251
+ private Object getJsonValue(JSONObject jsonObject, String key) {
252
+ if (!jsonObject.has(key)) {
253
+ return null;
254
+ }
255
+ try {
256
+ Object value = jsonObject.get(key);
257
+ if (value == JSONObject.NULL) {
258
+ return null;
259
+ }
260
+ return value;
261
+ } catch (JSONException e) {
262
+ return null;
263
+ }
264
+ }
265
+
266
+ private boolean isEqualValue(Object actual, Object expected) {
267
+ if (actual == null && expected == null) {
268
+ return true;
269
+ }
270
+ if (actual == null || expected == null) {
271
+ return false;
272
+ }
273
+
274
+ if (actual instanceof String actualString) {
275
+ Object normalizedActual = parseJsonStringIfNeeded(actualString);
276
+ if (normalizedActual != actual) {
277
+ return isEqualValue(normalizedActual, expected);
278
+ }
279
+ }
280
+
281
+ // Handle number comparison
282
+ if (actual instanceof Number && expected instanceof Number) {
283
+ return ((Number) actual).doubleValue() == ((Number) expected).doubleValue();
284
+ }
285
+
286
+ // Handle string comparison
287
+ if (actual instanceof String && expected instanceof String) {
288
+ return actual.equals(expected);
289
+ }
290
+
291
+ // Handle boolean comparison (JSON booleans are represented as Boolean in Java)
292
+ if (actual instanceof Boolean && expected instanceof Boolean) {
293
+ return actual.equals(expected);
294
+ }
295
+
296
+ // Fallback to string comparison
297
+ return actual.toString().equals(expected.toString());
298
+ }
299
+
300
+ private boolean matchesCustomKey(Object actual, Object expected) {
301
+ if (expected instanceof Map<?, ?> expectedMap && expectedMap.containsKey("contains")) {
302
+ return containsValue(actual, expectedMap.get("contains"));
303
+ }
304
+ return isEqualValue(actual, expected);
305
+ }
306
+
307
+ private boolean containsValue(Object actual, Object expectedValue) {
308
+ Object normalizedActual = actual instanceof String actualString
309
+ ? parseJsonStringIfNeeded(actualString)
310
+ : actual;
311
+
312
+ if (normalizedActual instanceof JSONArray actualArray) {
313
+ try {
314
+ for (int i = 0; i < actualArray.length(); i++) {
315
+ if (isEqualValue(actualArray.get(i), expectedValue)) {
316
+ return true;
317
+ }
318
+ }
319
+ } catch (JSONException ignored) {
320
+ return false;
321
+ }
322
+ }
323
+ return isEqualValue(normalizedActual, expectedValue);
324
+ }
325
+
326
+ private Object parseJsonStringIfNeeded(String value) {
327
+ String trimmedValue = value.trim();
328
+ if (trimmedValue.length() < 2) {
329
+ return value;
330
+ }
331
+ try {
332
+ if (trimmedValue.startsWith("[") && trimmedValue.endsWith("]")) {
333
+ return new JSONArray(trimmedValue);
334
+ }
335
+ } catch (JSONException ignored) {
336
+ return value;
337
+ }
338
+ return value;
339
+ }
22
340
 
23
341
  public void sdkConfig(ReadableMap context, Promise promise) {
24
342
  Map<String, Object> map = context.toHashMap();
@@ -37,9 +355,12 @@ public class FTMobileImpl {
37
355
  Boolean enableLimitWithDbSize = (Boolean) map.get("enableLimitWithDbSize");
38
356
  Long dbCacheLimit = ReactNativeUtils.convertToNativeLong(map.get("dbCacheLimit"));
39
357
  Integer dbDiscardStrategy = ReactNativeUtils.convertToNativeInt(map.get("dbDiscardStrategy"));
40
- String sdkPkgInfo = (String)map.get("pkgInfo");
41
358
  Map<String, Object> dataModifier = (Map<String, Object>) map.get("dataModifier");
42
359
  Map<String, Map<String,Object>> lineDataModifier = (Map<String, Map<String,Object>>) map.get("lineDataModifier");
360
+ Boolean remoteConfiguration = (Boolean) map.get("remoteConfiguration");
361
+ Integer remoteConfigMiniUpdateInterval = ReactNativeUtils.convertToNativeInt(map.get("remoteConfigMiniUpdateInterval"));
362
+ this.remoteConfigOverrideRules = context.hasKey("remoteConfigOverrideRules")
363
+ ? context.getArray("remoteConfigOverrideRules") : null;
43
364
 
44
365
  FTSDKConfig sdkConfig = (datakitUrl != null)
45
366
  ? FTSDKConfig.builder(datakitUrl)
@@ -103,9 +424,6 @@ public class FTMobileImpl {
103
424
  sdkConfig.setDbCacheDiscard(dbCacheDiscard);
104
425
  }
105
426
 
106
- if(sdkPkgInfo!=null){
107
- InnerClassProxy.addPkgInfo(sdkConfig,"reactnative",sdkPkgInfo);
108
- }
109
427
  if (dataModifier != null) {
110
428
  sdkConfig.setDataModifier(new DataModifier() {
111
429
  @Override
@@ -127,6 +445,40 @@ public class FTMobileImpl {
127
445
  }
128
446
  }
129
447
  );
448
+ }
449
+ if (remoteConfiguration != null) {
450
+ sdkConfig.setRemoteConfiguration(remoteConfiguration);
451
+ }
452
+ remoteConfigurationEnabled = sdkConfig.isRemoteConfiguration();
453
+ if (remoteConfigMiniUpdateInterval != null) {
454
+ sdkConfig.setRemoteConfigMiniUpdateInterval(remoteConfigMiniUpdateInterval);
455
+ this.remoteConfigMiniUpdateInterval = remoteConfigMiniUpdateInterval;
456
+ } else {
457
+ this.remoteConfigMiniUpdateInterval = sdkConfig.getRemoteConfigMiniUpdateInterval();
458
+ }
459
+ if (remoteConfigurationEnabled) {
460
+ sdkConfig.setRemoteConfigurationCallBack(new FTRemoteConfigManager.FetchResult() {
461
+ private String rawJson;
462
+ private List<String> appliedRuleIds = new ArrayList<>();
463
+
464
+ @Override
465
+ public RemoteConfigBean onConfigSuccessFetched(RemoteConfigBean configBean, String jsonConfig) {
466
+ rawJson = jsonConfig;
467
+ RemoteConfigOverrideResult result = applyRemoteConfigOverrideRules(configBean, jsonConfig);
468
+ appliedRuleIds = result.appliedRuleIds;
469
+ emitRemoteConfigEvent(true, configBean.toJsonString(), appliedRuleIds, null, null);
470
+ return result.configBean;
471
+ }
472
+
473
+ @Override
474
+ public void onResult(boolean success) {
475
+ if (!success) {
476
+ emitRemoteConfigEvent(false, rawJson, appliedRuleIds, "FETCH_FAILED", "Remote config update failed");
477
+ }
478
+ rawJson = null;
479
+ appliedRuleIds = new ArrayList<>();
480
+ }
481
+ });
130
482
  }
131
483
  FTSdk.install(sdkConfig);
132
484
  // LogUtils.d("configCheck","sdkConfig:"+new Gson().toJson(sdkConfig));
@@ -195,4 +547,71 @@ public class FTMobileImpl {
195
547
  FTSdk.clearAllData();
196
548
  promise.resolve(null);
197
549
  }
550
+
551
+ public void updateRemoteConfig(Promise promise) {
552
+ if (!remoteConfigurationEnabled) {
553
+ promise.reject("E_REMOTE_CONFIG_DISABLED", "Remote configuration is not enabled.");
554
+ return;
555
+ }
556
+ FTSdk.updateRemoteConfig(remoteConfigMiniUpdateInterval, new FTRemoteConfigManager.FetchResult() {
557
+ private String rawJson;
558
+ private List<String> appliedRuleIds = new ArrayList<>();
559
+
560
+ @Override
561
+ public RemoteConfigBean onConfigSuccessFetched(RemoteConfigBean configBean, String jsonConfig) {
562
+ rawJson = jsonConfig;
563
+ RemoteConfigOverrideResult result = applyRemoteConfigOverrideRules(configBean, jsonConfig);
564
+ appliedRuleIds = result.appliedRuleIds;
565
+ promise.resolve(createRemoteConfigPayload("manual", true, configBean.toJsonString(), appliedRuleIds, null, null));
566
+ return result.configBean;
567
+ }
568
+
569
+ @Override
570
+ public void onResult(boolean success) {
571
+ if (!success) {
572
+ promise.reject("E_REMOTE_CONFIG_UPDATE_FAILED", "Remote config update failed");
573
+ } else if (rawJson == null) {
574
+ promise.resolve(createRemoteConfigPayload("manual", true, null, appliedRuleIds, null, null));
575
+ }
576
+ }
577
+ });
578
+ }
579
+
580
+ public void updateRemoteConfigWithMiniUpdateInterval(int interval, @Nullable ReadableArray rules, Promise promise) {
581
+ if (!remoteConfigurationEnabled) {
582
+ promise.reject("E_REMOTE_CONFIG_DISABLED", "Remote configuration is not enabled.");
583
+ return;
584
+ }
585
+ FTSdk.updateRemoteConfig(interval, new FTRemoteConfigManager.FetchResult() {
586
+ private String rawJson;
587
+ private List<String> appliedRuleIds = new ArrayList<>();
588
+
589
+ @Override
590
+ public RemoteConfigBean onConfigSuccessFetched(RemoteConfigBean configBean, String jsonConfig) {
591
+ rawJson = jsonConfig;
592
+ ReadableArray rulesToApply = rules != null && rules.size() > 0 ? rules : remoteConfigOverrideRules;
593
+ RemoteConfigOverrideResult result = applyRemoteConfigOverrideRules(configBean, jsonConfig, rulesToApply);
594
+ appliedRuleIds = result.appliedRuleIds;
595
+ promise.resolve(createRemoteConfigPayload("manual", true, configBean.toJsonString(), appliedRuleIds, null, null));
596
+ return result.configBean;
597
+ }
598
+
599
+ @Override
600
+ public void onResult(boolean success) {
601
+ if (!success) {
602
+ promise.reject("E_REMOTE_CONFIG_UPDATE_FAILED", "Remote config update failed");
603
+ } else if (rawJson == null) {
604
+ promise.resolve(createRemoteConfigPayload("manual", true, null, appliedRuleIds, null, null));
605
+ }
606
+ }
607
+ });
608
+ }
609
+
610
+ public void addListener(String eventName) {
611
+ // Required for NativeEventEmitter. No-op because native does not need listener bookkeeping.
612
+ }
613
+
614
+ public void removeListeners(double count) {
615
+ // Required for NativeEventEmitter. No-op because native does not need listener bookkeeping.
616
+ }
198
617
  }
@@ -15,6 +15,7 @@ import com.ft.sdk.garble.bean.NetStatusBean;
15
15
  import com.ft.sdk.garble.bean.ResourceParams;
16
16
  import com.ft.sdk.reactnative.utils.ReactNativeUtils;
17
17
 
18
+ import java.util.ArrayList;
18
19
  import java.util.HashMap;
19
20
  import java.util.Map;
20
21
 
@@ -44,6 +45,8 @@ public class FTRUMImpl {
44
45
  Map<String, Object> globalContext = (Map<String, Object>) map.get("globalContext");
45
46
  Integer rumCacheLimitCount = ReactNativeUtils.convertToNativeInt(map.get("rumCacheLimitCount"));
46
47
  Integer rumDiscardStrategy = ReactNativeUtils.convertToNativeInt(map.get("rumDiscardStrategy"));
48
+ Boolean enableTraceWebView = (Boolean) map.get("enableTraceWebView");
49
+ ArrayList<String> allowWebViewHost = (ArrayList<String>) map.get("allowWebViewHost");
47
50
 
48
51
  FTRUMConfig rumConfig = new FTRUMConfig().setRumAppId(rumAppId);
49
52
  if (sampleRate != null) {
@@ -122,6 +125,15 @@ public class FTRUMImpl {
122
125
  }
123
126
  rumConfig.setRumCacheDiscardStrategy(rumCacheDiscard);
124
127
  }
128
+ if (enableTraceWebView != null) {
129
+ rumConfig.setEnableTraceWebView(enableTraceWebView);
130
+ }
131
+ if (allowWebViewHost != null) {
132
+ String[] allowWebViewHostArr = new String[allowWebViewHost.size()];
133
+ allowWebViewHost.toArray(allowWebViewHostArr);
134
+ rumConfig.setAllowWebViewHost(allowWebViewHostArr);
135
+ }
136
+
125
137
  FTSdk.initRUMWithConfig(rumConfig);
126
138
  //LogUtils.d("configCheck","rumConfig:"+new Gson().toJson(rumConfig));
127
139
  promise.resolve(null);
@@ -11,10 +11,11 @@ import com.facebook.react.bridge.ReadableMap;
11
11
  @ReactModule(name = FTMobileModule.NAME)
12
12
  public class FTMobileModule extends NativeFTMobileSpec {
13
13
  public static final String NAME = FTMobileImpl.NAME;
14
- private final FTMobileImpl impl = new FTMobileImpl();
14
+ private final FTMobileImpl impl;
15
15
 
16
16
  public FTMobileModule(ReactApplicationContext reactContext) {
17
17
  super(reactContext);
18
+ impl = new FTMobileImpl(reactContext);
18
19
  }
19
20
 
20
21
  @Override
@@ -66,4 +67,25 @@ public class FTMobileModule extends NativeFTMobileSpec {
66
67
  public void clearAllData(Promise promise) {
67
68
  impl.clearAllData(promise);
68
69
  }
70
+
71
+ @ReactMethod
72
+ public void updateRemoteConfig(Promise promise) {
73
+ impl.updateRemoteConfig(promise);
74
+ }
75
+
76
+ @ReactMethod
77
+ public void updateRemoteConfigWithMiniUpdateInterval(int interval, @Nullable ReadableArray rules, Promise promise) {
78
+ impl.updateRemoteConfigWithMiniUpdateInterval(interval, rules, promise);
79
+ }
80
+
81
+ @ReactMethod
82
+ public void addListener(String eventName) {
83
+ impl.addListener(eventName);
84
+ }
85
+
86
+ @ReactMethod
87
+ public void removeListeners(double count) {
88
+ impl.removeListeners(count);
89
+ }
90
+
69
91
  }
@@ -1,21 +1,23 @@
1
1
  package com.ft.sdk.reactnative;
2
2
 
3
3
  import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
4
5
 
5
6
  import com.facebook.react.bridge.Promise;
6
7
  import com.facebook.react.bridge.ReactApplicationContext;
7
8
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
8
9
  import com.facebook.react.bridge.ReactMethod;
10
+ import com.facebook.react.bridge.ReadableArray;
9
11
  import com.facebook.react.bridge.ReadableMap;
10
12
 
11
13
  public class FTMobileModule extends ReactContextBaseJavaModule {
14
+ private final FTMobileImpl impl;
12
15
 
13
16
  public FTMobileModule(ReactApplicationContext reactContext) {
14
17
  super(reactContext);
18
+ impl = new FTMobileImpl(reactContext);
15
19
  }
16
20
 
17
- private final FTMobileImpl impl = new FTMobileImpl();
18
-
19
21
  @ReactMethod
20
22
  public void sdkConfig(ReadableMap context, Promise promise) {
21
23
  impl.sdkConfig(context, promise);
@@ -61,6 +63,26 @@ public class FTMobileModule extends ReactContextBaseJavaModule {
61
63
  impl.clearAllData(promise);
62
64
  }
63
65
 
66
+ @ReactMethod
67
+ public void updateRemoteConfig(Promise promise) {
68
+ impl.updateRemoteConfig(promise);
69
+ }
70
+
71
+ @ReactMethod
72
+ public void updateRemoteConfigWithMiniUpdateInterval(int interval, @Nullable ReadableArray rules, Promise promise) {
73
+ impl.updateRemoteConfigWithMiniUpdateInterval(interval, rules, promise);
74
+ }
75
+
76
+ @ReactMethod
77
+ public void addListener(String eventName) {
78
+ impl.addListener(eventName);
79
+ }
80
+
81
+ @ReactMethod
82
+ public void removeListeners(double count) {
83
+ impl.removeListeners(count);
84
+ }
85
+
64
86
  @NonNull
65
87
  @Override
66
88
  public String getName() {
@@ -7,11 +7,11 @@
7
7
  //
8
8
 
9
9
  #import <Foundation/Foundation.h>
10
- #import <React/RCTBridgeModule.h>
10
+ #import <React/RCTEventEmitter.h>
11
11
 
12
12
  NS_ASSUME_NONNULL_BEGIN
13
13
 
14
- @interface FTMobileReactNative : NSObject<RCTBridgeModule>
14
+ @interface FTMobileReactNative : RCTEventEmitter<RCTBridgeModule>
15
15
 
16
16
  @end
17
17