@truewatchtech/react-native-mobile 0.4.3-alpha.2 → 0.4.3
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/FTMobileReactNativeSDK.podspec +1 -1
- package/README.md +0 -34
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/ft/sdk/reactnative/FTLogImpl.java +10 -2
- package/android/src/main/java/com/ft/sdk/reactnative/FTMobileImpl.java +45 -3
- package/android/src/main/java/com/ft/sdk/reactnative/FTRUMImpl.java +51 -9
- package/android/src/main/java/com/ft/sdk/reactnative/FTTraceImpl.java +5 -2
- package/android/src/main/java/com/ft/sdk/reactnative/ViewTiming.java +17 -0
- package/android/src/main/java/com/ft/sdk/reactnative/VisitorIdConfigMapper.java +50 -0
- package/android/src/newarch/java/com/ft/sdk/reactnative/FTMobileModule.java +5 -0
- package/android/src/newarch/java/com/ft/sdk/reactnative/FTRUMModule.java +18 -0
- package/android/src/oldarch/java/com/ft/sdk/reactnative/FTMobileModule.java +5 -0
- package/android/src/oldarch/java/com/ft/sdk/reactnative/FTRUMModule.java +15 -0
- package/android/src/test/java/com/ft/sdk/reactnative/FTMobileImplTest.java +53 -0
- package/ios/FTMobileReactNative.mm +37 -2
- package/ios/FTReactNativeLog.mm +7 -2
- package/ios/FTReactNativeRUM.mm +94 -4
- package/ios/FTReactNativeResource.m +6 -0
- package/ios/FTReactNativeTrace.mm +4 -2
- package/ios/FTReactNativeViewTiming.h +18 -0
- package/ios/FTWebSocketResourceData.h +4 -0
- package/ios/FTWebSocketResourceData.m +31 -0
- package/lib/commonjs/ft_logger.js +3 -1
- package/lib/commonjs/ft_logger.js.map +1 -1
- package/lib/commonjs/ft_mobile_agent.js +13 -1
- package/lib/commonjs/ft_mobile_agent.js.map +1 -1
- package/lib/commonjs/ft_rum.js +19 -3
- package/lib/commonjs/ft_rum.js.map +1 -1
- package/lib/commonjs/ft_tracing.js +2 -1
- package/lib/commonjs/ft_tracing.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/rum/FTRumViewTracking.js +147 -0
- package/lib/commonjs/rum/FTRumViewTracking.js.map +1 -0
- package/lib/commonjs/rum/FTRumWebSocketNative.js.map +1 -1
- package/lib/commonjs/rum/FTRumWebSocketTiming.js +19 -1
- package/lib/commonjs/rum/FTRumWebSocketTiming.js.map +1 -1
- package/lib/commonjs/rum/FTRumWebSocketTracking.js +7 -11
- package/lib/commonjs/rum/FTRumWebSocketTracking.js.map +1 -1
- package/lib/commonjs/specs/NativeFTMobileReactNative.js.map +1 -1
- package/lib/commonjs/specs/NativeFTReactNativeRUM.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/commonjs/version.js.map +1 -1
- package/lib/commonjs/visitorIdConfig.js +37 -0
- package/lib/commonjs/visitorIdConfig.js.map +1 -0
- package/lib/module/ft_logger.js +3 -1
- package/lib/module/ft_logger.js.map +1 -1
- package/lib/module/ft_mobile_agent.js +13 -1
- package/lib/module/ft_mobile_agent.js.map +1 -1
- package/lib/module/ft_rum.js +19 -3
- package/lib/module/ft_rum.js.map +1 -1
- package/lib/module/ft_tracing.js +2 -1
- package/lib/module/ft_tracing.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/rum/FTRumViewTracking.js +140 -0
- package/lib/module/rum/FTRumViewTracking.js.map +1 -0
- package/lib/module/rum/FTRumWebSocketNative.js.map +1 -1
- package/lib/module/rum/FTRumWebSocketTiming.js +19 -1
- package/lib/module/rum/FTRumWebSocketTiming.js.map +1 -1
- package/lib/module/rum/FTRumWebSocketTracking.js +7 -11
- package/lib/module/rum/FTRumWebSocketTracking.js.map +1 -1
- package/lib/module/specs/NativeFTMobileReactNative.js.map +1 -1
- package/lib/module/specs/NativeFTReactNativeRUM.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/module/version.js.map +1 -1
- package/lib/module/visitorIdConfig.js +31 -0
- package/lib/module/visitorIdConfig.js.map +1 -0
- package/lib/typescript/ft_logger.d.ts +11 -1
- package/lib/typescript/ft_mobile_agent.d.ts +25 -0
- package/lib/typescript/ft_rum.d.ts +33 -5
- package/lib/typescript/ft_tracing.d.ts +9 -1
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/rum/FTRumViewTracking.d.ts +32 -0
- package/lib/typescript/rum/FTRumWebSocketNative.d.ts +2 -3
- package/lib/typescript/rum/FTRumWebSocketTiming.d.ts +6 -1
- package/lib/typescript/rum/FTRumWebSocketTracking.d.ts +2 -4
- package/lib/typescript/specs/NativeFTMobileReactNative.d.ts +1 -0
- package/lib/typescript/specs/NativeFTReactNativeRUM.d.ts +7 -1
- package/lib/typescript/version.d.ts +1 -1
- package/lib/typescript/visitorIdConfig.d.ts +11 -0
- package/package.json +4 -3
- package/src/ft_logger.tsx +11 -1
- package/src/ft_mobile_agent.tsx +34 -1
- package/src/ft_rum.tsx +50 -5
- package/src/ft_tracing.tsx +9 -1
- package/src/index.tsx +4 -0
- package/src/rum/FTRumViewTracking.ts +179 -0
- package/src/rum/FTRumWebSocketNative.ts +2 -1
- package/src/rum/FTRumWebSocketTiming.ts +34 -2
- package/src/rum/FTRumWebSocketTracking.ts +9 -14
- package/src/specs/NativeFTMobileReactNative.ts +1 -0
- package/src/specs/NativeFTReactNativeRUM.ts +15 -1
- package/src/version.ts +1 -1
- package/src/visitorIdConfig.ts +123 -0
package/README.md
CHANGED
|
@@ -28,40 +28,6 @@ import {
|
|
|
28
28
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
## WebSocket handshake tracking
|
|
32
|
-
|
|
33
|
-
To collect iOS WebSocket handshakes while native Resource auto-collection is disabled:
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
await FTReactNativeRUM.setConfig({
|
|
37
|
-
androidAppId: 'YOUR_ANDROID_APP_ID',
|
|
38
|
-
iOSAppId: 'YOUR_IOS_APP_ID',
|
|
39
|
-
enableNativeUserResource: false,
|
|
40
|
-
enableIOSWebSocketResource: true,
|
|
41
|
-
});
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
`enableIOSWebSocketResource` defaults to `false` and is independent of
|
|
45
|
-
`enableNativeUserResource`. It only affects iOS; Android WebSocket collection
|
|
46
|
-
continues through the native SDK under `enableNativeUserResource`.
|
|
47
|
-
When disabled, new iOS connections are not instrumented or injected with
|
|
48
|
-
WebSocket Trace headers. Handshakes already started can finish normally.
|
|
49
|
-
When enabled, Trace injection additionally requires `enableNativeAutoTrace`.
|
|
50
|
-
Only connections created after tracking starts are observed.
|
|
51
|
-
|
|
52
|
-
iOS starts JS capture and native setup together, without waiting for a native
|
|
53
|
-
readiness reply. JS measures the handshake and injects Trace headers; the native
|
|
54
|
-
bridge handles Resource reporting and optionally adds a response snapshot.
|
|
55
|
-
Missing socket association keeps the native URL filtering, sampling and privacy
|
|
56
|
-
path. Only older native packages without this bridge use the legacy JS route.
|
|
57
|
-
Connections created before the hooks are installed may have no native snapshot.
|
|
58
|
-
|
|
59
|
-
iOS handshake tracking reads `error.message` first. When it is absent, the SDK
|
|
60
|
-
can use `close.reason` from the immediately following abnormal close (`1006`),
|
|
61
|
-
before the next microtask. The first error still ends handshake timing; normal
|
|
62
|
-
close reasons are not collected. Native HTTP response snapshots take precedence
|
|
63
|
-
over error-text inference.
|
|
64
|
-
|
|
65
31
|
## More
|
|
66
32
|
|
|
67
33
|
[View Doc Here](https://docs.truewatch.com/real-user-monitoring/react-native/app-access/)
|
package/android/build.gradle
CHANGED
|
@@ -185,8 +185,8 @@ repositories {
|
|
|
185
185
|
dependencies {
|
|
186
186
|
// noinspection GradleDynamicVersion
|
|
187
187
|
implementation 'com.facebook.react:react-native:+'
|
|
188
|
-
implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-sdk:1.7.
|
|
189
|
-
implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-native:1.1.
|
|
188
|
+
implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-sdk:1.7.6'
|
|
189
|
+
implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-native:1.1.4'
|
|
190
190
|
// implementation files('../example/android/app/libs/ft-sdk-debug.aar')
|
|
191
191
|
// implementation files('../example/android/app/libs/ft-session-replay-debug.aar')
|
|
192
192
|
|
|
@@ -21,8 +21,10 @@ public class FTLogImpl {
|
|
|
21
21
|
Map<String, Object> map = context.toHashMap();
|
|
22
22
|
Integer discardStrategy = ReactNativeUtils.convertToNativeInt(map.get("discardStrategy"));
|
|
23
23
|
Double sampleRate = (Double) map.get("sampleRate");
|
|
24
|
+
Double logSamplingRate = (Double) map.get("logSamplingRate");
|
|
24
25
|
ArrayList<Object> logTypeReadArr = (ArrayList<Object>) map.get("logLevelFilters");
|
|
25
26
|
Boolean enableLinkRumData = (Boolean) map.get("enableLinkRumData");
|
|
27
|
+
Boolean enableWebViewLog = (Boolean) map.get("enableWebViewLog");
|
|
26
28
|
Boolean enableCustomLog = (Boolean) map.get("enableCustomLog");
|
|
27
29
|
HashMap<String, Object> globalContext = (HashMap<String, Object>) map.get("globalContext");
|
|
28
30
|
Integer logCacheLimitCount = ReactNativeUtils.convertToNativeInt(map.get("logCacheLimitCount"));
|
|
@@ -47,8 +49,10 @@ public class FTLogImpl {
|
|
|
47
49
|
FTLoggerConfig logConfig = new FTLoggerConfig()
|
|
48
50
|
.setLogCacheDiscardStrategy(logCacheDiscard);
|
|
49
51
|
|
|
50
|
-
if (
|
|
51
|
-
logConfig.
|
|
52
|
+
if (logSamplingRate != null) {
|
|
53
|
+
logConfig.setLogSamplingRate(logSamplingRate.floatValue());
|
|
54
|
+
} else if (sampleRate != null) {
|
|
55
|
+
logConfig.setLogSamplingRate((float) (sampleRate * 100.0));
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
if (logTypeReadArr != null) {
|
|
@@ -70,6 +74,10 @@ public class FTLogImpl {
|
|
|
70
74
|
logConfig.setEnableLinkRumData(enableLinkRumData);
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
if (enableWebViewLog != null) {
|
|
78
|
+
logConfig.setEnableWebViewLog(enableWebViewLog);
|
|
79
|
+
}
|
|
80
|
+
|
|
73
81
|
if (enableCustomLog != null) {
|
|
74
82
|
logConfig.setEnableCustomLog(enableCustomLog);
|
|
75
83
|
}
|
|
@@ -171,6 +171,24 @@ public class FTMobileImpl {
|
|
|
171
171
|
if (override.hasKey("logSampleRate") && !override.isNull("logSampleRate")) {
|
|
172
172
|
configBean.setLogSampleRate((float) override.getDouble("logSampleRate"));
|
|
173
173
|
}
|
|
174
|
+
if (override.hasKey("sessionSamplingRate") && !override.isNull("sessionSamplingRate")) {
|
|
175
|
+
configBean.setSessionSamplingRate((float) override.getDouble("sessionSamplingRate"));
|
|
176
|
+
}
|
|
177
|
+
if (override.hasKey("sessionOnErrorSamplingRate") && !override.isNull("sessionOnErrorSamplingRate")) {
|
|
178
|
+
configBean.setSessionOnErrorSamplingRate((float) override.getDouble("sessionOnErrorSamplingRate"));
|
|
179
|
+
}
|
|
180
|
+
if (override.hasKey("traceSamplingRate") && !override.isNull("traceSamplingRate")) {
|
|
181
|
+
configBean.setTraceSamplingRate((float) override.getDouble("traceSamplingRate"));
|
|
182
|
+
}
|
|
183
|
+
if (override.hasKey("logSamplingRate") && !override.isNull("logSamplingRate")) {
|
|
184
|
+
configBean.setLogSamplingRate((float) override.getDouble("logSamplingRate"));
|
|
185
|
+
}
|
|
186
|
+
if (override.hasKey("sessionReplaySamplingRate") && !override.isNull("sessionReplaySamplingRate")) {
|
|
187
|
+
configBean.setSessionReplaySamplingRate((float) override.getDouble("sessionReplaySamplingRate"));
|
|
188
|
+
}
|
|
189
|
+
if (override.hasKey("sessionReplayOnErrorSamplingRate") && !override.isNull("sessionReplayOnErrorSamplingRate")) {
|
|
190
|
+
configBean.setSessionReplayOnErrorSamplingRate((float) override.getDouble("sessionReplayOnErrorSamplingRate"));
|
|
191
|
+
}
|
|
174
192
|
if (override.hasKey("logLevelFilters") && !override.isNull("logLevelFilters")) {
|
|
175
193
|
ReadableArray filtersArray = override.getArray("logLevelFilters");
|
|
176
194
|
String[] filters = new String[filtersArray.size()];
|
|
@@ -182,6 +200,9 @@ public class FTMobileImpl {
|
|
|
182
200
|
if (override.hasKey("logEnableCustomLog") && !override.isNull("logEnableCustomLog")) {
|
|
183
201
|
configBean.setLogEnableCustomLog(override.getBoolean("logEnableCustomLog"));
|
|
184
202
|
}
|
|
203
|
+
if (override.hasKey("logEnableWebViewLog") && !override.isNull("logEnableWebViewLog")) {
|
|
204
|
+
configBean.setLogEnableWebViewLog(override.getBoolean("logEnableWebViewLog"));
|
|
205
|
+
}
|
|
185
206
|
if (override.hasKey("logEnableConsoleLog") && !override.isNull("logEnableConsoleLog")) {
|
|
186
207
|
configBean.setLogEnableConsoleLog(override.getBoolean("logEnableConsoleLog"));
|
|
187
208
|
}
|
|
@@ -367,6 +388,19 @@ public class FTMobileImpl {
|
|
|
367
388
|
return convertedFilters;
|
|
368
389
|
}
|
|
369
390
|
|
|
391
|
+
static FTSDKConfig buildSDKConfig(@Nullable String datakitUrl,
|
|
392
|
+
@Nullable String datawayUrl,
|
|
393
|
+
@Nullable String clientToken) {
|
|
394
|
+
if (datakitUrl != null && datakitUrl.length() > 0) {
|
|
395
|
+
return FTSDKConfig.builder(datakitUrl);
|
|
396
|
+
}
|
|
397
|
+
if (datawayUrl != null && datawayUrl.length() > 0
|
|
398
|
+
&& clientToken != null && clientToken.length() > 0) {
|
|
399
|
+
return FTSDKConfig.builder(datawayUrl, clientToken);
|
|
400
|
+
}
|
|
401
|
+
return FTSDKConfig.builder();
|
|
402
|
+
}
|
|
403
|
+
|
|
370
404
|
public void sdkConfig(ReadableMap context, Promise promise) {
|
|
371
405
|
Map<String, Object> map = context.toHashMap();
|
|
372
406
|
String datakitUrl = (String) map.get("datakitUrl");
|
|
@@ -393,9 +427,12 @@ public class FTMobileImpl {
|
|
|
393
427
|
this.remoteConfigOverrideRules = context.hasKey("remoteConfigOverrideRules")
|
|
394
428
|
? context.getArray("remoteConfigOverrideRules") : null;
|
|
395
429
|
|
|
396
|
-
FTSDKConfig sdkConfig = (datakitUrl
|
|
397
|
-
|
|
398
|
-
|
|
430
|
+
FTSDKConfig sdkConfig = buildSDKConfig(datakitUrl, datawayUrl, cliToken);
|
|
431
|
+
|
|
432
|
+
if (map.containsKey("allowWebViewHost")) {
|
|
433
|
+
List<String> hosts = (List<String>) map.get("allowWebViewHost");
|
|
434
|
+
sdkConfig.setAllowWebViewHost(hosts == null ? null : hosts.toArray(new String[0]));
|
|
435
|
+
}
|
|
399
436
|
|
|
400
437
|
if (env != null) {
|
|
401
438
|
EnvType envType;
|
|
@@ -523,6 +560,11 @@ public class FTMobileImpl {
|
|
|
523
560
|
promise.resolve(null);
|
|
524
561
|
}
|
|
525
562
|
|
|
563
|
+
public void resetVisitorId(Promise promise) {
|
|
564
|
+
FTSdk.resetVisitorId();
|
|
565
|
+
promise.resolve(null);
|
|
566
|
+
}
|
|
567
|
+
|
|
526
568
|
public void bindRUMUserData(String userId, String userName, String userEmail, ReadableMap extra, Promise promise) {
|
|
527
569
|
UserData userData = new UserData();
|
|
528
570
|
userData.setId(userId);
|
|
@@ -14,6 +14,7 @@ import com.ft.sdk.FTRUMGlobalManager;
|
|
|
14
14
|
import com.ft.sdk.FTSdk;
|
|
15
15
|
import com.ft.sdk.RUMCacheDiscard;
|
|
16
16
|
import com.ft.sdk.garble.bean.AppState;
|
|
17
|
+
import com.ft.sdk.garble.bean.ViewTrackingType;
|
|
17
18
|
import com.ft.sdk.garble.bean.NetStatusBean;
|
|
18
19
|
import com.ft.sdk.garble.bean.ResourceParams;
|
|
19
20
|
import com.ft.sdk.reactnative.utils.ReactNativeUtils;
|
|
@@ -47,9 +48,18 @@ public class FTRUMImpl implements LifecycleEventListener {
|
|
|
47
48
|
@ReactMethod
|
|
48
49
|
public void setConfig(ReadableMap context, Promise promise) {
|
|
49
50
|
Map<String, Object> map = context.toHashMap();
|
|
51
|
+
com.ft.sdk.FTVisitorIdConfig visitorIdConfig;
|
|
52
|
+
try {
|
|
53
|
+
visitorIdConfig = VisitorIdConfigMapper.fromMap(map.get("visitorIdConfig"));
|
|
54
|
+
} catch (IllegalArgumentException error) {
|
|
55
|
+
promise.reject("E_VISITOR_ID_CONFIG", error.getMessage(), error);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
50
58
|
String rumAppId = (String) map.get("androidAppId");
|
|
51
59
|
Double sampleRate = (Double) map.get("sampleRate");
|
|
60
|
+
Double sessionSamplingRate = (Double) map.get("sessionSamplingRate");
|
|
52
61
|
Double sessionOnErrorSampleRate = (Double) map.get("sessionOnErrorSampleRate");
|
|
62
|
+
Double sessionOnErrorSamplingRate = (Double) map.get("sessionOnErrorSamplingRate");
|
|
53
63
|
|
|
54
64
|
Boolean enableNativeUserAction = (Boolean) map.get("enableNativeUserAction");
|
|
55
65
|
Boolean enableNativeUserView = (Boolean) map.get("enableNativeUserView");
|
|
@@ -70,12 +80,16 @@ public class FTRUMImpl implements LifecycleEventListener {
|
|
|
70
80
|
Boolean enableTraceWebView = (Boolean) map.get("enableTraceWebView");
|
|
71
81
|
ArrayList<String> allowWebViewHost = (ArrayList<String>) map.get("allowWebViewHost");
|
|
72
82
|
|
|
73
|
-
FTRUMConfig rumConfig = new FTRUMConfig().setRumAppId(rumAppId);
|
|
74
|
-
if (
|
|
75
|
-
rumConfig.
|
|
83
|
+
FTRUMConfig rumConfig = new FTRUMConfig().setRumAppId(rumAppId).setVisitorIdConfig(visitorIdConfig);
|
|
84
|
+
if (sessionSamplingRate != null) {
|
|
85
|
+
rumConfig.setSessionSamplingRate(sessionSamplingRate.floatValue());
|
|
86
|
+
} else if (sampleRate != null) {
|
|
87
|
+
rumConfig.setSessionSamplingRate((float) (sampleRate * 100.0));
|
|
76
88
|
}
|
|
77
|
-
if (
|
|
78
|
-
rumConfig.
|
|
89
|
+
if (sessionOnErrorSamplingRate != null) {
|
|
90
|
+
rumConfig.setSessionOnErrorSamplingRate(sessionOnErrorSamplingRate.floatValue());
|
|
91
|
+
} else if (sessionOnErrorSampleRate != null) {
|
|
92
|
+
rumConfig.setSessionOnErrorSamplingRate((float) (sessionOnErrorSampleRate * 100.0));
|
|
79
93
|
}
|
|
80
94
|
if (enableNativeUserAction != null) {
|
|
81
95
|
rumConfig.setEnableTraceUserAction(enableNativeUserAction);
|
|
@@ -153,10 +167,8 @@ public class FTRUMImpl implements LifecycleEventListener {
|
|
|
153
167
|
if (allowWebViewHost != null) {
|
|
154
168
|
String[] allowWebViewHostArr = new String[allowWebViewHost.size()];
|
|
155
169
|
allowWebViewHost.toArray(allowWebViewHostArr);
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
ftSdk.getBaseConfig().setAllowWebViewHost(allowWebViewHostArr);
|
|
159
|
-
}
|
|
170
|
+
// Let the native SDK apply legacy hosts only when base hosts are omitted.
|
|
171
|
+
rumConfig.setAllowWebViewHost(allowWebViewHostArr);
|
|
160
172
|
}
|
|
161
173
|
|
|
162
174
|
FTSdk.initRUMWithConfig(rumConfig);
|
|
@@ -242,6 +254,36 @@ public class FTRUMImpl implements LifecycleEventListener {
|
|
|
242
254
|
promise.resolve(null);
|
|
243
255
|
}
|
|
244
256
|
|
|
257
|
+
@ReactMethod
|
|
258
|
+
public void onCreateViewWithLoadStart(String viewName, double duration, double loadStartEpochMs, Promise promise) {
|
|
259
|
+
long nanoseconds = ViewTiming.durationNanoseconds(duration);
|
|
260
|
+
FTRUMGlobalManager.get().onCreateView(viewName, nanoseconds,
|
|
261
|
+
nanoseconds > 0 ? ViewTiming.epochNanoseconds(loadStartEpochMs) : 0);
|
|
262
|
+
promise.resolve(null);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@ReactMethod
|
|
266
|
+
public void startViewWithTrackingType(String viewName, ReadableMap map, double trackingType, Promise promise) {
|
|
267
|
+
if (trackingType != 0 && trackingType != 1) {
|
|
268
|
+
promise.reject("E_VIEW_TRACKING_TYPE", "trackingType must be Manual (0) or Automatic (1)");
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
FTRUMGlobalManager.get().startView(viewName, map == null ? null : map.toHashMap(),
|
|
272
|
+
trackingType == 1 ? ViewTrackingType.AUTOMATIC : ViewTrackingType.MANUAL);
|
|
273
|
+
promise.resolve(null);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
@ReactMethod
|
|
277
|
+
public void updateViewLoadingTime(double duration, Promise promise) {
|
|
278
|
+
if (Double.isNaN(duration) || Double.isInfinite(duration) || duration < 0
|
|
279
|
+
|| duration > 9007199254740991d || duration != Math.floor(duration)) {
|
|
280
|
+
promise.reject("E_VIEW_LOADING_TIME", "duration must be a non-negative safe integer in nanoseconds");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
FTRUMGlobalManager.get().updateLoadTime((long) duration);
|
|
284
|
+
promise.resolve(null);
|
|
285
|
+
}
|
|
286
|
+
|
|
245
287
|
@ReactMethod
|
|
246
288
|
public void onCreateView(String viewName, Double duration, Promise promise) {
|
|
247
289
|
FTRUMGlobalManager.get().onCreateView(viewName, duration.longValue());
|
|
@@ -21,13 +21,16 @@ public class FTTraceImpl {
|
|
|
21
21
|
public void setConfig(ReadableMap context, Promise promise) {
|
|
22
22
|
Map<String, Object> map = context.toHashMap();
|
|
23
23
|
Double sampleRate = (Double) map.get("sampleRate");
|
|
24
|
+
Double traceSamplingRate = (Double) map.get("traceSamplingRate");
|
|
24
25
|
Integer traceType = ReactNativeUtils.convertToNativeInt(map.get("traceType"));
|
|
25
26
|
Boolean enableLinkRUMData = (Boolean) map.get("enableLinkRUMData");
|
|
26
27
|
Boolean enableNativeAutoTrace = (Boolean) map.get("enableNativeAutoTrace");
|
|
27
28
|
|
|
28
29
|
FTTraceConfig traceConfig = new FTTraceConfig();
|
|
29
|
-
if (
|
|
30
|
-
traceConfig.
|
|
30
|
+
if (traceSamplingRate != null) {
|
|
31
|
+
traceConfig.setTraceSamplingRate(traceSamplingRate.floatValue());
|
|
32
|
+
} else if (sampleRate != null) {
|
|
33
|
+
traceConfig.setTraceSamplingRate((float) (sampleRate * 100.0));
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
if (traceType != null) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package com.ft.sdk.reactnative;
|
|
2
|
+
|
|
3
|
+
final class ViewTiming {
|
|
4
|
+
private ViewTiming() {}
|
|
5
|
+
|
|
6
|
+
static long durationNanoseconds(double value) {
|
|
7
|
+
return (!Double.isNaN(value) && !Double.isInfinite(value)) && value > 0 && value < 0x1p63 ? (long) value : 0;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static long epochNanoseconds(double milliseconds) {
|
|
11
|
+
if ((Double.isNaN(milliseconds) || Double.isInfinite(milliseconds)) || milliseconds <= 0 || milliseconds >= 0x1p63 / 1000000.0) return 0;
|
|
12
|
+
long whole = (long) milliseconds;
|
|
13
|
+
long fraction = (long) ((milliseconds - whole) * 1000000.0);
|
|
14
|
+
if (whole > Long.MAX_VALUE / 1000000 || fraction > Long.MAX_VALUE - whole * 1000000) return 0;
|
|
15
|
+
return whole * 1000000 + fraction;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package com.ft.sdk.reactnative;
|
|
2
|
+
|
|
3
|
+
import com.ft.sdk.FTVisitorIdConfig;
|
|
4
|
+
import java.net.URI;
|
|
5
|
+
import java.util.List;
|
|
6
|
+
import java.util.Map;
|
|
7
|
+
import java.util.regex.Pattern;
|
|
8
|
+
|
|
9
|
+
final class VisitorIdConfigMapper {
|
|
10
|
+
private VisitorIdConfigMapper() {}
|
|
11
|
+
|
|
12
|
+
static FTVisitorIdConfig fromMap(Object value) {
|
|
13
|
+
if (value == null) return null;
|
|
14
|
+
if (!(value instanceof Map)) throw new IllegalArgumentException("visitorIdConfig must be an object");
|
|
15
|
+
Map<?, ?> map = (Map<?, ?>) value;
|
|
16
|
+
if (!(map.get("header") instanceof String)) throw new IllegalArgumentException("Visitor ID header is required");
|
|
17
|
+
FTVisitorIdConfig config = new FTVisitorIdConfig().setHeader((String) map.get("header"));
|
|
18
|
+
if (map.containsKey("ttlHours")) {
|
|
19
|
+
if (!(map.get("ttlHours") instanceof Number)) throw new IllegalArgumentException("Visitor ID TTL must be numeric");
|
|
20
|
+
double hours = ((Number) map.get("ttlHours")).doubleValue();
|
|
21
|
+
double milliseconds = hours * 3600000;
|
|
22
|
+
if (Double.isNaN(hours) || Double.isInfinite(hours) || milliseconds < 1 || milliseconds >= Long.MAX_VALUE) {
|
|
23
|
+
throw new IllegalArgumentException("Visitor ID TTL is out of range");
|
|
24
|
+
}
|
|
25
|
+
config.setTtlHours(hours);
|
|
26
|
+
}
|
|
27
|
+
int rules = 0;
|
|
28
|
+
for (String key : new String[]{"urlPrefixes", "regularExpressions"}) {
|
|
29
|
+
Object values = map.get(key);
|
|
30
|
+
if (values == null && !map.containsKey(key)) continue;
|
|
31
|
+
if (!(values instanceof List)) throw new IllegalArgumentException(key + " must be an array");
|
|
32
|
+
for (Object item : (List<?>) values) {
|
|
33
|
+
if (!(item instanceof String) || ((String) item).isEmpty()) throw new IllegalArgumentException("Invalid Visitor ID rule");
|
|
34
|
+
String rule = (String) item;
|
|
35
|
+
if ("urlPrefixes".equals(key)) {
|
|
36
|
+
URI uri = URI.create(rule);
|
|
37
|
+
if (uri.getHost() == null || !("http".equalsIgnoreCase(uri.getScheme()) || "https".equalsIgnoreCase(uri.getScheme()))) {
|
|
38
|
+
throw new IllegalArgumentException("Visitor ID prefix must be an HTTP(S) URL");
|
|
39
|
+
}
|
|
40
|
+
config.addMatch(rule);
|
|
41
|
+
} else {
|
|
42
|
+
config.addMatch(Pattern.compile(rule));
|
|
43
|
+
}
|
|
44
|
+
rules++;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (rules == 0) throw new IllegalArgumentException("Visitor ID requires URL matching rules");
|
|
48
|
+
return config;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -39,6 +39,11 @@ public class FTMobileModule extends NativeFTMobileReactNativeSpec {
|
|
|
39
39
|
impl.bindRUMUserData(userId, userName, userEmail, extra, promise);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
@ReactMethod
|
|
43
|
+
public void resetVisitorId(Promise promise) {
|
|
44
|
+
impl.resetVisitorId(promise);
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
@ReactMethod
|
|
43
48
|
public void unbindRUMUserData(Promise promise) {
|
|
44
49
|
impl.unbindRUMUserData(promise);
|
|
@@ -58,6 +58,24 @@ public class FTRUMModule extends NativeFTReactNativeRUMSpec {
|
|
|
58
58
|
impl.addAction(actionName, actionType, map, promise);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
@Override
|
|
62
|
+
@ReactMethod
|
|
63
|
+
public void onCreateViewWithLoadStart(String viewName, double duration, double loadStartEpochMs, Promise promise) {
|
|
64
|
+
impl.onCreateViewWithLoadStart(viewName, duration, loadStartEpochMs, promise);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@Override
|
|
68
|
+
@ReactMethod
|
|
69
|
+
public void startViewWithTrackingType(String viewName, ReadableMap map, double trackingType, Promise promise) {
|
|
70
|
+
impl.startViewWithTrackingType(viewName, map, trackingType, promise);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@Override
|
|
74
|
+
@ReactMethod
|
|
75
|
+
public void updateViewLoadingTime(double duration, Promise promise) {
|
|
76
|
+
impl.updateViewLoadingTime(duration, promise);
|
|
77
|
+
}
|
|
78
|
+
|
|
61
79
|
@Override
|
|
62
80
|
@ReactMethod
|
|
63
81
|
public void onCreateView(String viewName, double duration, Promise promise) {
|
|
@@ -38,6 +38,11 @@ public class FTMobileModule extends ReactContextBaseJavaModule {
|
|
|
38
38
|
impl.bindRUMUserData(userId, userName, userEmail, extra, promise);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
@ReactMethod
|
|
42
|
+
public void resetVisitorId(Promise promise) {
|
|
43
|
+
impl.resetVisitorId(promise);
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
@ReactMethod
|
|
42
47
|
public void unbindRUMUserData(Promise promise) {
|
|
43
48
|
impl.unbindRUMUserData(promise);
|
|
@@ -56,6 +56,21 @@ public class FTRUMModule extends ReactContextBaseJavaModule {
|
|
|
56
56
|
impl.addAction(actionName, actionType, map, promise);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
@ReactMethod
|
|
60
|
+
public void onCreateViewWithLoadStart(String viewName, double duration, double loadStartEpochMs, Promise promise) {
|
|
61
|
+
impl.onCreateViewWithLoadStart(viewName, duration, loadStartEpochMs, promise);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@ReactMethod
|
|
65
|
+
public void startViewWithTrackingType(String viewName, ReadableMap map, double trackingType, Promise promise) {
|
|
66
|
+
impl.startViewWithTrackingType(viewName, map, trackingType, promise);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@ReactMethod
|
|
70
|
+
public void updateViewLoadingTime(double duration, Promise promise) {
|
|
71
|
+
impl.updateViewLoadingTime(duration, promise);
|
|
72
|
+
}
|
|
73
|
+
|
|
59
74
|
@ReactMethod
|
|
60
75
|
public void onCreateView(String viewName, Double duration, Promise promise) {
|
|
61
76
|
impl.onCreateView(viewName, duration, promise);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
package com.ft.sdk.reactnative;
|
|
2
|
+
|
|
3
|
+
import static org.junit.Assert.assertEquals;
|
|
4
|
+
|
|
5
|
+
import com.ft.sdk.FTSDKConfig;
|
|
6
|
+
|
|
7
|
+
import org.junit.Test;
|
|
8
|
+
|
|
9
|
+
public class FTMobileImplTest {
|
|
10
|
+
@Test
|
|
11
|
+
public void buildsConfigWithoutInitialUploadAddress() {
|
|
12
|
+
FTSDKConfig config = FTMobileImpl.buildSDKConfig(null, null, null);
|
|
13
|
+
|
|
14
|
+
assertEquals("", config.getDatakitUrl());
|
|
15
|
+
assertEquals("", config.getDatawayUrl());
|
|
16
|
+
assertEquals("", config.getClientToken());
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@Test
|
|
20
|
+
public void ignoresIncompleteDatawayConfig() {
|
|
21
|
+
FTSDKConfig config = FTMobileImpl.buildSDKConfig(null, "https://ingest.example.com", null);
|
|
22
|
+
|
|
23
|
+
assertEquals("", config.getDatakitUrl());
|
|
24
|
+
assertEquals("", config.getDatawayUrl());
|
|
25
|
+
assertEquals("", config.getClientToken());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@Test
|
|
29
|
+
public void keepsExistingDatakitConfigBehavior() {
|
|
30
|
+
FTSDKConfig config = FTMobileImpl.buildSDKConfig(
|
|
31
|
+
"http://10.0.0.1:9529",
|
|
32
|
+
"https://ingest.example.com",
|
|
33
|
+
"client-token"
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
assertEquals("http://10.0.0.1:9529", config.getDatakitUrl());
|
|
37
|
+
assertEquals("", config.getDatawayUrl());
|
|
38
|
+
assertEquals("", config.getClientToken());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@Test
|
|
42
|
+
public void keepsExistingDatawayConfigBehavior() {
|
|
43
|
+
FTSDKConfig config = FTMobileImpl.buildSDKConfig(
|
|
44
|
+
null,
|
|
45
|
+
"https://ingest.example.com",
|
|
46
|
+
"client-token"
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
assertEquals("", config.getDatakitUrl());
|
|
50
|
+
assertEquals("https://ingest.example.com", config.getDatawayUrl());
|
|
51
|
+
assertEquals("client-token", config.getClientToken());
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
//
|
|
8
8
|
|
|
9
9
|
#import "FTMobileReactNative.h"
|
|
10
|
+
#import <TrueWatchSDK/FTSDKAgent.h>
|
|
10
11
|
#import <React/RCTConvert.h>
|
|
11
12
|
#import <TrueWatchSDK/FTMobileAgent.h>
|
|
12
13
|
#import <TrueWatchSDK/FTSDKConfig+Private.h>
|
|
@@ -275,12 +276,33 @@ RCT_EXPORT_MODULE()
|
|
|
275
276
|
if ([override.allKeys containsObject:@"logSampleRate"]) {
|
|
276
277
|
model.logSampleRate = @([RCTConvert double:override[@"logSampleRate"]]);
|
|
277
278
|
}
|
|
279
|
+
if ([override.allKeys containsObject:@"sessionSamplingRate"]) {
|
|
280
|
+
model.sessionSamplingRate = @([RCTConvert double:override[@"sessionSamplingRate"]]);
|
|
281
|
+
}
|
|
282
|
+
if ([override.allKeys containsObject:@"sessionOnErrorSamplingRate"]) {
|
|
283
|
+
model.sessionOnErrorSamplingRate = @([RCTConvert double:override[@"sessionOnErrorSamplingRate"]]);
|
|
284
|
+
}
|
|
285
|
+
if ([override.allKeys containsObject:@"traceSamplingRate"]) {
|
|
286
|
+
model.traceSamplingRate = @([RCTConvert double:override[@"traceSamplingRate"]]);
|
|
287
|
+
}
|
|
288
|
+
if ([override.allKeys containsObject:@"logSamplingRate"]) {
|
|
289
|
+
model.logSamplingRate = @([RCTConvert double:override[@"logSamplingRate"]]);
|
|
290
|
+
}
|
|
291
|
+
if ([override.allKeys containsObject:@"sessionReplaySamplingRate"]) {
|
|
292
|
+
model.sessionReplaySamplingRate = @([RCTConvert double:override[@"sessionReplaySamplingRate"]]);
|
|
293
|
+
}
|
|
294
|
+
if ([override.allKeys containsObject:@"sessionReplayOnErrorSamplingRate"]) {
|
|
295
|
+
model.sessionReplayOnErrorSamplingRate = @([RCTConvert double:override[@"sessionReplayOnErrorSamplingRate"]]);
|
|
296
|
+
}
|
|
278
297
|
if ([override.allKeys containsObject:@"logLevelFilters"]) {
|
|
279
298
|
model.logLevelFilters = [RCTConvert NSArray:override[@"logLevelFilters"]];
|
|
280
299
|
}
|
|
281
300
|
if ([override.allKeys containsObject:@"logEnableCustomLog"]) {
|
|
282
301
|
model.logEnableCustomLog = @([RCTConvert double:override[@"logEnableCustomLog"]]);
|
|
283
302
|
}
|
|
303
|
+
if ([override.allKeys containsObject:@"logEnableWebViewLog"] && override[@"logEnableWebViewLog"] != [NSNull null]) {
|
|
304
|
+
model.logEnableWebViewLog = @([RCTConvert BOOL:override[@"logEnableWebViewLog"]]);
|
|
305
|
+
}
|
|
284
306
|
|
|
285
307
|
NSString *ruleId = [RCTConvert NSString:rule[@"id"]];
|
|
286
308
|
[appliedRuleIds addObject:ruleId.length > 0 ? ruleId : [NSString stringWithFormat:@"rule_%lu", (unsigned long)idx]];
|
|
@@ -320,6 +342,12 @@ RCT_REMAP_METHOD(bindRUMUserData,
|
|
|
320
342
|
[self bindRUMUserData:userId userName:userName userEmail:userName extra:extra resolve:resolve reject:reject];
|
|
321
343
|
}
|
|
322
344
|
|
|
345
|
+
RCT_REMAP_METHOD(resetVisitorId,
|
|
346
|
+
resetVisitorIdResolver:(RCTPromiseResolveBlock)resolve
|
|
347
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
348
|
+
[self resetVisitorId:resolve reject:reject];
|
|
349
|
+
}
|
|
350
|
+
|
|
323
351
|
RCT_REMAP_METHOD(unbindRUMUserData,
|
|
324
352
|
unbindRUMUserData_Resolver:(RCTPromiseResolveBlock)resolve
|
|
325
353
|
rejecter:(RCTPromiseRejectBlock)reject
|
|
@@ -383,8 +411,7 @@ RCT_REMAP_METHOD(clearAllData,
|
|
|
383
411
|
}else if(datakitUrl && datakitUrl.length>0){
|
|
384
412
|
config = [[FTSDKConfig alloc]initWithDatakitUrl:datakitUrl];
|
|
385
413
|
}else{
|
|
386
|
-
|
|
387
|
-
return;
|
|
414
|
+
config = [[FTSDKConfig alloc]init];
|
|
388
415
|
}
|
|
389
416
|
if ([context.allKeys containsObject:@"debug"]) {
|
|
390
417
|
config.enableSDKDebugLog = [RCTConvert BOOL:context[@"debug"]];
|
|
@@ -428,6 +455,9 @@ RCT_REMAP_METHOD(clearAllData,
|
|
|
428
455
|
if ([context.allKeys containsObject:@"dataFilters"]) {
|
|
429
456
|
config.dataFilters = [RCTConvert NSDictionary:context[@"dataFilters"]];
|
|
430
457
|
}
|
|
458
|
+
if ([context.allKeys containsObject:@"allowWebViewHost"]) {
|
|
459
|
+
config.allowWebViewHost = [RCTConvert NSArray:context[@"allowWebViewHost"]];
|
|
460
|
+
}
|
|
431
461
|
if ([context.allKeys containsObject:@"globalContext"]) {
|
|
432
462
|
config.globalContext = [RCTConvert NSDictionary:context[@"globalContext"]];
|
|
433
463
|
}
|
|
@@ -528,6 +558,11 @@ RCT_REMAP_METHOD(clearAllData,
|
|
|
528
558
|
[[FTMobileAgent sharedInstance] unbindUser];
|
|
529
559
|
resolve(nil);
|
|
530
560
|
}
|
|
561
|
+
- (void)resetVisitorId:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
562
|
+
[FTSDKAgent resetVisitorID];
|
|
563
|
+
resolve(nil);
|
|
564
|
+
}
|
|
565
|
+
|
|
531
566
|
- (void)clearAllData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
532
567
|
[FTMobileAgent clearAllData];
|
|
533
568
|
resolve(nil);
|
package/ios/FTReactNativeLog.mm
CHANGED
|
@@ -42,8 +42,13 @@ RCT_REMAP_METHOD(logWithStatusString,
|
|
|
42
42
|
|
|
43
43
|
- (void)logConfig:(NSDictionary *)context resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
44
44
|
FTLoggerConfig *logger = [[FTLoggerConfig alloc]init];
|
|
45
|
-
if ([context.allKeys containsObject:@"
|
|
46
|
-
|
|
45
|
+
if ([context.allKeys containsObject:@"logSamplingRate"]) {
|
|
46
|
+
logger.logSamplingRate = [RCTConvert double:context[@"logSamplingRate"]];
|
|
47
|
+
} else if ([context.allKeys containsObject:@"sampleRate"]) {
|
|
48
|
+
logger.logSamplingRate = [RCTConvert double:context[@"sampleRate"]] * 100;
|
|
49
|
+
}
|
|
50
|
+
if ([context.allKeys containsObject:@"enableWebViewLog"]) {
|
|
51
|
+
logger.enableWebViewLog = [RCTConvert BOOL:context[@"enableWebViewLog"]];
|
|
47
52
|
}
|
|
48
53
|
NSArray<NSNumber *>*filters = [RCTConvert NSNumberArray:context[@"logLevelFilters"]];
|
|
49
54
|
if (filters) {
|