@luciq/react-native 19.6.0 → 19.7.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/CHANGELOG.md +12 -0
- package/README.md +174 -111
- package/android/native.gradle +1 -1
- package/android/proguard-rules.txt +1 -1
- package/android/src/main/java/ai/luciq/reactlibrary/Constants.java +3 -0
- package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqAPMModule.java +13 -5
- package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqNetworkLoggerModule.java +29 -9
- package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqReactnativeModule.java +139 -118
- package/android/src/main/java/ai/luciq/reactlibrary/utils/EventEmitterModule.java +5 -0
- package/android/src/main/java/ai/luciq/reactlibrary/utils/LuciqRNLogger.java +53 -0
- package/dist/modules/Luciq.js +10 -1
- package/dist/modules/NetworkLogger.d.ts +0 -5
- package/dist/modules/NetworkLogger.js +9 -1
- package/dist/utils/FeatureFlags.d.ts +6 -0
- package/dist/utils/FeatureFlags.js +35 -0
- package/dist/utils/LuciqUtils.js +7 -0
- package/dist/utils/XhrNetworkInterceptor.js +85 -53
- package/ios/RNLuciq/LuciqNetworkLoggerBridge.m +30 -6
- package/ios/RNLuciq/LuciqReactBridge.m +21 -4
- package/ios/RNLuciq/Util/LuciqRNLogger.h +32 -0
- package/ios/RNLuciq/Util/LuciqRNLogger.m +57 -0
- package/ios/native.rb +1 -1
- package/package.json +1 -1
- package/src/modules/Luciq.ts +13 -1
- package/src/modules/NetworkLogger.ts +26 -1
- package/src/utils/FeatureFlags.ts +44 -0
- package/src/utils/LuciqUtils.ts +20 -0
- package/src/utils/XhrNetworkInterceptor.ts +128 -55
|
@@ -2,6 +2,7 @@ package ai.luciq.reactlibrary;
|
|
|
2
2
|
|
|
3
3
|
import static ai.luciq.apm.configuration.cp.APMFeature.APM_NETWORK_PLUGIN_INSTALLED;
|
|
4
4
|
import static ai.luciq.apm.configuration.cp.APMFeature.CP_NATIVE_INTERCEPTION_ENABLED;
|
|
5
|
+
import static ai.luciq.reactlibrary.Constants.NET_TAG;
|
|
5
6
|
import static ai.luciq.reactlibrary.utils.LuciqUtil.getMethod;
|
|
6
7
|
|
|
7
8
|
import android.app.Application;
|
|
@@ -13,8 +14,6 @@ import android.os.Build;
|
|
|
13
14
|
import android.util.Log;
|
|
14
15
|
import android.view.View;
|
|
15
16
|
|
|
16
|
-
import com.facebook.react.bridge.ReactApplicationContext;
|
|
17
|
-
|
|
18
17
|
import androidx.annotation.NonNull;
|
|
19
18
|
import androidx.annotation.UiThread;
|
|
20
19
|
|
|
@@ -32,22 +31,37 @@ import com.facebook.react.bridge.WritableNativeArray;
|
|
|
32
31
|
import com.facebook.react.bridge.WritableNativeMap;
|
|
33
32
|
import com.facebook.react.uimanager.UIManagerHelper;
|
|
34
33
|
import com.facebook.react.uimanager.UIManagerModule;
|
|
34
|
+
|
|
35
|
+
import org.json.JSONException;
|
|
36
|
+
import org.json.JSONObject;
|
|
37
|
+
import org.json.JSONTokener;
|
|
38
|
+
|
|
39
|
+
import java.io.File;
|
|
40
|
+
import java.lang.reflect.Method;
|
|
41
|
+
import java.util.ArrayList;
|
|
42
|
+
import java.util.Arrays;
|
|
43
|
+
import java.util.HashMap;
|
|
44
|
+
import java.util.Iterator;
|
|
45
|
+
import java.util.List;
|
|
46
|
+
import java.util.Locale;
|
|
47
|
+
import java.util.Map;
|
|
48
|
+
|
|
49
|
+
import javax.annotation.Nullable;
|
|
50
|
+
|
|
35
51
|
import ai.luciq.apm.InternalAPM;
|
|
36
|
-
import ai.luciq.apm.configuration.cp.APMFeature;
|
|
37
52
|
import ai.luciq.library.Feature;
|
|
53
|
+
import ai.luciq.library.IssueType;
|
|
54
|
+
import ai.luciq.library.LogLevel;
|
|
38
55
|
import ai.luciq.library.Luciq;
|
|
39
56
|
import ai.luciq.library.LuciqColorTheme;
|
|
40
57
|
import ai.luciq.library.LuciqCustomTextPlaceHolder;
|
|
41
|
-
import ai.luciq.library.IssueType;
|
|
42
|
-
import ai.luciq.library.LogLevel;
|
|
43
58
|
import ai.luciq.library.ReproConfigurations;
|
|
44
59
|
import ai.luciq.library.core.InstabugCore;
|
|
60
|
+
import ai.luciq.library.featuresflags.model.LuciqFeatureFlag;
|
|
45
61
|
import ai.luciq.library.internal.crossplatform.CoreFeature;
|
|
46
62
|
import ai.luciq.library.internal.crossplatform.CoreFeaturesState;
|
|
47
63
|
import ai.luciq.library.internal.crossplatform.FeaturesStateListener;
|
|
48
64
|
import ai.luciq.library.internal.crossplatform.InternalCore;
|
|
49
|
-
import ai.luciq.library.featuresflags.model.LuciqFeatureFlag;
|
|
50
|
-
import ai.luciq.library.internal.crossplatform.InternalCore;
|
|
51
65
|
import ai.luciq.library.internal.crossplatform.OnFeaturesUpdatedListener;
|
|
52
66
|
import ai.luciq.library.internal.module.LuciqLocale;
|
|
53
67
|
import ai.luciq.library.invocation.LuciqInvocationEvent;
|
|
@@ -56,29 +70,12 @@ import ai.luciq.library.model.LuciqTheme;
|
|
|
56
70
|
import ai.luciq.library.model.NetworkLog;
|
|
57
71
|
import ai.luciq.library.model.Report;
|
|
58
72
|
import ai.luciq.library.ui.onboarding.WelcomeMessage;
|
|
59
|
-
import ai.luciq.library.util.LuciqSDKLogger;
|
|
60
73
|
import ai.luciq.reactlibrary.utils.ArrayUtil;
|
|
61
74
|
import ai.luciq.reactlibrary.utils.EventEmitterModule;
|
|
75
|
+
import ai.luciq.reactlibrary.utils.LuciqRNLogger;
|
|
62
76
|
import ai.luciq.reactlibrary.utils.MainThreadHandler;
|
|
63
|
-
|
|
64
77
|
import ai.luciq.reactlibrary.utils.RNTouchedViewExtractor;
|
|
65
78
|
|
|
66
|
-
import org.json.JSONException;
|
|
67
|
-
import org.json.JSONObject;
|
|
68
|
-
import org.json.JSONTokener;
|
|
69
|
-
|
|
70
|
-
import java.io.File;
|
|
71
|
-
import java.lang.reflect.Method;
|
|
72
|
-
import java.util.ArrayList;
|
|
73
|
-
import java.util.Arrays;
|
|
74
|
-
import java.util.HashMap;
|
|
75
|
-
import java.util.Iterator;
|
|
76
|
-
import java.util.List;
|
|
77
|
-
import java.util.Locale;
|
|
78
|
-
import java.util.Map;
|
|
79
|
-
|
|
80
|
-
import javax.annotation.Nullable;
|
|
81
|
-
|
|
82
79
|
|
|
83
80
|
/**
|
|
84
81
|
* The type Rn luciq reactnative module.
|
|
@@ -86,6 +83,7 @@ import javax.annotation.Nullable;
|
|
|
86
83
|
public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
87
84
|
|
|
88
85
|
private static final String TAG = "Luciq-RN-Core";
|
|
86
|
+
;
|
|
89
87
|
|
|
90
88
|
private LuciqCustomTextPlaceHolder placeHolders;
|
|
91
89
|
private static Report currentReport;
|
|
@@ -123,6 +121,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
123
121
|
|
|
124
122
|
/**
|
|
125
123
|
* Enables or disables Luciq functionality.
|
|
124
|
+
*
|
|
126
125
|
* @param isEnabled A boolean to enable/disable Luciq.
|
|
127
126
|
*/
|
|
128
127
|
@ReactMethod
|
|
@@ -163,6 +162,9 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
163
162
|
|
|
164
163
|
|
|
165
164
|
) {
|
|
165
|
+
final int parsedLogLevel = ArgsRegistry.sdkLogLevels.getOrDefault(logLevel, LogLevel.ERROR);
|
|
166
|
+
LuciqRNLogger.setLevel(parsedLogLevel);
|
|
167
|
+
LuciqRNLogger.d(NET_TAG, "[init] Called — logLevel=" + logLevel + ", useNativeNetworkInterception=" + useNativeNetworkInterception + ", codePushVersion=" + codePushVersion + ", appVariant=" + appVariant);
|
|
166
168
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
167
169
|
@Override
|
|
168
170
|
public void run() {
|
|
@@ -171,7 +173,6 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
171
173
|
final ArrayList<String> keys = ArrayUtil.parseReadableArrayOfStrings(invocationEventValues);
|
|
172
174
|
final ArrayList<LuciqInvocationEvent> parsedInvocationEvents = ArgsRegistry.invocationEvents.getAll(keys);
|
|
173
175
|
final LuciqInvocationEvent[] invocationEvents = parsedInvocationEvents.toArray(new LuciqInvocationEvent[0]);
|
|
174
|
-
final int parsedLogLevel = ArgsRegistry.sdkLogLevels.getOrDefault(logLevel, LogLevel.ERROR);
|
|
175
176
|
|
|
176
177
|
final Application application = (Application) reactContext.getApplicationContext();
|
|
177
178
|
|
|
@@ -179,7 +180,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
179
180
|
.setInvocationEvents(invocationEvents)
|
|
180
181
|
.setLogLevel(parsedLogLevel);
|
|
181
182
|
|
|
182
|
-
if (map!=null&&map.hasKey("ignoreAndroidSecureFlag")) {
|
|
183
|
+
if (map != null && map.hasKey("ignoreAndroidSecureFlag")) {
|
|
183
184
|
builder.ignoreFlagSecure(map.getBoolean("ignoreAndroidSecureFlag"));
|
|
184
185
|
}
|
|
185
186
|
|
|
@@ -190,12 +191,12 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
190
191
|
builder.setCodePushVersion(codePushVersion);
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
if (appVariant != null) {
|
|
195
|
+
builder.setAppVariant(appVariant);
|
|
196
|
+
}
|
|
196
197
|
|
|
197
|
-
if(overAirVersion != null
|
|
198
|
-
if(Luciq.isBuilt()) {
|
|
198
|
+
if (overAirVersion != null) {
|
|
199
|
+
if (Luciq.isBuilt()) {
|
|
199
200
|
Luciq.setOverAirVersion(overAirVersion.getString("version"),
|
|
200
201
|
ArgsRegistry.overAirUpdateService.get(overAirVersion.getString("service")));
|
|
201
202
|
} else {
|
|
@@ -204,6 +205,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
204
205
|
}
|
|
205
206
|
|
|
206
207
|
builder.build();
|
|
208
|
+
LuciqRNLogger.d(NET_TAG, "[init] SDK build complete");
|
|
207
209
|
}
|
|
208
210
|
});
|
|
209
211
|
}
|
|
@@ -547,7 +549,6 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
547
549
|
}
|
|
548
550
|
|
|
549
551
|
|
|
550
|
-
|
|
551
552
|
/**
|
|
552
553
|
* Removes user attribute if exists.
|
|
553
554
|
*
|
|
@@ -969,6 +970,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
969
970
|
final String requestHeaders,
|
|
970
971
|
final String responseHeaders,
|
|
971
972
|
final double duration) {
|
|
973
|
+
LuciqRNLogger.d(NET_TAG, "[networkLogAndroid-Core] Received from JS: " + method + " " + url + ", status=" + (int) responseCode + ", duration=" + (long) duration + "ms, reqBodyLen=" + (requestBody != null ? requestBody.length() : 0) + ", resBodyLen=" + (responseBody != null ? responseBody.length() : 0));
|
|
972
974
|
try {
|
|
973
975
|
final String date = String.valueOf(System.currentTimeMillis());
|
|
974
976
|
|
|
@@ -985,11 +987,14 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
985
987
|
networkLog.setRequestHeaders(requestHeaders);
|
|
986
988
|
networkLog.setResponseHeaders(responseHeaders);
|
|
987
989
|
} catch (OutOfMemoryError | Exception exception) {
|
|
990
|
+
LuciqRNLogger.e(NET_TAG, "[networkLogAndroid-Core] OOM/Error setting log contents: " + exception.getMessage() + " for " + method + " " + url);
|
|
988
991
|
Log.d(TAG, "Error: " + exception.getMessage() + "while trying to set network log contents (request body, response body, request headers, and response headers).");
|
|
989
992
|
}
|
|
990
993
|
|
|
991
994
|
networkLog.insert();
|
|
995
|
+
LuciqRNLogger.d(NET_TAG, "[networkLogAndroid-Core] Successfully inserted NetworkLog: " + method + " " + url);
|
|
992
996
|
} catch (OutOfMemoryError | Exception exception) {
|
|
997
|
+
LuciqRNLogger.e(NET_TAG, "[networkLogAndroid-Core] OOM/Error inserting network log: " + exception.getMessage() + " for " + method + " " + url);
|
|
993
998
|
Log.d(TAG, "Error: " + exception.getMessage() + "while trying to insert a network log");
|
|
994
999
|
}
|
|
995
1000
|
}
|
|
@@ -998,18 +1003,18 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
998
1003
|
@Nullable
|
|
999
1004
|
private View resolveReactView(final int reactTag) {
|
|
1000
1005
|
try {
|
|
1001
|
-
|
|
1002
|
-
|
|
1006
|
+
final ReactApplicationContext reactContext = getReactApplicationContext();
|
|
1007
|
+
final UIManagerModule uiManagerModule = reactContext.getNativeModule(UIManagerModule.class);
|
|
1003
1008
|
|
|
1004
|
-
|
|
1009
|
+
if (uiManagerModule == null) {
|
|
1005
1010
|
UIManager uiNewManagerModule = UIManagerHelper.getUIManagerForReactTag(reactContext, reactTag);
|
|
1006
1011
|
if (uiNewManagerModule != null) {
|
|
1007
1012
|
return uiNewManagerModule.resolveView(reactTag);
|
|
1008
1013
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1014
|
+
return null;
|
|
1015
|
+
}
|
|
1011
1016
|
|
|
1012
|
-
|
|
1017
|
+
return uiManagerModule.resolveView(reactTag);
|
|
1013
1018
|
} catch (Exception e) {
|
|
1014
1019
|
return null;
|
|
1015
1020
|
}
|
|
@@ -1024,8 +1029,8 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1024
1029
|
try {
|
|
1025
1030
|
final View view = resolveReactView(reactTag);
|
|
1026
1031
|
|
|
1027
|
-
if(view !=null){
|
|
1028
|
-
|
|
1032
|
+
if (view != null) {
|
|
1033
|
+
Luciq.addPrivateViews(view);
|
|
1029
1034
|
}
|
|
1030
1035
|
} catch (Exception e) {
|
|
1031
1036
|
e.printStackTrace();
|
|
@@ -1041,9 +1046,9 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1041
1046
|
public void run() {
|
|
1042
1047
|
try {
|
|
1043
1048
|
final View view = resolveReactView(reactTag);
|
|
1044
|
-
if(view !=null){
|
|
1049
|
+
if (view != null) {
|
|
1045
1050
|
|
|
1046
|
-
|
|
1051
|
+
Luciq.removePrivateViews(view);
|
|
1047
1052
|
}
|
|
1048
1053
|
} catch (Exception e) {
|
|
1049
1054
|
e.printStackTrace();
|
|
@@ -1078,7 +1083,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1078
1083
|
* Reports that the screen has been changed (Repro Steps) the screen sent to this method will be the 'current view' on the dashboard
|
|
1079
1084
|
*
|
|
1080
1085
|
* @param screenName string containing the screen name
|
|
1081
|
-
* @param spanId
|
|
1086
|
+
* @param spanId the span ID for screen loading tracking (nullable)
|
|
1082
1087
|
*/
|
|
1083
1088
|
@ReactMethod
|
|
1084
1089
|
public void reportScreenChange(final String screenName, @Nullable final String spanId) {
|
|
@@ -1087,9 +1092,9 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1087
1092
|
public void run() {
|
|
1088
1093
|
try {
|
|
1089
1094
|
Long uiTraceId = spanId != null ? Long.parseLong(spanId) : null;
|
|
1090
|
-
Method method = getMethod(Class.forName("ai.luciq.library.Luciq"), "reportScreenChange", Bitmap.class, String.class
|
|
1095
|
+
Method method = getMethod(Class.forName("ai.luciq.library.Luciq"), "reportScreenChange", Bitmap.class, String.class, Long.class);
|
|
1091
1096
|
if (method != null) {
|
|
1092
|
-
method.invoke(null, null, screenName
|
|
1097
|
+
method.invoke(null, null, screenName, uiTraceId);
|
|
1093
1098
|
}
|
|
1094
1099
|
} catch (Exception e) {
|
|
1095
1100
|
e.printStackTrace();
|
|
@@ -1099,7 +1104,6 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1099
1104
|
}
|
|
1100
1105
|
|
|
1101
1106
|
|
|
1102
|
-
|
|
1103
1107
|
@ReactMethod
|
|
1104
1108
|
public void addFeatureFlags(final ReadableMap featureFlagsMap) {
|
|
1105
1109
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
@@ -1172,7 +1176,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1172
1176
|
*/
|
|
1173
1177
|
@ReactMethod
|
|
1174
1178
|
public void registerFeatureFlagsChangeListener() {
|
|
1175
|
-
|
|
1179
|
+
LuciqRNLogger.d(NET_TAG, "[registerFeatureFlagsChangeListener] Registering native feature flags listener");
|
|
1176
1180
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1177
1181
|
@Override
|
|
1178
1182
|
public void run() {
|
|
@@ -1180,16 +1184,19 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1180
1184
|
InternalCore.INSTANCE._setFeaturesStateListener(new FeaturesStateListener() {
|
|
1181
1185
|
@Override
|
|
1182
1186
|
public void invoke(@NonNull CoreFeaturesState featuresState) {
|
|
1187
|
+
LuciqRNLogger.d(NET_TAG, "[FeatureFlagsListener] Received update — W3CTraceID=" + featuresState.isW3CExternalTraceIdEnabled() + ", generatedHeader=" + featuresState.isAttachingGeneratedHeaderEnabled() + ", caughtHeader=" + featuresState.isAttachingCapturedHeaderEnabled() + ", networkBodyLimit=" + featuresState.getNetworkLogCharLimit());
|
|
1183
1188
|
WritableMap params = Arguments.createMap();
|
|
1184
1189
|
params.putBoolean("isW3ExternalTraceIDEnabled", featuresState.isW3CExternalTraceIdEnabled());
|
|
1185
1190
|
params.putBoolean("isW3ExternalGeneratedHeaderEnabled", featuresState.isAttachingGeneratedHeaderEnabled());
|
|
1186
1191
|
params.putBoolean("isW3CaughtHeaderEnabled", featuresState.isAttachingCapturedHeaderEnabled());
|
|
1187
|
-
params.putInt("networkBodyLimit",featuresState.getNetworkLogCharLimit());
|
|
1192
|
+
params.putInt("networkBodyLimit", featuresState.getNetworkLogCharLimit());
|
|
1188
1193
|
|
|
1189
1194
|
sendEvent(Constants.LCQ_ON_FEATURE_FLAGS_UPDATE_RECEIVED_CALLBACK, params);
|
|
1195
|
+
LuciqRNLogger.d(NET_TAG, "[FeatureFlagsListener] Sent event to JS: " + Constants.LCQ_ON_FEATURE_FLAGS_UPDATE_RECEIVED_CALLBACK);
|
|
1190
1196
|
}
|
|
1191
1197
|
});
|
|
1192
1198
|
} catch (Exception e) {
|
|
1199
|
+
LuciqRNLogger.e(NET_TAG, "[registerFeatureFlagsChangeListener] Failed to register listener", e);
|
|
1193
1200
|
e.printStackTrace();
|
|
1194
1201
|
}
|
|
1195
1202
|
|
|
@@ -1204,13 +1211,16 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1204
1211
|
*/
|
|
1205
1212
|
@ReactMethod
|
|
1206
1213
|
public void isW3ExternalTraceIDEnabled(Promise promise) {
|
|
1207
|
-
|
|
1214
|
+
LuciqRNLogger.d(NET_TAG, "[isW3ExternalTraceIDEnabled] Querying native flag");
|
|
1208
1215
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1209
1216
|
@Override
|
|
1210
1217
|
public void run() {
|
|
1211
1218
|
try {
|
|
1212
|
-
|
|
1219
|
+
boolean enabled = InternalCore.INSTANCE._isFeatureEnabled(CoreFeature.W3C_EXTERNAL_TRACE_ID);
|
|
1220
|
+
LuciqRNLogger.d(NET_TAG, "[isW3ExternalTraceIDEnabled] Result=" + enabled);
|
|
1221
|
+
promise.resolve(enabled);
|
|
1213
1222
|
} catch (Exception e) {
|
|
1223
|
+
LuciqRNLogger.e(NET_TAG, "[isW3ExternalTraceIDEnabled] Error querying flag", e);
|
|
1214
1224
|
e.printStackTrace();
|
|
1215
1225
|
promise.resolve(false);
|
|
1216
1226
|
}
|
|
@@ -1226,13 +1236,16 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1226
1236
|
*/
|
|
1227
1237
|
@ReactMethod
|
|
1228
1238
|
public void isW3ExternalGeneratedHeaderEnabled(Promise promise) {
|
|
1229
|
-
|
|
1239
|
+
LuciqRNLogger.d(NET_TAG, "[isW3ExternalGeneratedHeaderEnabled] Querying native flag");
|
|
1230
1240
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1231
1241
|
@Override
|
|
1232
1242
|
public void run() {
|
|
1233
1243
|
try {
|
|
1234
|
-
|
|
1244
|
+
boolean enabled = InternalCore.INSTANCE._isFeatureEnabled(CoreFeature.W3C_ATTACHING_GENERATED_HEADER);
|
|
1245
|
+
LuciqRNLogger.d(NET_TAG, "[isW3ExternalGeneratedHeaderEnabled] Result=" + enabled);
|
|
1246
|
+
promise.resolve(enabled);
|
|
1235
1247
|
} catch (Exception e) {
|
|
1248
|
+
LuciqRNLogger.e(NET_TAG, "[isW3ExternalGeneratedHeaderEnabled] Error querying flag", e);
|
|
1236
1249
|
e.printStackTrace();
|
|
1237
1250
|
promise.resolve(false);
|
|
1238
1251
|
}
|
|
@@ -1247,13 +1260,16 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1247
1260
|
*/
|
|
1248
1261
|
@ReactMethod
|
|
1249
1262
|
public void isW3CaughtHeaderEnabled(Promise promise) {
|
|
1250
|
-
|
|
1263
|
+
LuciqRNLogger.d(NET_TAG, "[isW3CaughtHeaderEnabled] Querying native flag");
|
|
1251
1264
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1252
1265
|
@Override
|
|
1253
1266
|
public void run() {
|
|
1254
1267
|
try {
|
|
1255
|
-
|
|
1268
|
+
boolean enabled = InternalCore.INSTANCE._isFeatureEnabled(CoreFeature.W3C_ATTACHING_CAPTURED_HEADER);
|
|
1269
|
+
LuciqRNLogger.d(NET_TAG, "[isW3CaughtHeaderEnabled] Result=" + enabled);
|
|
1270
|
+
promise.resolve(enabled);
|
|
1256
1271
|
} catch (Exception e) {
|
|
1272
|
+
LuciqRNLogger.e(NET_TAG, "[isW3CaughtHeaderEnabled] Error querying flag", e);
|
|
1257
1273
|
e.printStackTrace();
|
|
1258
1274
|
promise.resolve(false);
|
|
1259
1275
|
}
|
|
@@ -1268,7 +1284,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1268
1284
|
* Map between the exported JS constant and the arg key in {@link ArgsRegistry}.
|
|
1269
1285
|
* The constant name and the arg key should match to be able to resolve the
|
|
1270
1286
|
* constant with its actual value from the {@link ArgsRegistry} maps.
|
|
1271
|
-
*
|
|
1287
|
+
* <p>
|
|
1272
1288
|
* This is a workaround, because RN cannot resolve enums in the constants map.
|
|
1273
1289
|
*/
|
|
1274
1290
|
@Override
|
|
@@ -1299,23 +1315,25 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1299
1315
|
}
|
|
1300
1316
|
});
|
|
1301
1317
|
}
|
|
1318
|
+
|
|
1302
1319
|
/**
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1320
|
+
* Enables or disables capturing network body.
|
|
1321
|
+
*
|
|
1322
|
+
* @param isEnabled A boolean to enable/disable capturing network body.
|
|
1323
|
+
*/
|
|
1324
|
+
@ReactMethod
|
|
1325
|
+
public void setNetworkLogBodyEnabled(final boolean isEnabled) {
|
|
1326
|
+
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1327
|
+
@Override
|
|
1328
|
+
public void run() {
|
|
1329
|
+
try {
|
|
1330
|
+
Luciq.setNetworkLogBodyEnabled(isEnabled);
|
|
1331
|
+
} catch (Exception e) {
|
|
1332
|
+
e.printStackTrace();
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1319
1337
|
|
|
1320
1338
|
/**
|
|
1321
1339
|
* Sets the auto mask screenshots types.
|
|
@@ -1347,13 +1365,16 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1347
1365
|
*/
|
|
1348
1366
|
@ReactMethod
|
|
1349
1367
|
public void getNetworkBodyMaxSize(Promise promise) {
|
|
1350
|
-
|
|
1368
|
+
LuciqRNLogger.d(NET_TAG, "[getNetworkBodyMaxSize] Querying network body size limit");
|
|
1351
1369
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1352
1370
|
@Override
|
|
1353
1371
|
public void run() {
|
|
1354
1372
|
try {
|
|
1355
|
-
|
|
1373
|
+
Object limit = InternalCore.INSTANCE.get_networkLogCharLimit();
|
|
1374
|
+
LuciqRNLogger.d(NET_TAG, "[getNetworkBodyMaxSize] Result=" + limit);
|
|
1375
|
+
promise.resolve(limit);
|
|
1356
1376
|
} catch (Exception e) {
|
|
1377
|
+
LuciqRNLogger.e(NET_TAG, "[getNetworkBodyMaxSize] Error querying limit", e);
|
|
1357
1378
|
e.printStackTrace();
|
|
1358
1379
|
promise.resolve(false);
|
|
1359
1380
|
}
|
|
@@ -1361,20 +1382,20 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1361
1382
|
});
|
|
1362
1383
|
}
|
|
1363
1384
|
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1385
|
+
/**
|
|
1386
|
+
* Sets current App variant
|
|
1387
|
+
*
|
|
1388
|
+
* @param appVariant The app variant name .
|
|
1389
|
+
*/
|
|
1390
|
+
@ReactMethod
|
|
1391
|
+
public void setAppVariant(@NonNull String appVariant) {
|
|
1392
|
+
try {
|
|
1393
|
+
Luciq.setAppVariant(appVariant);
|
|
1373
1394
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
}
|
|
1395
|
+
} catch (Exception e) {
|
|
1396
|
+
e.printStackTrace();
|
|
1377
1397
|
}
|
|
1398
|
+
}
|
|
1378
1399
|
|
|
1379
1400
|
/**
|
|
1380
1401
|
* Enables or disables WebView monitoring.
|
|
@@ -1505,17 +1526,16 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1505
1526
|
}
|
|
1506
1527
|
|
|
1507
1528
|
|
|
1508
|
-
|
|
1509
1529
|
/**
|
|
1510
1530
|
* Applies a color to the theme builder if present in the configuration.
|
|
1511
1531
|
*
|
|
1512
1532
|
* @param themeConfig The theme configuration map
|
|
1513
|
-
* @param builder
|
|
1514
|
-
* @param key
|
|
1515
|
-
* @param setter
|
|
1533
|
+
* @param builder The theme builder
|
|
1534
|
+
* @param key The configuration key
|
|
1535
|
+
* @param setter The color setter function
|
|
1516
1536
|
*/
|
|
1517
1537
|
private void applyColorIfPresent(ReadableMap themeConfig, ai.luciq.library.model.LuciqTheme.Builder builder,
|
|
1518
|
-
|
|
1538
|
+
String key, java.util.function.BiConsumer<ai.luciq.library.model.LuciqTheme.Builder, Integer> setter) {
|
|
1519
1539
|
if (themeConfig.hasKey(key)) {
|
|
1520
1540
|
int color = getColor(themeConfig, key);
|
|
1521
1541
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
@@ -1528,12 +1548,12 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1528
1548
|
* Applies a text style to the theme builder if present in the configuration.
|
|
1529
1549
|
*
|
|
1530
1550
|
* @param themeConfig The theme configuration map
|
|
1531
|
-
* @param builder
|
|
1532
|
-
* @param key
|
|
1533
|
-
* @param setter
|
|
1551
|
+
* @param builder The theme builder
|
|
1552
|
+
* @param key The configuration key
|
|
1553
|
+
* @param setter The text style setter function
|
|
1534
1554
|
*/
|
|
1535
1555
|
private void applyTextStyleIfPresent(ReadableMap themeConfig, ai.luciq.library.model.LuciqTheme.Builder builder,
|
|
1536
|
-
|
|
1556
|
+
String key, java.util.function.BiConsumer<ai.luciq.library.model.LuciqTheme.Builder, Integer> setter) {
|
|
1537
1557
|
if (themeConfig.hasKey(key)) {
|
|
1538
1558
|
int style = getTextStyle(themeConfig, key);
|
|
1539
1559
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
@@ -1546,13 +1566,13 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1546
1566
|
* Sets a font on the theme builder if the font configuration is present in the theme config.
|
|
1547
1567
|
*
|
|
1548
1568
|
* @param themeConfig The theme configuration map
|
|
1549
|
-
* @param builder
|
|
1550
|
-
* @param fileKey
|
|
1551
|
-
* @param assetKey
|
|
1552
|
-
* @param fontType
|
|
1569
|
+
* @param builder The theme builder
|
|
1570
|
+
* @param fileKey The key for font file path
|
|
1571
|
+
* @param assetKey The key for font asset path
|
|
1572
|
+
* @param fontType The type of font (for logging purposes)
|
|
1553
1573
|
*/
|
|
1554
1574
|
private void setFontIfPresent(ReadableMap themeConfig, ai.luciq.library.model.LuciqTheme.Builder builder,
|
|
1555
|
-
|
|
1575
|
+
String fileKey, String assetKey, String fontType) {
|
|
1556
1576
|
if (themeConfig.hasKey(fileKey) || themeConfig.hasKey(assetKey)) {
|
|
1557
1577
|
Typeface typeface = getTypeface(themeConfig, fileKey, assetKey);
|
|
1558
1578
|
if (typeface != null) {
|
|
@@ -1637,27 +1657,28 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1637
1657
|
return Typeface.DEFAULT;
|
|
1638
1658
|
}
|
|
1639
1659
|
|
|
1640
|
-
/**
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
private String getFileName(String path) {
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1660
|
+
/**
|
|
1661
|
+
* Extracts the filename from a path, removing any directory prefixes.
|
|
1662
|
+
*
|
|
1663
|
+
* @param path The full path to the file
|
|
1664
|
+
* @return Just the filename with extension
|
|
1665
|
+
*/
|
|
1666
|
+
private String getFileName(String path) {
|
|
1667
|
+
if (path == null || path.isEmpty()) {
|
|
1668
|
+
return path;
|
|
1669
|
+
}
|
|
1650
1670
|
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1671
|
+
int lastSeparator = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
|
|
1672
|
+
if (lastSeparator >= 0 && lastSeparator < path.length() - 1) {
|
|
1673
|
+
return path.substring(lastSeparator + 1);
|
|
1674
|
+
}
|
|
1655
1675
|
|
|
1656
|
-
|
|
1657
|
-
}
|
|
1676
|
+
return path;
|
|
1677
|
+
}
|
|
1658
1678
|
|
|
1659
|
-
|
|
1679
|
+
/**
|
|
1660
1680
|
* Enables or disables displaying in full-screen mode, hiding the status and navigation bars.
|
|
1681
|
+
*
|
|
1661
1682
|
* @param isEnabled A boolean to enable/disable setFullscreen.
|
|
1662
1683
|
*/
|
|
1663
1684
|
@ReactMethod
|
|
@@ -1666,7 +1687,7 @@ private String getFileName(String path) {
|
|
|
1666
1687
|
@Override
|
|
1667
1688
|
public void run() {
|
|
1668
1689
|
try {
|
|
1669
|
-
|
|
1690
|
+
Luciq.setFullscreen(isEnabled);
|
|
1670
1691
|
} catch (Exception e) {
|
|
1671
1692
|
e.printStackTrace();
|
|
1672
1693
|
}
|
|
@@ -10,6 +10,7 @@ import com.facebook.react.bridge.WritableMap;
|
|
|
10
10
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
11
11
|
|
|
12
12
|
public abstract class EventEmitterModule extends ReactContextBaseJavaModule {
|
|
13
|
+
private static final String NET_TAG = "LCQ-RN-NET";
|
|
13
14
|
private int listenerCount = 0;
|
|
14
15
|
|
|
15
16
|
public EventEmitterModule(ReactApplicationContext context) {
|
|
@@ -22,14 +23,18 @@ public abstract class EventEmitterModule extends ReactContextBaseJavaModule {
|
|
|
22
23
|
getReactApplicationContext()
|
|
23
24
|
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
24
25
|
.emit(event, params);
|
|
26
|
+
} else {
|
|
27
|
+
LuciqRNLogger.w(NET_TAG, "[EventEmitter] Event DROPPED (no JS listeners): event=" + event + ", module=" + getName() + ", listenerCount=0");
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
protected void addListener(String ignoredEvent) {
|
|
29
32
|
listenerCount++;
|
|
33
|
+
LuciqRNLogger.d(NET_TAG, "[EventEmitter] addListener — module=" + getName() + ", event=" + ignoredEvent + ", listenerCount=" + listenerCount);
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
protected void removeListeners(Integer count) {
|
|
33
37
|
listenerCount -= count;
|
|
38
|
+
LuciqRNLogger.d(NET_TAG, "[EventEmitter] removeListeners — module=" + getName() + ", removed=" + count + ", listenerCount=" + listenerCount);
|
|
34
39
|
}
|
|
35
40
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
package ai.luciq.reactlibrary.utils;
|
|
2
|
+
|
|
3
|
+
import android.util.Log;
|
|
4
|
+
|
|
5
|
+
import ai.luciq.library.LogLevel;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Bridge-side logger that gates android.util.Log calls on the same
|
|
9
|
+
* debugLogsLevel the host app passes to Luciq.init(), so the native
|
|
10
|
+
* RN bridge diagnostic logs do not leak in production builds when the
|
|
11
|
+
* JS-side Logger is silent.
|
|
12
|
+
*
|
|
13
|
+
* Mirrors the level hierarchy in src/utils/logger.ts:
|
|
14
|
+
* VERBOSE > DEBUG > ERROR > NONE
|
|
15
|
+
*/
|
|
16
|
+
public final class LuciqRNLogger {
|
|
17
|
+
|
|
18
|
+
private static volatile int currentLevel = LogLevel.ERROR;
|
|
19
|
+
|
|
20
|
+
private LuciqRNLogger() {}
|
|
21
|
+
|
|
22
|
+
public static void setLevel(int level) {
|
|
23
|
+
currentLevel = level;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public static int getLevel() {
|
|
27
|
+
return currentLevel;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static void d(String tag, String message) {
|
|
31
|
+
if (currentLevel >= LogLevel.DEBUG) {
|
|
32
|
+
Log.d(tag, message);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public static void w(String tag, String message) {
|
|
37
|
+
if (currentLevel >= LogLevel.DEBUG) {
|
|
38
|
+
Log.w(tag, message);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public static void e(String tag, String message) {
|
|
43
|
+
if (currentLevel >= LogLevel.ERROR) {
|
|
44
|
+
Log.e(tag, message);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public static void e(String tag, String message, Throwable throwable) {
|
|
49
|
+
if (currentLevel >= LogLevel.ERROR) {
|
|
50
|
+
Log.e(tag, message, throwable);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
package/dist/modules/Luciq.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AppState, findNodeHandle, Platform } from 'react-native';
|
|
2
2
|
import Report from '../models/Report';
|
|
3
3
|
import { emitter, NativeEvents, NativeLuciq } from '../native/NativeLuciq';
|
|
4
|
-
import { registerFeatureFlagsListener } from '../utils/FeatureFlags';
|
|
4
|
+
import { registerFeatureFlagsListener, initFeatureFlagsCache } from '../utils/FeatureFlags';
|
|
5
5
|
import { LogLevel, NetworkInterceptionMode, ReproStepsMode, StringKey, } from '../utils/Enums';
|
|
6
6
|
import LuciqUtils, { checkNetworkRequestHandlers, resetNativeObfuscationListener, setApmNetworkFlagsIfChanged, stringifyIfNotString, } from '../utils/LuciqUtils';
|
|
7
7
|
import * as NetworkLogger from './NetworkLogger';
|
|
@@ -57,10 +57,19 @@ function reportCurrentViewForAndroid(screenName) {
|
|
|
57
57
|
* @param config SDK configurations. See {@link LuciqConfig} for more info.
|
|
58
58
|
*/
|
|
59
59
|
export const init = (config) => {
|
|
60
|
+
initFeatureFlagsCache();
|
|
60
61
|
if (Platform.OS === 'android') {
|
|
61
62
|
// Add android feature flags listener for android
|
|
62
63
|
registerFeatureFlagsListener();
|
|
63
64
|
addOnFeatureUpdatedListener(config);
|
|
65
|
+
// Enable the JS XHR interceptor synchronously so cold-start requests
|
|
66
|
+
// (fired before LCQ_ON_FEATURES_UPDATED_CALLBACK arrives) are captured.
|
|
67
|
+
handleNetworkInterceptionMode(config);
|
|
68
|
+
setApmNetworkFlagsIfChanged({
|
|
69
|
+
isNativeInterceptionFeatureEnabled: isNativeInterceptionFeatureEnabled,
|
|
70
|
+
hasAPMNetworkPlugin: hasAPMNetworkPlugin,
|
|
71
|
+
shouldEnableNativeInterception: shouldEnableNativeInterception,
|
|
72
|
+
});
|
|
64
73
|
}
|
|
65
74
|
else {
|
|
66
75
|
isNativeInterceptionFeatureEnabled = NativeNetworkLogger.isNativeInterceptionEnabled();
|