diff --git a/CHANGELOG.md b/CHANGELOG.md index abda7ed70..347fc17f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## [Unreleased](https://github.com/Instabug/Instabug-React-Native/compare/v15.0.1...dev) + +### Changed + +- **BREAKING** Remove deprecated APIs ([#1424](https://github.com/Instabug/Instabug-React-Native/pull/1424)). See migration guide for more details. + +### Added + +- Add support Advanced UI customization. ([#1411](https://github.com/Instabug/Instabug-React-Native/pull/1411)) + +- Add screen rendering monitoring functionality within the APM product. ([#1416](https://github.com/Instabug/Instabug-React-Native/pull/1416)) + +## [15.0.2](https://github.com/Instabug/Instabug-React-Native/compare/v15.2.0...dev) + +### Added + +- Add support for ignoreFlagSecure to bypass SDK screenshot security protocols on Android. ([#1394](https://github.com/Instabug/Instabug-React-Native/pull/1394)) + +### Fixed + +- async initialization. ([#1427](https://github.com/Instabug/Instabug-React-Native/pull/1427)) + ## [15.0.1](https://github.com/Instabug/Instabug-React-Native/compare/v14.3.0...v15.0.1) ### Added diff --git a/FONTS_SETUP_GUIDE.md b/FONTS_SETUP_GUIDE.md new file mode 100644 index 000000000..5c0c6c903 --- /dev/null +++ b/FONTS_SETUP_GUIDE.md @@ -0,0 +1,522 @@ +# Complete Font Setup Guide for Instabug React Native + +This guide covers all ways to use fonts with the `setTheme` function in Instabug React Native, including Google Fonts, custom fonts, system fonts, and both Expo and regular React Native projects. + +## Table of Contents + +1. [Overview](#overview) +2. [Font Types Supported](#font-types-supported) +3. [Regular React Native Setup](#regular-react-native-setup) +4. [Expo Setup](#expo-setup) +5. [Asset Linking Options](#asset-linking-options) +6. [Usage Examples](#usage-examples) +7. [Troubleshooting](#troubleshooting) +8. [Platform Compatibility Notes](#platform-compatibility-notes) + +## Overview + +The Instabug React Native bridge supports font loading from multiple sources: + +- **App Bundle**: Fonts included in your app assets +- **System Fonts**: Built-in platform fonts +- **Custom Fonts**: Any TTF/OTF font files +- **Google Fonts**: Downloaded TTF files from Google Fonts + +## Font Types Supported + +### 1. Google Fonts + +- Download TTF files from [Google Fonts](https://fonts.google.com/) +- Examples: Roboto, Inter, Nunito, Open Sans, Lato + +### 2. Custom Fonts + +- Any TTF/OTF font files +- Commercial fonts, free fonts, custom designs + +### 3. System Fonts + +- Platform default fonts +- No setup required +- Examples: San Francisco (iOS), Roboto (Android) + +## Regular React Native Setup + +### Method 1: Bundle Fonts (Recommended) + +#### Step 1: Download Font Files + +```bash +# Create fonts directory +mkdir fonts + +# Download your desired fonts (example with Google Fonts) +# Download from Google Fonts or any font provider +# Place TTF files in the fonts directory +``` + +#### Step 2: Add to Android + +```bash +# Create assets/fonts directory +mkdir -p android/app/src/main/assets/fonts + +# Copy font files +cp fonts/*.ttf android/app/src/main/assets/fonts/ +``` + +#### Step 3: Add to iOS + +1. **Add to Xcode Project:** + + - Open your iOS project in Xcode + - Right-click on your project → "Add Files to [ProjectName]" + - Select your TTF files + - Make sure "Add to target" is checked + +2. **Update Info.plist:** + +```xml +UIAppFonts + + Roboto-Regular.ttf + Roboto-Bold.ttf + Inter-Regular.ttf + Inter-Bold.ttf + +``` + +#### Step 4: Use with setTheme + +```typescript +import Instabug from 'instabug-reactnative'; +import { Platform } from 'react-native'; + +const applyCustomTheme = () => { + Instabug.setTheme({ + // Colors + primaryColor: '#2196F3', + backgroundColor: '#FFFFFF', + primaryTextColor: '#333333', + + // Text styles (Android only) + primaryTextStyle: 'normal', + secondaryTextStyle: 'normal', + ctaTextStyle: 'bold', + + // Fonts - Android (use font paths) + ...(Platform.OS === 'android' && { + primaryFontPath: '/data/user/0/com.yourapp/files/fonts/Roboto-Regular.ttf', + secondaryFontPath: '/data/user/0/com.yourapp/files/fonts/Roboto-Light.ttf', + ctaFontPath: '/data/user/0/com.yourapp/files/fonts/Roboto-Bold.ttf', + }), + + // Fonts - iOS (use font paths, not assets) + ...(Platform.OS === 'ios' && { + primaryFontPath: 'fonts/Roboto-Regular.ttf', + secondaryFontPath: 'fonts/Roboto-Light.ttf', + ctaFontPath: 'fonts/Roboto-Bold.ttf', + }), + }); +}; +``` + +### Method 2: System Fonts Only + +```typescript +import Instabug from 'instabug-reactnative'; + +const applySystemTheme = () => { + Instabug.setTheme({ + // Colors only - uses system fonts + primaryColor: '#2196F3', + backgroundColor: '#FFFFFF', + primaryTextColor: '#333333', + secondaryTextColor: '#666666', + titleTextColor: '#000000', + + // Text styles (Android only) + primaryTextStyle: 'normal', + secondaryTextStyle: 'normal', + ctaTextStyle: 'bold', + + // No font paths = uses system fonts + }); +}; +``` + +## Expo Setup + +### Method 1: Expo Fonts (Recommended for Expo) + +#### Step 1: Install Expo Fonts + +```bash +npx expo install expo-font +``` + +#### Step 2: Download and Add Fonts + +```bash +# Create fonts directory +mkdir fonts + +# Download your fonts and place them in the fonts directory +# Example: Roboto-Regular.ttf, Roboto-Bold.ttf, Inter-Regular.ttf +``` + +#### Step 3: Configure app.json + +```json +{ + "expo": { + "fonts": [ + { + "asset": "./fonts/Roboto-Regular.ttf", + "family": "Roboto-Regular" + }, + { + "asset": "./fonts/Roboto-Bold.ttf", + "family": "Roboto-Bold" + }, + { + "asset": "./fonts/Inter-Regular.ttf", + "family": "Inter-Regular" + } + ] + } +} +``` + +#### Step 4: Load Fonts in Your App + +```typescript +import * as Font from 'expo-font'; +import { useEffect, useState } from 'react'; + +export default function App() { + const [fontsLoaded, setFontsLoaded] = useState(false); + + useEffect(() => { + async function loadFonts() { + await Font.loadAsync({ + 'Roboto-Regular': require('./fonts/Roboto-Regular.ttf'), + 'Roboto-Bold': require('./fonts/Roboto-Bold.ttf'), + 'Inter-Regular': require('./fonts/Inter-Regular.ttf'), + }); + setFontsLoaded(true); + } + loadFonts(); + }, []); + + if (!fontsLoaded) { + return ; + } + + return ; +} +``` + +#### Step 5: Use with setTheme + +```typescript +import Instabug from 'instabug-reactnative'; +import { Platform } from 'react-native'; + +const applyExpoTheme = () => { + Instabug.setTheme({ + // Colors + primaryColor: '#2196F3', + backgroundColor: '#FFFFFF', + primaryTextColor: '#333333', + + // Text styles (Android only) + primaryTextStyle: 'normal', + secondaryTextStyle: 'normal', + ctaTextStyle: 'bold', + + // Fonts - use font paths for both platforms + primaryFontPath: 'fonts/Roboto-Regular.ttf', + secondaryFontPath: 'fonts/Inter-Regular.ttf', + ctaFontPath: 'fonts/Roboto-Bold.ttf', + }); +}; +``` + +### Method 2: Expo with Bundle Fonts + +Same as Regular React Native Method 1, but fonts are automatically included in the Expo build. + +## Asset Linking Options + +### Option 1: Manual Copy (Current Method) + +- Copy TTF files to native directories +- Update Info.plist manually +- Works with all setups + +### Option 2: React Native CLI Linking + +```bash +# Create a react-native.config.js file +module.exports = { + assets: ['./fonts/'], +}; +``` + +Then run: + +```bash +npx react-native link +``` + +### Option 3: Expo Asset Linking + +```json +{ + "expo": { + "fonts": [ + { + "asset": "./fonts/Roboto-Regular.ttf", + "family": "Roboto-Regular" + } + ] + } +} +``` + +### Option 4: Metro Asset Plugin + +```bash +npm install --save-dev react-native-asset +``` + +Create `react-native.config.js`: + +```javascript +module.exports = { + assets: ['./fonts/'], +}; +``` + +## Usage Examples + +### Example 1: Google Fonts (Roboto) + +```typescript +// Download: Roboto-Regular.ttf, Roboto-Bold.ttf, Roboto-Light.ttf +// Add to project using any method above + +const applyRobotoTheme = () => { + Instabug.setTheme({ + primaryColor: '#1976D2', + backgroundColor: '#FAFAFA', + primaryTextColor: '#212121', + secondaryTextColor: '#757575', + titleTextColor: '#000000', + + // Text styles (Android only) + primaryTextStyle: 'normal', + secondaryTextStyle: 'normal', + ctaTextStyle: 'bold', + + // Font paths for both platforms + primaryFontPath: 'fonts/Roboto-Regular.ttf', + secondaryFontPath: 'fonts/Roboto-Light.ttf', + ctaFontPath: 'fonts/Roboto-Bold.ttf', + }); +}; +``` + +### Example 2: Custom Fonts (Inter) + +```typescript +// Download: Inter-Regular.ttf, Inter-Bold.ttf, Inter-Medium.ttf +// Add to project using any method above + +const applyInterTheme = () => { + Instabug.setTheme({ + primaryColor: '#3B82F6', + backgroundColor: '#FFFFFF', + primaryTextColor: '#1F2937', + secondaryTextColor: '#6B7280', + titleTextColor: '#111827', + + // Text styles (Android only) + primaryTextStyle: 'normal', + secondaryTextStyle: 'normal', + ctaTextStyle: 'bold', + + // Font paths for both platforms + primaryFontPath: 'fonts/Inter-Regular.ttf', + secondaryFontPath: 'fonts/Inter-Medium.ttf', + ctaFontPath: 'fonts/Inter-Bold.ttf', + }); +}; +``` + +### Example 3: System Fonts Only + +```typescript +const applySystemTheme = () => { + Instabug.setTheme({ + primaryColor: '#007AFF', + backgroundColor: '#F2F2F7', + primaryTextColor: '#000000', + secondaryTextColor: '#8E8E93', + titleTextColor: '#000000', + + // Text styles (Android only) - no font paths = uses system fonts + primaryTextStyle: 'normal', + secondaryTextStyle: 'normal', + ctaTextStyle: 'bold', + }); +}; +``` + +### Example 4: Mixed Approach + +```typescript +const applyMixedTheme = () => { + Instabug.setTheme({ + primaryColor: '#FF6B6B', + backgroundColor: '#FFFFFF', + primaryTextColor: '#2D3436', + secondaryTextColor: '#636E72', + titleTextColor: '#2D3436', + + // Text styles (Android only) + primaryTextStyle: 'normal', + secondaryTextStyle: 'normal', + ctaTextStyle: 'bold', + + // Custom font only for CTA - rest use system fonts + ctaFontPath: 'fonts/Roboto-Bold.ttf', + }); +}; +``` + +## Platform Compatibility Notes + +### **Important: iOS Font Asset Limitation** + +The iOS implementation currently **only supports** `primaryFontPath`, `secondaryFontPath`, and `ctaFontPath` properties. The `*FontAsset` properties are **not supported** on iOS. + +**Android**: Supports both `*FontPath` and `*FontAsset` properties +**iOS**: Only supports `*FontPath` properties + +### **Recommended Approach** + +Use `*FontPath` properties for both platforms to ensure compatibility: + +```typescript +// ✅ Works on both platforms +Instabug.setTheme({ + primaryFontPath: 'fonts/Roboto-Regular.ttf', + secondaryFontPath: 'fonts/Roboto-Light.ttf', + ctaFontPath: 'fonts/Roboto-Bold.ttf', +}); + +// ❌ iOS doesn't support these +Instabug.setTheme({ + primaryFontAsset: 'fonts/Roboto-Regular.ttf', // iOS ignores this + secondaryFontAsset: 'fonts/Roboto-Light.ttf', // iOS ignores this + ctaFontAsset: 'fonts/Roboto-Bold.ttf', // iOS ignores this +}); +``` + +### **Font Path Format** + +- **Android**: Can use full paths or just filenames +- **iOS**: Use relative paths like `fonts/Roboto-Regular.ttf` + +## Troubleshooting + +### Common Issues + +#### 1. Font Not Loading + +**Symptoms:** Font appears as system font or doesn't change +**Solutions:** + +- Check font filename matches exactly (case-sensitive) +- Verify font is added to both Android and iOS +- For iOS, check Info.plist entries +- For Expo, ensure fonts are loaded before using setTheme +- **iOS users**: Make sure you're using `*FontPath` properties, not `*FontAsset` + +#### 2. Font Loading in Expo + +**Symptoms:** Font works in development but not in production +**Solutions:** + +- Use `expo-font` to load fonts before app starts +- Ensure fonts are included in app.json +- Test with `expo build` or EAS Build + +#### 3. Font File Issues + +**Symptoms:** App crashes or font doesn't load +**Solutions:** + +- Verify TTF file is not corrupted +- Check file size (should be reasonable, not 0 bytes) +- Ensure font file is valid TTF/OTF format + +#### 4. Performance Issues + +**Symptoms:** App slow to start or font loading delays +**Solutions:** + +- Use system fonts for better performance +- Limit number of custom fonts +- Preload fonts in app initialization + +### Debug Steps + +1. **Check Font Loading:** + +```typescript +// Add this to debug font loading +console.log('Available fonts:', Instabug.getAvailableFonts()); // If available +``` + +2. **Verify File Paths:** + +```bash +# Check if fonts are in the right place +ls -la android/app/src/main/assets/fonts/ +ls -la ios/YourApp/ +``` + +3. **Test with System Fonts First:** + +```typescript +// Test with system fonts to ensure setTheme works +Instabug.setTheme({ + primaryColor: '#FF0000', + // No fontFamily = system fonts +}); +``` + +## Best Practices + +1. **Use System Fonts When Possible:** Better performance and consistency +2. **Limit Custom Fonts:** Use 1-2 custom fonts maximum +3. **Preload Fonts:** Load fonts before app starts +4. **Test on Both Platforms:** Fonts may behave differently on iOS vs Android +5. **Use Standard Font Weights:** Regular, Bold, Light are most reliable +6. **Keep Font Files Small:** Optimize TTF files for mobile +7. **Use \*FontPath Properties:** Ensures compatibility with both platforms + +## Summary + +- **Regular React Native:** Use bundle fonts or system fonts +- **Expo:** Use expo-font or bundle fonts +- **Asset Linking:** Available through CLI tools and Expo config +- **Google Fonts:** Download TTF files and add to project +- **Custom Fonts:** Any TTF/OTF file works the same way +- **System Fonts:** No setup required, best performance +- **Platform Compatibility:** Use `*FontPath` properties for both platforms + +The native bridge handles all font loading automatically once fonts are properly added to your project! diff --git a/android/native.gradle b/android/native.gradle index d9c7a2f5b..70b9807e7 100644 --- a/android/native.gradle +++ b/android/native.gradle @@ -1,5 +1,5 @@ project.ext.instabug = [ - version: '15.0.2.7020723-SNAPSHOT' + version: '15.0.2.7085294-SNAPSHOT' ] dependencies { diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java index 9b6348ab4..7c0901936 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java @@ -19,7 +19,8 @@ public class RNInstabug { private static RNInstabug instance; - private RNInstabug() {} + private RNInstabug() { + } public static RNInstabug getInstance() { @@ -36,14 +37,13 @@ public static RNInstabug getInstance() { /** * Initializes the SDK on the native side, which is useful for capturing startup issues specific to the native part of the app. * - * @param application The application context. + * @param application The application context. * @param applicationToken The app's identifying token, available on your dashboard. - * @param logLevel The level of detail in logs that you want to print. - *

Pick one of the log levels described in {@link LogLevel}. - * default logLevel is {@link LogLevel#ERROR}

- * @param InvocationEvent The events that trigger the SDK's user interface. - * Choose from the available events listed in {@link InstabugInvocationEvent}. - * + * @param logLevel The level of detail in logs that you want to print. + *

Pick one of the log levels described in {@link LogLevel}. + * default logLevel is {@link LogLevel#ERROR}

+ * @param InvocationEvent The events that trigger the SDK's user interface. + * Choose from the available events listed in {@link InstabugInvocationEvent}. * @example

Here's an example usage:

*
      * RNInstabug.getInstance().init(
@@ -59,17 +59,24 @@ public void init(
             @NonNull Application application,
             @NonNull String applicationToken,
             int logLevel,
+            Boolean ignoreSecureFlag,
             @NonNull InstabugInvocationEvent... InvocationEvent
-    ) {
+            ) {
         try {
 
             setBaseUrlForDeprecationLogs();
             setCurrentPlatform();
 
-            new Instabug.Builder(application, applicationToken)
+            Instabug.Builder builder = new Instabug.Builder(application, applicationToken)
                     .setInvocationEvents(InvocationEvent)
-                    .setSdkDebugLogsLevel(logLevel)
-                    .build();
+                    .setSdkDebugLogsLevel(logLevel);
+
+            if (ignoreSecureFlag != null) {
+                builder.ignoreFlagSecure(ignoreSecureFlag);
+            }
+
+            builder.build();
+
 
             // Temporarily disabling APM hot launches
             APM.setHotAppLaunchEnabled(false);
@@ -80,15 +87,13 @@ public void init(
     }
 
 
-
     /**
      * Initializes the SDK on the native side, which is useful for capturing startup issues specific to the native part of the app.
      *
-     * @param application The application context.
+     * @param application      The application context.
      * @param applicationToken The app's identifying token, available on your dashboard.
-     * @param invocationEvent The events that trigger the SDK's user interface.
-     *      Choose from the available events listed in {@link InstabugInvocationEvent}.
-     *
+     * @param invocationEvent  The events that trigger the SDK's user interface.
+     *                         Choose from the available events listed in {@link InstabugInvocationEvent}.
      * @example 

Here's an example usage:

*
      * RNInstabug.getInstance().init(
@@ -104,7 +109,7 @@ public void init(
             @NonNull String applicationToken,
             @NonNull InstabugInvocationEvent... invocationEvent
     ) {
-        init(application, applicationToken, LogLevel.ERROR, invocationEvent);
+        init(application, applicationToken, LogLevel.ERROR,null, invocationEvent);
     }
 
     @VisibleForTesting
@@ -160,6 +165,7 @@ public static class Builder {
          * The events that trigger the SDK's user interface.
          */
         private InstabugInvocationEvent[] invocationEvents;
+        private Boolean ignoreFlagSecure;
 
 
         /**
@@ -210,6 +216,16 @@ public Builder setCodePushVersion(String codePushVersion) {
             return this;
         }
 
+        /**
+         * Sets flag to override SDK screenshot security behavior.
+         *
+         * @param ignoreFlagSecure flag to override SDK screenshot security behavior.
+         */
+        public Builder ignoreFlagSecure(boolean ignoreFlagSecure) {
+            this.ignoreFlagSecure = ignoreFlagSecure;
+            return this;
+        }
+
         /**
          * Sets the invocation triggering events for the SDK's user interface
          *
@@ -237,6 +253,10 @@ public void build() {
                     instabugBuilder.setCodePushVersion(codePushVersion);
                 }
 
+                if (ignoreFlagSecure != null) {
+                    instabugBuilder.ignoreFlagSecure(ignoreFlagSecure);
+                }
+
                 instabugBuilder.build();
 
                 // Temporarily disabling APM hot launches
diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java
index f6ef387c1..533ad95e0 100644
--- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java
+++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java
@@ -14,7 +14,6 @@
 import com.facebook.react.bridge.ReactMethod;
 import com.facebook.react.bridge.ReadableMap;
 import com.instabug.apm.APM;
-import com.instabug.apm.model.ExecutionTrace;
 import com.instabug.apm.networking.APMNetworkLogger;
 import com.instabug.apm.networkinterception.cp.APMCPNetworkLog;
 import com.instabug.reactlibrary.utils.EventEmitterModule;
@@ -31,8 +30,6 @@ public RNInstabugAPMModule(ReactApplicationContext reactApplicationContext) {
         super(reactApplicationContext);
     }
 
-    @Deprecated
-    HashMap traces = new HashMap();
 
     @Nonnull
     @Override
@@ -205,78 +202,6 @@ public void run() {
         });
     }
 
-    /**
-     * Starts an execution trace
-     *
-     * @param name string name of the trace.
-     * @deprecated see {@link #startFlow(String)}
-     */
-    @Deprecated
-    @ReactMethod
-    public void startExecutionTrace(final String name, final String id, final Promise promise) {
-        MainThreadHandler.runOnMainThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    String result = "";
-                    ExecutionTrace trace = APM.startExecutionTrace(name);
-                    if (trace != null) {
-                        result = id;
-                        traces.put(id, trace);
-                    }
-                    promise.resolve(result);
-                } catch (Exception e) {
-                    e.printStackTrace();
-                    promise.resolve(null);
-                }
-            }
-        });
-    }
-
-    /**
-     * Adds a new attribute to trace
-     *
-     * @param id    String id of the trace.
-     * @param key   attribute key
-     * @param value attribute value. Null to remove attribute
-     * @deprecated see {@link #setFlowAttribute}
-     */
-    @Deprecated
-    @ReactMethod
-    public void setExecutionTraceAttribute(final String id, final String key, final String value) {
-        MainThreadHandler.runOnMainThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    traces.get(id).setAttribute(key, value);
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        });
-    }
-
-    /**
-     * Ends a trace
-     *
-     * @param id string id of the trace.
-     * @deprecated see {@link #endFlow}
-     */
-    @Deprecated
-    @ReactMethod
-    public void endExecutionTrace(final String id) {
-        MainThreadHandler.runOnMainThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    traces.get(id).end();
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        });
-    }
-
     /**
      * Starts a UI trace
      *
@@ -471,7 +396,7 @@ private void networkLogAndroid(final double requestStartTime,
      * @param isEnabled boolean indicating enabled or disabled.
      */
     @ReactMethod
-    public void setScreenRenderEnabled(boolean isEnabled) {
+    public void setScreenRenderingEnabled(boolean isEnabled) {
         MainThreadHandler.runOnMainThread(new Runnable() {
             @Override
             public void run() {
diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugBugReportingModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugBugReportingModule.java
index 0dd9270e0..420011ddb 100644
--- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugBugReportingModule.java
+++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugBugReportingModule.java
@@ -389,7 +389,6 @@ public void run() {
             }
         });
     }
-
     /**
     * Sets a minimum number of characters as a requirement for the comments field in the different report types.
     * @param limit int number of characters.
@@ -410,8 +409,7 @@ public void run() {
                         typesInts[i] = types.get(i);
                     }
 
-                    BugReporting.setCommentMinimumCharacterCount(limit, typesInts);
-                } catch (Exception e) {
+                    BugReporting.setCommentMinimumCharacterCountForBugReportType(limit, typesInts);                } catch (Exception e) {
                     e.printStackTrace();
                 }
             }
diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java
index 8507993ad..a67024f0e 100644
--- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java
+++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java
@@ -6,10 +6,14 @@
 
 import android.app.Application;
 import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Typeface;
 import android.net.Uri;
 import android.util.Log;
 import android.view.View;
 
+import com.facebook.react.bridge.ReactApplicationContext;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.UiThread;
 
@@ -43,6 +47,7 @@
 import com.instabug.library.internal.module.InstabugLocale;
 import com.instabug.library.invocation.InstabugInvocationEvent;
 import com.instabug.library.logging.InstabugLog;
+import com.instabug.library.model.IBGTheme;
 import com.instabug.library.model.NetworkLog;
 import com.instabug.library.model.Report;
 import com.instabug.library.ui.onboarding.WelcomeMessage;
@@ -145,7 +150,8 @@ public void init(
             final ReadableArray invocationEventValues,
             final String logLevel,
             final boolean useNativeNetworkInterception,
-            @Nullable final String codePushVersion
+            @Nullable final String codePushVersion,
+            final ReadableMap map
     ) {
         MainThreadHandler.runOnMainThread(new Runnable() {
             @Override
@@ -163,6 +169,10 @@ public void run() {
                         .setInvocationEvents(invocationEvents)
                         .setLogLevel(parsedLogLevel);
 
+                if (map!=null&&map.hasKey("ignoreAndroidSecureFlag")) {
+                    builder.ignoreFlagSecure(map.getBoolean("ignoreAndroidSecureFlag"));
+                }
+
                 if (codePushVersion != null) {
                     if (Instabug.isBuilt()) {
                         Instabug.setCodePushVersion(codePushVersion);
@@ -278,26 +288,6 @@ public void run() {
         });
     }
 
-    /**
-     * Set the primary color that the SDK will use to tint certain UI elements in the SDK
-     *
-     * @param primaryColor The value of the primary color ,
-     *                     whatever this color was parsed from a resource color or hex color
-     *                     or RGB color values
-     */
-    @ReactMethod
-    public void setPrimaryColor(final int primaryColor) {
-        MainThreadHandler.runOnMainThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Instabug.setPrimaryColor(primaryColor);
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        });
-    }
 
     /**
      * Gets tags.
@@ -1033,60 +1023,7 @@ public void run() {
         });
     }
 
-    /**
-     * @deprecated see {@link #addFeatureFlags(ReadableArray)}
-     */
-    @ReactMethod
-    public void addExperiments(final ReadableArray experiments) {
-        MainThreadHandler.runOnMainThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Object[] objectArray = ArrayUtil.toArray(experiments);
-                    String[] stringArray = Arrays.copyOf(objectArray, objectArray.length, String[].class);
-                    Instabug.addExperiments(Arrays.asList(stringArray));
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        });
-    }
-
-    /**
-     * @deprecated see {@link #removeFeatureFlags(ReadableArray)}
-     */
-    @ReactMethod
-    public void removeExperiments(final ReadableArray experiments) {
-        MainThreadHandler.runOnMainThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Object[] objectArray = ArrayUtil.toArray(experiments);
-                    String[] stringArray = Arrays.copyOf(objectArray, objectArray.length, String[].class);
-                    Instabug.removeExperiments(Arrays.asList(stringArray));
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        });
-    }
-
-    /**
-     * @deprecated see {@link #removeAllFeatureFlags()}
-     */
-    @ReactMethod
-    public void clearAllExperiments() {
-        MainThreadHandler.runOnMainThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Instabug.clearAllExperiments();
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        });
-    }
+    
 
     @ReactMethod
     public void addFeatureFlags(final ReadableMap featureFlagsMap) {
@@ -1350,4 +1287,255 @@ public void run() {
             }
         });
     }
+    /**
+     * Sets the theme for Instabug using a configuration object.
+     *
+     * @param themeConfig A ReadableMap containing theme properties such as colors, fonts, and text styles.
+     */
+    @ReactMethod
+    public void setTheme(final ReadableMap themeConfig) {
+        MainThreadHandler.runOnMainThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    com.instabug.library.model.IBGTheme.Builder builder = new com.instabug.library.model.IBGTheme.Builder();
+
+                    // Apply colors
+                    applyColorIfPresent(themeConfig, builder, "primaryColor", (themeBuilder, color) -> themeBuilder.setPrimaryColor(color));
+                    applyColorIfPresent(themeConfig, builder, "secondaryTextColor", (themeBuilder, color) -> themeBuilder.setSecondaryTextColor(color));
+                    applyColorIfPresent(themeConfig, builder, "primaryTextColor", (themeBuilder, color) -> themeBuilder.setPrimaryTextColor(color));
+                    applyColorIfPresent(themeConfig, builder, "titleTextColor", (themeBuilder, color) -> themeBuilder.setTitleTextColor(color));
+                    applyColorIfPresent(themeConfig, builder, "backgroundColor", (themeBuilder, color) -> themeBuilder.setBackgroundColor(color));
+
+                    // Apply text styles
+                    applyTextStyleIfPresent(themeConfig, builder, "primaryTextStyle", (themeBuilder, style) -> themeBuilder.setPrimaryTextStyle(style));
+                    applyTextStyleIfPresent(themeConfig, builder, "secondaryTextStyle", (themeBuilder, style) -> themeBuilder.setSecondaryTextStyle(style));
+                    applyTextStyleIfPresent(themeConfig, builder, "ctaTextStyle", (themeBuilder, style) -> themeBuilder.setCtaTextStyle(style));
+                    setFontIfPresent(themeConfig, builder, "primaryFontPath", "primaryFontAsset", "primary");
+                    setFontIfPresent(themeConfig, builder, "secondaryFontPath", "secondaryFontAsset", "secondary");
+                    setFontIfPresent(themeConfig, builder, "ctaFontPath", "ctaFontAsset", "CTA");
+
+                    IBGTheme theme = builder.build();
+                    Instabug.setTheme(theme);
+
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+    
+    /**
+     * Retrieves a color value from the ReadableMap.
+     * 
+     * @param map The ReadableMap object.
+     * @param key The key to look for.
+     * @return The parsed color as an integer, or black if missing or invalid.
+     */
+    private int getColor(ReadableMap map, String key) {
+        try {
+            if (map != null && map.hasKey(key) && !map.isNull(key)) {
+                String colorString = map.getString(key);
+                return Color.parseColor(colorString);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return Color.BLACK;
+    }
+    
+    /**
+     * Retrieves a text style from the ReadableMap.
+     * 
+     * @param map The ReadableMap object.
+     * @param key The key to look for.
+     * @return The corresponding Typeface style, or Typeface.NORMAL if missing or invalid.
+     */
+    private int getTextStyle(ReadableMap map, String key) {
+        try {
+            if (map != null && map.hasKey(key) && !map.isNull(key)) {
+                String style = map.getString(key);
+                switch (style.toLowerCase()) {
+                    case "bold":
+                        return Typeface.BOLD;
+                    case "italic":
+                        return Typeface.ITALIC;
+                    case "bold_italic":
+                        return Typeface.BOLD_ITALIC;
+                    case "normal":
+                    default:
+                        return Typeface.NORMAL;
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return Typeface.NORMAL; 
+    }
+    
+
+
+    /**
+     * Applies a color to the theme builder if present in the configuration.
+     * 
+     * @param themeConfig The theme configuration map
+     * @param builder The theme builder
+     * @param key The configuration key
+     * @param setter The color setter function
+     */
+    private void applyColorIfPresent(ReadableMap themeConfig, com.instabug.library.model.IBGTheme.Builder builder, 
+                                   String key, java.util.function.BiConsumer setter) {
+        if (themeConfig.hasKey(key)) {
+            int color = getColor(themeConfig, key);
+            setter.accept(builder, color);
+        }
+    }
+
+    /**
+     * Applies a text style to the theme builder if present in the configuration.
+     * 
+     * @param themeConfig The theme configuration map
+     * @param builder The theme builder
+     * @param key The configuration key
+     * @param setter The text style setter function
+     */
+    private void applyTextStyleIfPresent(ReadableMap themeConfig, com.instabug.library.model.IBGTheme.Builder builder, 
+                                       String key, java.util.function.BiConsumer setter) {
+        if (themeConfig.hasKey(key)) {
+            int style = getTextStyle(themeConfig, key);
+            setter.accept(builder, style);
+        }
+    }
+
+    /**
+     * Sets a font on the theme builder if the font configuration is present in the theme config.
+     * 
+     * @param themeConfig The theme configuration map
+     * @param builder The theme builder
+     * @param fileKey The key for font file path
+     * @param assetKey The key for font asset path
+     * @param fontType The type of font (for logging purposes)
+     */
+    private void setFontIfPresent(ReadableMap themeConfig, com.instabug.library.model.IBGTheme.Builder builder, 
+                                 String fileKey, String assetKey, String fontType) {
+        if (themeConfig.hasKey(fileKey) || themeConfig.hasKey(assetKey)) {
+            Typeface typeface = getTypeface(themeConfig, fileKey, assetKey);
+            if (typeface != null) {
+                switch (fontType) {
+                    case "primary":
+                        builder.setPrimaryTextFont(typeface);
+                        break;
+                    case "secondary":
+                        builder.setSecondaryTextFont(typeface);
+                        break;
+                    case "CTA":
+                        builder.setCtaTextFont(typeface);
+                        break;
+                }
+            } else {
+                Log.e("InstabugModule", "Failed to load " + fontType + " font");
+            }
+        }
+    }
+    
+    /**
+     * Loads a Typeface from a file path.
+     * 
+     * @param fileName The filename to load
+     * @return The loaded Typeface or null if failed
+     */
+    private Typeface loadTypefaceFromFile(String fileName) {
+        try {
+            Typeface typeface = Typeface.create(fileName, Typeface.NORMAL);
+            if (typeface != null && !typeface.equals(Typeface.DEFAULT)) {
+                return typeface;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * Loads a Typeface from assets.
+     * 
+     * @param fileName The filename in assets/fonts/ directory
+     * @return The loaded Typeface or null if failed
+     */
+    private Typeface loadTypefaceFromAssets(String fileName) {
+        try {
+            return Typeface.createFromAsset(getReactApplicationContext().getAssets(), "fonts/" + fileName);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    private Typeface getTypeface(ReadableMap map, String fileKey, String assetKey) {
+        try {
+            if (fileKey != null && map.hasKey(fileKey) && !map.isNull(fileKey)) {
+                String fontPath = map.getString(fileKey);
+                String fileName = getFileName(fontPath);
+                
+                // Try loading from file first
+                Typeface typeface = loadTypefaceFromFile(fileName);
+                if (typeface != null) {
+                    return typeface;
+                }
+                
+                // Try loading from assets
+                typeface = loadTypefaceFromAssets(fileName);
+                if (typeface != null) {
+                    return typeface;
+                }
+            }
+
+            if (assetKey != null && map.hasKey(assetKey) && !map.isNull(assetKey)) {
+                String assetPath = map.getString(assetKey);
+                String fileName = getFileName(assetPath);
+                return loadTypefaceFromAssets(fileName);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return Typeface.DEFAULT;
+    }
+
+/**
+ * Extracts the filename from a path, removing any directory prefixes.
+ * 
+ * @param path The full path to the file
+ * @return Just the filename with extension
+ */
+private String getFileName(String path) {
+    if (path == null || path.isEmpty()) {
+        return path;
+    }
+    
+    int lastSeparator = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
+    if (lastSeparator >= 0 && lastSeparator < path.length() - 1) {
+        return path.substring(lastSeparator + 1);
+    }
+    
+    return path;
+}
+
+ /**
+     * Enables or disables displaying in full-screen mode, hiding the status and navigation bars.
+     * @param isEnabled A boolean to enable/disable setFullscreen.
+     */
+    @ReactMethod
+    public void setFullscreen(final boolean isEnabled) {
+        MainThreadHandler.runOnMainThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                        Instabug.setFullscreen(isEnabled);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
 }
diff --git a/android/src/test/java/com/instabug/reactlibrary/RNInstabugAPMModuleTest.java b/android/src/test/java/com/instabug/reactlibrary/RNInstabugAPMModuleTest.java
index 63445978f..1f4852081 100644
--- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugAPMModuleTest.java
+++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugAPMModuleTest.java
@@ -114,17 +114,6 @@ public void givenTruesetEnabled_whenQuery_thenShouldCallNativeApiWithEnabled() {
         APM.endAppLaunch();
     }
 
-    @Test
-    public void givenString$startExecutionTrace_whenQuery_thenShouldCallNativeApi() {
-        Promise promise = mock(Promise.class);
-        // when
-        apmModule.startExecutionTrace("trace", "1", promise);
-        // then
-        verify(APM.class, times(1));
-        APM.startExecutionTrace("trace");
-        verify(promise).resolve(any());
-    }
-
     @Test
     public void testStartFlow() {
         String appFlowName = "appFlowName";
@@ -156,34 +145,6 @@ public void testSetFlowAttribute() {
         mockAPM.verifyNoMoreInteractions();
     }
 
-    // @Test
-    // public void givenString$setExecutionTraceAttribute_whenQuery_thenShouldCallNativeApiWithIntArgs() {
-    //     // given
-    //     PowerMockito.mockStatic(APM.class);
-    //     ExecutionTrace trace = mock(ExecutionTrace.class);
-    //     Callback callback = mock(Callback.class);
-    //     // when
-    //     PowerMockito.whenNew(ExecutionTrace.class).withArguments("trace").thenReturn(trace);
-    //     apmModule.startExecutionTrace("trace", "1", callback);
-    //     apmModule.setExecutionTraceAttribute("trace", "key", "value");
-    //     // then
-    //     verify(trace).setAttribute("key", "value");
-    // }
-
-    // @Test
-    // public void givenTrace$endExecutionTrace_whenQuery_thenShouldCallNativeApiWithIntArgs() {
-    //     // given
-    //     PowerMockito.mockStatic(APM.class);
-    //     ExecutionTrace trace = mock(ExecutionTrace.class);
-    //     Callback callback = mock(Callback.class);
-    //     // when
-    //     PowerMockito.whenNew(ExecutionTrace.class).withArguments("trace").thenReturn(trace);
-    //     apmModule.startExecutionTrace("trace", "1", callback);
-    //     apmModule.endExecutionTrace("1");
-    //     // then
-    //     verify(trace).end();
-    // }
-
     @Test
     public void givenString$startUITrace_whenQuery_thenShouldCallNativeApiWithEnabled() {
 
@@ -207,7 +168,7 @@ public void testSetFlowAttribute() {
 
     @Test
     public void given$setScreenRenderEnabled_whenQuery_thenShouldCallNativeApiWithEnabled() {
-        apmModule.setScreenRenderEnabled(true);
+        apmModule.setScreenRenderingEnabled(true);
         // then
         verify(APM.class, times(1));
         APM.setScreenRenderingEnabled(true);
diff --git a/android/src/test/java/com/instabug/reactlibrary/RNInstabugBugReportingModuleTest.java b/android/src/test/java/com/instabug/reactlibrary/RNInstabugBugReportingModuleTest.java
index dc55e81a5..15cef0e2f 100644
--- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugBugReportingModuleTest.java
+++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugBugReportingModuleTest.java
@@ -359,8 +359,8 @@ public Object answer(InvocationOnMock invocation) {
         // then
         verify(BugReporting.class, VerificationModeFactory.times(1));
         int type1 = args.get(keysArray[0]);
-        
-        BugReporting.setCommentMinimumCharacterCount(count, type1);
+
+        BugReporting.setCommentMinimumCharacterCountForBugReportType(count, type1);
     }
     @Test
     public void TestAddUserConsent() {
diff --git a/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java b/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java
index f4f6f9bc1..c68d7778f 100644
--- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java
+++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java
@@ -193,18 +193,6 @@ public void tearDown() {
         Instabug.setUserData(data);
     }
 
-    @Test
-    public void givenArg$setPrimaryColor_whenQuery_thenShouldCallNativeApiWithArg() {
-        // given
-
-        int color = 3902;
-        // when
-        rnModule.setPrimaryColor(color);
-        // then
-        verify(Instabug.class,times(1));
-        Instabug.setPrimaryColor(color);
-    }
-
     @Test
     public void testSetCodePushVersion() {
         String codePushVersion = "123";
@@ -535,51 +523,6 @@ public void testIdentifyUserWithId() {
 
     }
 
-    @Test
-    public void givenArg$addExperiments_whenQuery_thenShouldCallNativeApiWithArg() {
-        // given
-        JavaOnlyArray array = new JavaOnlyArray();
-        array.pushString("exp1");
-        array.pushString("exp2");
-
-        // when
-        rnModule.addExperiments(array);
-
-        // then
-        verify(Instabug.class,times(1));
-        List expectedList = new ArrayList();
-        expectedList.add("exp1");
-        expectedList.add("exp2");
-        Instabug.addExperiments(expectedList);
-    }
-
-    @Test
-    public void givenArg$removeExperiments_whenQuery_thenShouldCallNativeApiWithArg() {
-        // given
-        JavaOnlyArray array = new JavaOnlyArray();
-        array.pushString("exp1");
-        array.pushString("exp2");
-
-        // when
-        rnModule.removeExperiments(array);
-
-        // then
-        verify(Instabug.class,times(1));
-        List expectedList = new ArrayList();
-        expectedList.add("exp1");
-        expectedList.add("exp2");
-        Instabug.removeExperiments(expectedList);
-    }
-
-    @Test
-    public void given$clearAllExperiments_whenQuery_thenShouldCallNativeApi() {
-        // when
-        rnModule.clearAllExperiments();
-
-        // then
-        verify(Instabug.class,times(1));
-        Instabug.clearAllExperiments();
-    }
 
     @Test
     public void testAddFeatureFlags() {
@@ -704,4 +647,72 @@ public void testGetNetworkBodyMaxSize_resolvesPromiseWithExpectedValue() {
         verify(promise).resolve(expected);
     }
 
+    @Test
+    public void testEnablSetFullScreen() {
+        boolean isEnabled = true;
+
+        // when
+        rnModule.setFullscreen(isEnabled);
+
+        // then
+        verify(Instabug.class, times(1));
+        Instabug.setFullscreen(isEnabled);
+    }
+
+    @Test
+    public void testDisableSetFullScreen() {
+        // given
+        boolean isEnabled = false;
+
+        // when
+        rnModule.setFullscreen(isEnabled);
+
+        // then
+        verify(Instabug.class, times(1));
+        Instabug.setFullscreen(isEnabled);
+    }
+
+    @Test
+    public void testSetTheme() {
+        // given
+        JavaOnlyMap themeConfig = new JavaOnlyMap();
+        themeConfig.putString("primaryColor", "#FF0000");
+        themeConfig.putString("primaryTextColor", "#00FF00");
+        themeConfig.putString("secondaryTextColor", "#0000FF");
+        themeConfig.putString("titleTextColor", "#FFFF00");
+        themeConfig.putString("backgroundColor", "#FF00FF");
+        themeConfig.putString("primaryTextStyle", "bold");
+        themeConfig.putString("secondaryTextStyle", "italic");
+        themeConfig.putString("ctaTextStyle", "bold");
+
+        // Mock IBGTheme.Builder
+        com.instabug.library.model.IBGTheme.Builder mockBuilder = mock(com.instabug.library.model.IBGTheme.Builder.class);
+        com.instabug.library.model.IBGTheme mockTheme = mock(com.instabug.library.model.IBGTheme.class);
+        
+        try (MockedConstruction mockedBuilder = mockConstruction(
+                com.instabug.library.model.IBGTheme.Builder.class,
+                (mock, context) -> {
+                    when(mock.setPrimaryColor(anyInt())).thenReturn(mock);
+                    when(mock.setPrimaryTextColor(anyInt())).thenReturn(mock);
+                    when(mock.setSecondaryTextColor(anyInt())).thenReturn(mock);
+                    when(mock.setTitleTextColor(anyInt())).thenReturn(mock);
+                    when(mock.setBackgroundColor(anyInt())).thenReturn(mock);
+                    when(mock.setPrimaryTextStyle(anyInt())).thenReturn(mock);
+                    when(mock.setSecondaryTextStyle(anyInt())).thenReturn(mock);
+                    when(mock.setCtaTextStyle(anyInt())).thenReturn(mock);
+                    when(mock.setPrimaryTextFont(any())).thenReturn(mock);
+                    when(mock.setSecondaryTextFont(any())).thenReturn(mock);
+                    when(mock.setCtaTextFont(any())).thenReturn(mock);
+                    when(mock.build()).thenReturn(mockTheme);
+                })) {
+
+            // when
+            rnModule.setTheme(themeConfig);
+
+            // then
+            verify(Instabug.class, times(1));
+            Instabug.setTheme(mockTheme);
+        }
+    }
+
 }
diff --git a/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java b/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java
index df169df1e..625eab1c9 100644
--- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java
+++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java
@@ -4,6 +4,7 @@
 import static com.instabug.reactlibrary.util.GlobalMocks.reflected;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockConstruction;
@@ -62,18 +63,20 @@ public void testInitWithLogLevel() {
                     // Initializes Instabug with the correct token
                     assertEquals(token, actualToken);
                     when(mock.setSdkDebugLogsLevel(anyInt())).thenReturn(mock);
+                    when(mock.ignoreFlagSecure(anyBoolean())).thenReturn(mock);
                     when(mock.setInvocationEvents(any())).thenReturn(mock);
                 });
 
-        sut.init(mContext, token, logLevel, invocationEvents);
+        sut.init(mContext, token, logLevel, true, invocationEvents);
 
         Instabug.Builder builder = mInstabugBuilder.constructed().get(0);
 
         // Here we check that it has changed to verbose value of the `logLevel` property
         verify(builder).setSdkDebugLogsLevel(LogLevel.VERBOSE);
         verify(builder).setInvocationEvents(invocationEvents);
-        verify(builder).build();
+        verify(builder).ignoreFlagSecure(true);
 
+        verify(builder).build();
 
 
         verify(sut).setBaseUrlForDeprecationLogs();
@@ -95,7 +98,7 @@ public void testInitWithoutLogLevel() {
 
         sut.init(mContext, token, invocationEvents);
 
-        verify(sut).init(mContext, token, defaultLogLevel, invocationEvents);
+        verify(sut).init(mContext, token, defaultLogLevel, null,invocationEvents);
         mInstabugBuilder.close();
     }
 
diff --git a/examples/default/ios/InstabugTests/InstabugAPMTests.m b/examples/default/ios/InstabugTests/InstabugAPMTests.m
index cac456550..6960be2d5 100644
--- a/examples/default/ios/InstabugTests/InstabugAPMTests.m
+++ b/examples/default/ios/InstabugTests/InstabugAPMTests.m
@@ -86,53 +86,6 @@ - (void) testSetAutoUITraceEnabled {
   OCMVerify([mock setAutoUITraceEnabled:isEnabled]);
 }
 
-- (void) testStartExecutionTrace {
-  id mock = OCMClassMock([IBGAPM class]);
-  NSString* traceName = @"Trace_1";
-  NSString* traceKey = @"1";
-  RCTPromiseResolveBlock resolve = ^(id result) {};
-  RCTPromiseRejectBlock reject = ^(NSString *code, NSString *message, NSError *error) {};
-
-  OCMStub([mock startExecutionTraceWithName:traceName]);
-  [self.instabugBridge startExecutionTrace:traceName :traceKey :resolve :reject];
-  OCMVerify([mock startExecutionTraceWithName:traceName]);
-}
-
-- (void) testSetExecutionTraceAttribute {
-  NSString* traceName = @"Trace_1";
-  NSString* traceId = @"Id_1";
-  NSString* traceKey = @"Key_1";
-  NSString* traceValue = @"1";
-  RCTPromiseResolveBlock resolve = ^(id result) {};
-  RCTPromiseRejectBlock reject = ^(NSString *code, NSString *message, NSError *error) {};
-  IBGExecutionTrace * trace = [IBGExecutionTrace alloc];
-  id mock = OCMClassMock([IBGAPM class]);
-  id traceMock = OCMPartialMock(trace);
-
-  OCMStub([mock startExecutionTraceWithName:traceName]).andReturn(trace);
-  [self.instabugBridge startExecutionTrace:traceName :traceId :resolve :reject];
-
-  OCMStub([traceMock setAttributeWithKey:traceKey value:traceValue]);
-  [self.instabugBridge setExecutionTraceAttribute:traceId :traceKey :traceValue];
-  OCMVerify([traceMock setAttributeWithKey:traceKey value:traceValue]);
-}
-
-- (void) testEndExecutionTrace {
-  NSString* traceName = @"Trace_1";
-  NSString* traceId = @"Id_1";
-  RCTPromiseResolveBlock resolve = ^(id result) {};
-  RCTPromiseRejectBlock reject = ^(NSString *code, NSString *message, NSError *error) {};
-  IBGExecutionTrace * trace = [IBGExecutionTrace alloc];
-  id apmMock = OCMClassMock([IBGAPM class]);
-  id traceMock = OCMPartialMock(trace);
-
-  OCMStub([apmMock startExecutionTraceWithName:traceName]).andReturn(trace);
-  [self.instabugBridge startExecutionTrace:traceName :traceId :resolve :reject];
-
-  OCMStub([traceMock end]);
-  [self.instabugBridge endExecutionTrace:traceId];
-  OCMVerify([traceMock end]);
-}
 
 - (void) testStartFlow {
   id mock = OCMClassMock([IBGAPM class]);
@@ -181,7 +134,7 @@ - (void) testSetScreenRenderEnabled {
     id mock = OCMClassMock([IBGAPM class]);
     BOOL isEnabled = YES;
 
-    [self.instabugBridge setScreenRenderEnabled:isEnabled];
+    [self.instabugBridge setScreenRenderingEnabled:isEnabled];
 
     OCMVerify([mock setScreenRenderingEnabled:YES]);
 }
@@ -190,7 +143,7 @@ - (void) testSetScreenRenderDisabled {
     id mock = OCMClassMock([IBGAPM class]);
     BOOL isEnabled = NO;
 
-    [self.instabugBridge setScreenRenderEnabled:isEnabled];
+    [self.instabugBridge setScreenRenderingEnabled:isEnabled];
 
     OCMVerify([mock setScreenRenderingEnabled:NO]);
 }
diff --git a/examples/default/ios/InstabugTests/InstabugBugReportingTests.m b/examples/default/ios/InstabugTests/InstabugBugReportingTests.m
index f0b6f97ec..4d0250dc1 100644
--- a/examples/default/ios/InstabugTests/InstabugBugReportingTests.m
+++ b/examples/default/ios/InstabugTests/InstabugBugReportingTests.m
@@ -175,18 +175,6 @@ - (void) testSetDisclaimerText {
   OCMVerify([mock setDisclaimerText:text]);
 }
 
-- (void) testSetCommentMinimumCharacterCount {
-  id mock = OCMClassMock([IBGBugReporting class]);
-  NSNumber *limit = [NSNumber numberWithInt:20];
-  NSArray *reportTypesArr = [NSArray arrayWithObjects: @(IBGReportTypeBug), nil];
-  IBGBugReportingReportType reportTypes = 0;
-  for (NSNumber *reportType in reportTypesArr) {
-    reportTypes |= [reportType intValue];
-  }
-  OCMStub([mock setCommentMinimumCharacterCountForReportTypes:reportTypes withLimit:limit.intValue]);
-  [self.instabugBridge setCommentMinimumCharacterCount:limit reportTypes:reportTypesArr];
-  OCMVerify([mock setCommentMinimumCharacterCountForReportTypes:reportTypes withLimit:limit.intValue]);
-}
 - (void)testAddUserConsentWithKey {
   id mock = OCMClassMock([IBGBugReporting class]);
 
diff --git a/examples/default/ios/InstabugTests/InstabugSampleTests.m b/examples/default/ios/InstabugTests/InstabugSampleTests.m
index ded37c3af..b363af1d5 100644
--- a/examples/default/ios/InstabugTests/InstabugSampleTests.m
+++ b/examples/default/ios/InstabugTests/InstabugSampleTests.m
@@ -75,7 +75,9 @@ - (void)testInit {
 
   OCMStub([mock setCodePushVersion:codePushVersion]);
 
-  [self.instabugBridge init:appToken invocationEvents:invocationEvents debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception codePushVersion:codePushVersion];
+  [self.instabugBridge init:appToken invocationEvents:invocationEvents debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception codePushVersion:codePushVersion
+    options:nil
+  ];
   OCMVerify([mock setCodePushVersion:codePushVersion]);
 
   OCMVerify([self.mRNInstabug initWithToken:appToken invocationEvents:floatingButtonInvocationEvent debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception]);
@@ -141,19 +143,6 @@ - (void)testSetColorTheme {
   [self waitForExpectationsWithTimeout:EXPECTATION_TIMEOUT handler:nil];
 }
 
-- (void)testSetPrimaryColor {
-  UIColor *color = [UIColor whiteColor];
-  XCTestExpectation *expectation = [self expectationWithDescription:@"Testing [Instabug setPrimaryColor]"];
-
-  [self.instabugBridge setPrimaryColor:color];
-  [[NSRunLoop mainRunLoop] performBlock:^{
-    XCTAssertEqualObjects(Instabug.tintColor, color);
-    [expectation fulfill];
-  }];
-
-  [self waitForExpectationsWithTimeout:EXPECTATION_TIMEOUT handler:nil];
-}
-
 - (void)testAppendTags {
   id mock = OCMClassMock([Instabug class]);
   NSArray *tags = @[@"tag1", @"tag2"];
@@ -239,7 +228,7 @@ - (void)testSetReproStepsConfig {
   [self.instabugBridge setReproStepsConfig:bugMode :crashMode :sessionReplayMode];
 
   OCMVerify([mock setReproStepsFor:IBGIssueTypeBug withMode:bugMode]);
-  OCMVerify([mock setReproStepsFor:IBGIssueTypeCrash withMode:crashMode]);
+  OCMVerify([mock setReproStepsFor:IBGIssueTypeAllCrashes withMode:crashMode]);
  OCMVerify([mock setReproStepsFor:IBGIssueTypeSessionReplay withMode:sessionReplayMode]);
 }
 
@@ -486,30 +475,6 @@ - (void)testClearLogs {
   OCMVerify([mock clearAllLogs]);
 }
 
-- (void)testAddExperiments {
-  id mock = OCMClassMock([Instabug class]);
-  NSArray *experiments = @[@"exp1", @"exp2"];
-
-  OCMStub([mock addExperiments:experiments]);
-  [self.instabugBridge addExperiments:experiments];
-  OCMVerify([mock addExperiments:experiments]);
-}
-
-- (void)testRemoveExperiments {
-  id mock = OCMClassMock([Instabug class]);
-  NSArray *experiments = @[@"exp1", @"exp2"];
-
-  OCMStub([mock removeExperiments:experiments]);
-  [self.instabugBridge removeExperiments:experiments];
-  OCMVerify([mock removeExperiments:experiments]);
-}
-
-- (void)testClearAllExperiments {
-  id mock = OCMClassMock([Instabug class]);
-  OCMStub([mock clearAllExperiments]);
-  [self.instabugBridge clearAllExperiments];
-  OCMVerify([mock clearAllExperiments]);
-}
 
 - (void)testAddFeatureFlags {
   id mock = OCMClassMock([Instabug class]);
@@ -610,18 +575,18 @@ - (void) testIsW3CaughtHeaderEnabled {
 
 - (void)testEnableAutoMasking {
     id mock = OCMClassMock([Instabug class]);
-     
+
     NSArray *autoMaskingTypes = [NSArray arrayWithObjects:
          [NSNumber numberWithInteger:IBGAutoMaskScreenshotOptionLabels],
          [NSNumber numberWithInteger:IBGAutoMaskScreenshotOptionTextInputs],
          [NSNumber numberWithInteger:IBGAutoMaskScreenshotOptionMedia],
          [NSNumber numberWithInteger:IBGAutoMaskScreenshotOptionMaskNothing],
          nil];
-     
+
      OCMStub([mock setAutoMaskScreenshots:IBGAutoMaskScreenshotOptionLabels | IBGAutoMaskScreenshotOptionTextInputs | IBGAutoMaskScreenshotOptionMedia | IBGAutoMaskScreenshotOptionMaskNothing]);
-     
+
      [self.instabugBridge enableAutoMasking:autoMaskingTypes];
- 
+
      OCMVerify([mock setAutoMaskScreenshots:IBGAutoMaskScreenshotOptionLabels | IBGAutoMaskScreenshotOptionTextInputs | IBGAutoMaskScreenshotOptionMedia | IBGAutoMaskScreenshotOptionMaskNothing]);
 }
 
@@ -651,6 +616,73 @@ - (void)testGetNetworkBodyMaxSize {
 
     OCMVerify(ClassMethod([mock getNetworkBodyMaxSize]));
 }
+- (void)testSetTheme {
+    id mock = OCMClassMock([Instabug class]);
+    id mockTheme = OCMClassMock([IBGTheme class]);
+    
+    // Create theme configuration dictionary
+    NSDictionary *themeConfig = @{
+        @"primaryColor": @"#FF0000",
+        @"backgroundColor": @"#00FF00",
+        @"titleTextColor": @"#0000FF",
+        @"subtitleTextColor": @"#FFFF00",
+        @"primaryTextColor": @"#FF00FF",
+        @"secondaryTextColor": @"#00FFFF",
+        @"callToActionTextColor": @"#800080",
+        @"headerBackgroundColor": @"#808080",
+        @"footerBackgroundColor": @"#C0C0C0",
+        @"rowBackgroundColor": @"#FFFFFF",
+        @"selectedRowBackgroundColor": @"#E6E6FA",
+        @"rowSeparatorColor": @"#D3D3D3",
+        @"primaryFontPath": @"TestFont.ttf",
+        @"secondaryFontPath": @"fonts/AnotherFont.ttf",
+        @"ctaFontPath": @"./assets/fonts/CTAFont.ttf"
+    };
+
+    // Mock IBGTheme creation and configuration
+    OCMStub([mockTheme primaryColor]).andReturn([UIColor redColor]);
+    OCMStub([mockTheme backgroundColor]).andReturn([UIColor greenColor]);
+    OCMStub([mockTheme titleTextColor]).andReturn([UIColor blueColor]);
+    OCMStub([mockTheme subtitleTextColor]).andReturn([UIColor yellowColor]);
+    OCMStub([mockTheme primaryTextColor]).andReturn([UIColor magentaColor]);
+    OCMStub([mockTheme secondaryTextColor]).andReturn([UIColor cyanColor]);
+    OCMStub([mockTheme callToActionTextColor]).andReturn([UIColor purpleColor]);
+    OCMStub([mockTheme headerBackgroundColor]).andReturn([UIColor grayColor]);
+    OCMStub([mockTheme footerBackgroundColor]).andReturn([UIColor lightGrayColor]);
+    OCMStub([mockTheme rowBackgroundColor]).andReturn([UIColor whiteColor]);
+    OCMStub([mockTheme selectedRowBackgroundColor]).andReturn([UIColor redColor]);
+    OCMStub([mockTheme rowSeparatorColor]).andReturn([UIColor lightGrayColor]);
+    OCMStub([mockTheme primaryTextFont]).andReturn([UIFont systemFontOfSize:17.0]);
+    OCMStub([mockTheme secondaryTextFont]).andReturn([UIFont systemFontOfSize:17.0]);
+    OCMStub([mockTheme callToActionTextFont]).andReturn([UIFont systemFontOfSize:17.0]);
+
+    // Mock theme property setting
+    OCMStub([mockTheme setPrimaryColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setBackgroundColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setTitleTextColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setSubtitleTextColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setPrimaryTextColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setSecondaryTextColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setCallToActionTextColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setHeaderBackgroundColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setFooterBackgroundColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setRowBackgroundColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setSelectedRowBackgroundColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setRowSeparatorColor:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setPrimaryTextFont:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setSecondaryTextFont:[OCMArg any]]).andReturn(mockTheme);
+    OCMStub([mockTheme setCallToActionTextFont:[OCMArg any]]).andReturn(mockTheme);
+
+    // Mock Instabug.theme property
+    OCMStub([mock theme]).andReturn(mockTheme);
+    OCMStub([mock setTheme:[OCMArg any]]);
+
+    // Call the method
+    [self.instabugBridge setTheme:themeConfig];
+
+    // Verify that setTheme was called
+    OCMVerify([mock setTheme:[OCMArg any]]);
+}
 
 
 @end
diff --git a/examples/default/ios/Podfile b/examples/default/ios/Podfile
index 0d3e454c6..154cc210f 100644
--- a/examples/default/ios/Podfile
+++ b/examples/default/ios/Podfile
@@ -15,7 +15,7 @@ target 'InstabugExample' do
   config = use_native_modules!
   rn_maps_path = '../node_modules/react-native-maps'
   pod 'react-native-google-maps', :path => rn_maps_path
-  pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.26/Instabug.podspec'
+  pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec'
   # Flags change depending on the env values.
   flags = get_default_flags()
 
diff --git a/examples/default/ios/Podfile.lock b/examples/default/ios/Podfile.lock
index eab18a2da..79340aafa 100644
--- a/examples/default/ios/Podfile.lock
+++ b/examples/default/ios/Podfile.lock
@@ -31,7 +31,7 @@ PODS:
   - hermes-engine (0.75.4):
     - hermes-engine/Pre-built (= 0.75.4)
   - hermes-engine/Pre-built (0.75.4)
-  - Instabug (15.1.26)
+  - Instabug (15.1.31)
   - instabug-reactnative-ndk (0.1.0):
     - DoubleConversion
     - glog
@@ -1625,8 +1625,8 @@ PODS:
     - ReactCommon/turbomodule/bridging
     - ReactCommon/turbomodule/core
     - Yoga
-  - RNInstabug (15.0.1):
-    - Instabug (= 15.1.26)
+  - RNInstabug (15.0.2):
+    - Instabug (= 15.1.31)
     - React-Core
   - RNReanimated (3.16.1):
     - DoubleConversion
@@ -1770,7 +1770,7 @@ DEPENDENCIES:
   - fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`)
   - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
   - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
-  - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.26/Instabug.podspec`)
+  - Instabug (from `https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec`)
   - instabug-reactnative-ndk (from `../node_modules/instabug-reactnative-ndk`)
   - OCMock
   - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
@@ -1869,7 +1869,7 @@ EXTERNAL SOURCES:
     :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
     :tag: hermes-2024-08-15-RNv0.75.1-4b3bf912cc0f705b51b71ce1a5b8bd79b93a451b
   Instabug:
-    :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.26/Instabug.podspec
+    :podspec: https://ios-releases.instabug.com/custom/faeture-screen_rendering-release/15.1.31/Instabug.podspec
   instabug-reactnative-ndk:
     :path: "../node_modules/instabug-reactnative-ndk"
   RCT-Folly:
@@ -2024,7 +2024,7 @@ SPEC CHECKSUMS:
   Google-Maps-iOS-Utils: f77eab4c4326d7e6a277f8e23a0232402731913a
   GoogleMaps: 032f676450ba0779bd8ce16840690915f84e57ac
   hermes-engine: ea92f60f37dba025e293cbe4b4a548fd26b610a0
-  Instabug: c47bd604b5212496da79b19b368eb5de73833d69
+  Instabug: 447d3f5a9f1c83120235437e08c9a51aaa8f8605
   instabug-reactnative-ndk: d765ac289d56e8896398d02760d9abf2562fc641
   OCMock: 589f2c84dacb1f5aaf6e4cec1f292551fe748e74
   RCT-Folly: 4464f4d875961fce86008d45f4ecf6cef6de0740
@@ -2092,14 +2092,14 @@ SPEC CHECKSUMS:
   ReactCommon: 6a952e50c2a4b694731d7682aaa6c79bc156e4ad
   RNCClipboard: 2821ac938ef46f736a8de0c8814845dde2dcbdfb
   RNGestureHandler: 511250b190a284388f9dd0d2e56c1df76f14cfb8
-  RNInstabug: 35bf420d77731598fae13c33ceecf0343fd8dd99
+  RNInstabug: cdd10d22a6950eeb3426f748895b1c1597fcab6b
   RNReanimated: f42a5044d121d68e91680caacb0293f4274228eb
   RNScreens: c7ceced6a8384cb9be5e7a5e88e9e714401fd958
   RNSVG: 8b1a777d54096b8c2a0fd38fc9d5a454332bbb4d
   RNVectorIcons: 6382277afab3c54658e9d555ee0faa7a37827136
   SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
-  Yoga: aa3df615739504eebb91925fc9c58b4922ea9a08
+  Yoga: 055f92ad73f8c8600a93f0e25ac0b2344c3b07e6
 
-PODFILE CHECKSUM: 4e2ae668f4fb59c72dfd359d3d9c86ec6d4967e5
+PODFILE CHECKSUM: 3f4c318b317eb96e022a39eb0a81a414f5d95205
 
-COCOAPODS: 1.15.2
+COCOAPODS: 1.14.0
diff --git a/examples/default/react-native.config.js b/examples/default/react-native.config.js
new file mode 100644
index 000000000..cbdf34c94
--- /dev/null
+++ b/examples/default/react-native.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+  assets: ['./assets/fonts/'],
+};
diff --git a/examples/default/src/App.tsx b/examples/default/src/App.tsx
index 703932594..af84d5983 100644
--- a/examples/default/src/App.tsx
+++ b/examples/default/src/App.tsx
@@ -1,5 +1,5 @@
-import React, { useEffect, useState } from 'react';
-import { ActivityIndicator, StyleSheet } from 'react-native';
+import React, { useEffect } from 'react';
+import { StyleSheet } from 'react-native';
 
 import { GestureHandlerRootView } from 'react-native-gesture-handler';
 import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
@@ -41,43 +41,31 @@ export const App: React.FC = () => {
 
   const navigationRef = useNavigationContainerRef();
 
-  const [isInstabugInitialized, setIsInstabugInitialized] = useState(false);
-
   const initializeInstabug = () => {
-    // Synchronous setup
-    SessionReplay.setSyncCallback((data) => shouldSyncSession(data));
-
-    // Start async initialization but don't block rendering
-    Instabug.init({
-      token: 'deb1910a7342814af4e4c9210c786f35',
-      invocationEvents: [InvocationEvent.floatingButton],
-      debugLogsLevel: LogLevel.verbose,
-      networkInterceptionMode: NetworkInterceptionMode.javascript,
-    })
-      .then(() => {
-        // Post-initialization setup
-        NetworkLogger.setNetworkDataObfuscationHandler(async (networkData) => {
-          networkData.url = `${networkData.url}/JS/Obfuscated`;
-          return networkData;
-        });
-        APM.setScreenRenderEnabled(true);
-        setIsInstabugInitialized(true);
-      })
-      .catch((error) => {
-        console.error('Instabug initialization failed:', error);
-        setIsInstabugInitialized(true); // Proceed even if initialization fails
+    try {
+      SessionReplay.setSyncCallback((data) => shouldSyncSession(data));
+
+      Instabug.init({
+        token: 'deb1910a7342814af4e4c9210c786f35',
+        invocationEvents: [InvocationEvent.floatingButton],
+        debugLogsLevel: LogLevel.verbose,
+        networkInterceptionMode: NetworkInterceptionMode.javascript,
       });
 
-    // Synchronous configuration that doesn't depend on init completion
-    CrashReporting.setNDKCrashesEnabled(true);
-    Instabug.setReproStepsConfig({ all: ReproStepsMode.enabled });
-
-    // Set initialized immediately to show UI - initialization continues in background
-    setIsInstabugInitialized(true);
+      CrashReporting.setNDKCrashesEnabled(true);
+      Instabug.setReproStepsConfig({ all: ReproStepsMode.enabled });
+    } catch (error) {
+      console.error('Instabug initialization failed:', error);
+    }
   };
 
   useEffect(() => {
     initializeInstabug();
+    APM.setScreenRenderingEnabled(true);
+    NetworkLogger.setNetworkDataObfuscationHandler(async (networkData) => {
+      networkData.url = `${networkData.url}/JS/Obfuscated`;
+      return networkData;
+    });
   });
 
   useEffect(() => {
@@ -87,10 +75,6 @@ export const App: React.FC = () => {
     return unregisterListener;
   }, [navigationRef]);
 
-  if (!isInstabugInitialized) {
-    return ;
-  }
-
   return (
     
       
diff --git a/examples/default/src/navigation/HomeStack.tsx b/examples/default/src/navigation/HomeStack.tsx
index 0eafe75cb..94e461ed5 100644
--- a/examples/default/src/navigation/HomeStack.tsx
+++ b/examples/default/src/navigation/HomeStack.tsx
@@ -22,7 +22,6 @@ import {
 import { GoogleMapsScreen } from '../screens/user-steps/GoogleMapsScreen';
 import { LargeImageListScreen } from '../screens/user-steps/LargeImageListScreen';
 import { APMScreen } from '../screens/apm/APMScreen';
-import { ExecutionTraceScreen } from '../screens/apm/ExecutionTraceScreen';
 import { CustomUITraceScreen } from '../screens/apm/CustomUITraceScreen';
 import { NetworkScreen } from '../screens/apm/NetworkScreen';
 import { FlowsScreen } from '../screens/apm/FlowsScreen';
@@ -58,7 +57,6 @@ export type HomeStackParamList = {
   // APM //
   APM: undefined;
   NetworkTraces: undefined;
-  ExecutionTraces: undefined;
   CustomUITraces: undefined;
   AppFlows: undefined;
   WebViews: undefined;
@@ -144,7 +142,6 @@ export const HomeStackNavigator: React.FC = () => {
       
       
       
-      
       
       
        APM.endAppLaunch()} />
        navigation.navigate('NetworkTraces')} />
-       navigation.navigate('ExecutionTraces')} />
        navigation.navigate('CustomUITraces')} />
        navigation.navigate('AppFlows')} />
        navigation.navigate('WebViews')} />
diff --git a/examples/default/src/screens/apm/ExecutionTraceScreen.tsx b/examples/default/src/screens/apm/ExecutionTraceScreen.tsx
index c25c14cae..e69de29bb 100644
--- a/examples/default/src/screens/apm/ExecutionTraceScreen.tsx
+++ b/examples/default/src/screens/apm/ExecutionTraceScreen.tsx
@@ -1,70 +0,0 @@
-import React, { useState } from 'react';
-import { APM, Trace } from 'instabug-reactnative';
-import { ScrollView } from 'react-native';
-import { Section } from '../../components/Section';
-import { Screen } from '../../components/Screen';
-import { VStack } from 'native-base';
-import { InputField } from '../../components/InputField';
-import { CustomButton } from '../../components/CustomButton';
-import BackgroundTimer from 'react-native-background-timer';
-
-export const ExecutionTraceScreen: React.FC = () => {
-  const [traceName, setTraceName] = useState('');
-  const [traceAttributeKey, setTraceAttributeKey] = useState('');
-  const [traceAttributeValue, setTraceAttributeValue] = useState('');
-  let executionTrace: Trace;
-
-  async function startTrace() {
-    executionTrace = await APM.startExecutionTrace(traceName ?? '');
-  }
-
-  async function startDelayedTrace() {
-    return BackgroundTimer.setTimeout(async () => {
-      executionTrace = await APM.startExecutionTrace(traceName ?? '');
-    }, 5000);
-  }
-
-  function setTraceAttribute() {
-    if (!executionTrace) {
-      console.log('Please, start a trace before setting attributes.');
-    }
-    return executionTrace.setAttribute(traceAttributeKey ?? '', traceAttributeValue ?? '');
-  }
-
-  function endExecutionTrace() {
-    if (!executionTrace) {
-      console.log('Please, start a trace before ending it.');
-    }
-    return executionTrace.end();
-  }
-
-  return (
-    
-      
-        
- - setTraceName(text)} - value={traceName} - /> - - - setTraceAttributeKey(text)} - value={traceAttributeKey} - /> - setTraceAttributeValue(text)} - value={traceAttributeValue} - /> - - - -
-
-
- ); -}; diff --git a/examples/default/src/screens/apm/ScreenRender.tsx b/examples/default/src/screens/apm/ScreenRender.tsx index f9113a2c8..d42aea04a 100644 --- a/examples/default/src/screens/apm/ScreenRender.tsx +++ b/examples/default/src/screens/apm/ScreenRender.tsx @@ -24,7 +24,7 @@ const ScreenRenderSwitch: React.FC = () => { style={[styles.switch, isEnabled && styles.switchEnabled]} onPress={() => { setIsEnabled(!isEnabled); - APM.setScreenRenderEnabled(isEnabled); + APM.setScreenRenderingEnabled(isEnabled); }}> diff --git a/ios/RNInstabug/InstabugAPMBridge.h b/ios/RNInstabug/InstabugAPMBridge.h index 509e7fae3..849451991 100644 --- a/ios/RNInstabug/InstabugAPMBridge.h +++ b/ios/RNInstabug/InstabugAPMBridge.h @@ -15,19 +15,13 @@ - (void)setAppLaunchEnabled:(BOOL)isEnabled; - (void)endAppLaunch; - (void)setAutoUITraceEnabled:(BOOL)isEnabled; -- (void)startExecutionTrace:(NSString *)name :(NSString *)id - :(RCTPromiseResolveBlock)resolve - :(RCTPromiseRejectBlock)reject DEPRECATED_MSG_ATTRIBUTE("Please use APM.startFlow instead."); -- (void)setExecutionTraceAttribute:(NSString *)id:(NSString *)key - :(NSString *)value DEPRECATED_MSG_ATTRIBUTE("Please use APM.setTraceAttribute instead."); -- (void)endExecutionTrace:(NSString *)id DEPRECATED_MSG_ATTRIBUTE("Please use APM.endFlow instead."); - (void)startFlow:(NSString *)name; - (void)endFlow:(NSString *)name; - (void)setFlowAttribute:(NSString *)name :(NSString *)key :(NSString *_Nullable)value; - (void)startUITrace:(NSString *)name; - (void)endUITrace; -- (void)setScreenRenderEnabled:(BOOL)isEnabled; +- (void)setScreenRenderingEnabled:(BOOL)isEnabled; extern NSMutableDictionary *traces; diff --git a/ios/RNInstabug/InstabugAPMBridge.m b/ios/RNInstabug/InstabugAPMBridge.m index 3fe3effe4..a363b80fd 100644 --- a/ios/RNInstabug/InstabugAPMBridge.m +++ b/ios/RNInstabug/InstabugAPMBridge.m @@ -61,41 +61,6 @@ - (id) init IBGAPM.autoUITraceEnabled = isEnabled; } -// Starts new execution trace with the specified `name`. -// -// Deprecated see [startFlow: (NSString *)name] -RCT_EXPORT_METHOD(startExecutionTrace:(NSString *)name :(NSString *)id - :(RCTPromiseResolveBlock)resolve - :(RCTPromiseRejectBlock)reject) { - IBGExecutionTrace *trace = [IBGAPM startExecutionTraceWithName:name]; - if (trace != nil) { - [traces setObject: trace forKey: id]; - resolve(id); - } else { - resolve([NSNull null]); - } -} - -// Sets a user defined attribute for the execution trace. -// -// Deprecated see [setFlowAttribute:(NSString *)name :(NSString *)key :(NSString *_Nullable)value] -RCT_EXPORT_METHOD(setExecutionTraceAttribute:(NSString *)id :(NSString *)key :(NSString *)value) { - IBGExecutionTrace *trace = [traces objectForKey:id]; - if (trace != nil) { - [trace setAttributeWithKey:key value:value]; - } -} - -// Ends execution trace with the specified `name`. -// -// Deprecated see [endFlow: (NSString *)name] -RCT_EXPORT_METHOD(endExecutionTrace:(NSString *)id) { - IBGExecutionTrace *trace = [traces objectForKey:id]; - if (trace != nil) { - [trace end]; - } -} - // Starts a flow trace with the specified `name`, // allowing the SDK to capture and analyze the flow of execution within the application. RCT_EXPORT_METHOD(startFlow: (NSString *)name) { @@ -125,7 +90,7 @@ - (id) init } // Enables or disables screen render. -RCT_EXPORT_METHOD(setScreenRenderEnabled:(BOOL)isEnabled) { +RCT_EXPORT_METHOD(setScreenRenderingEnabled:(BOOL)isEnabled) { IBGAPM.screenRenderingEnabled = isEnabled; } diff --git a/ios/RNInstabug/InstabugBugReportingBridge.m b/ios/RNInstabug/InstabugBugReportingBridge.m index 75e058eb7..70efaa129 100644 --- a/ios/RNInstabug/InstabugBugReportingBridge.m +++ b/ios/RNInstabug/InstabugBugReportingBridge.m @@ -205,18 +205,16 @@ - (void) showBugReportingWithReportTypeAndOptionsHelper:(NSArray*)args { } RCT_EXPORT_METHOD(setCommentMinimumCharacterCount:(nonnull NSNumber *)limit reportTypes:(NSArray *)reportTypes) { - IBGBugReportingReportType parsedReportTypes = 0; - + IBGBugReportingType parsedReportTypes = 0; if (![reportTypes count]) { - parsedReportTypes = @(IBGBugReportingReportTypeBug).integerValue | @(IBGBugReportingReportTypeFeedback).integerValue | @(IBGBugReportingReportTypeQuestion).integerValue; + parsedReportTypes = @(IBGBugReportingTypeBug).integerValue | @(IBGBugReportingTypeFeedback).integerValue | @(IBGBugReportingTypeQuestion).integerValue; } else { for (NSNumber *reportType in reportTypes) { parsedReportTypes |= [reportType intValue]; } } - - [IBGBugReporting setCommentMinimumCharacterCountForReportTypes:parsedReportTypes withLimit:limit.intValue]; + [IBGBugReporting setCommentMinimumCharacterCount:[limit integerValue] forBugReportType:parsedReportTypes]; } RCT_EXPORT_METHOD(addUserConsent:(NSString *)key diff --git a/ios/RNInstabug/InstabugNetworkLoggerBridge.h b/ios/RNInstabug/InstabugNetworkLoggerBridge.h index 9673f8524..532f21d23 100644 --- a/ios/RNInstabug/InstabugNetworkLoggerBridge.h +++ b/ios/RNInstabug/InstabugNetworkLoggerBridge.h @@ -24,7 +24,7 @@ typedef NS_ENUM(NSInteger, NetworkListenerType) { +------------------------------------------------------------------------+ */ -- (void)isNativeInterceptionEnabled:(RCTPromiseResolveBlock _Nullable )resolve :(RCTPromiseRejectBlock _Nullable )reject; +- (BOOL)isNativeInterceptionEnabled; - (void) registerNetworkLogsListener:(NetworkListenerType)listenerType; diff --git a/ios/RNInstabug/InstabugNetworkLoggerBridge.m b/ios/RNInstabug/InstabugNetworkLoggerBridge.m index 16d71c814..2a2ddeb97 100644 --- a/ios/RNInstabug/InstabugNetworkLoggerBridge.m +++ b/ios/RNInstabug/InstabugNetworkLoggerBridge.m @@ -69,9 +69,11 @@ -(void)stopObserving { // Remove upstream listeners, stop unnecessary background tasks } -RCT_EXPORT_METHOD(isNativeInterceptionEnabled:(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject) { - resolve(@(IBGNetworkLogger.isNativeNetworkInterceptionFeatureEnabled)); -} +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isNativeInterceptionEnabled) { + return @(IBGNetworkLogger.isNativeNetworkInterceptionFeatureEnabled); +} + + RCT_EXPORT_METHOD(registerNetworkLogsListener: (NetworkListenerType) listenerType) { switch (listenerType) { diff --git a/ios/RNInstabug/InstabugReactBridge.h b/ios/RNInstabug/InstabugReactBridge.h index 1fe5505d3..3ff809f19 100644 --- a/ios/RNInstabug/InstabugReactBridge.h +++ b/ios/RNInstabug/InstabugReactBridge.h @@ -26,7 +26,8 @@ - (void)setEnabled:(BOOL)isEnabled; -- (void)init:(NSString *)token invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception codePushVersion:(NSString *)codePushVersion; +- (void)init:(NSString *)token invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception codePushVersion:(NSString *)codePushVersion +options:(nullable NSDictionary *)options; - (void)setCodePushVersion:(NSString *)version; @@ -42,6 +43,8 @@ - (void)setPrimaryColor:(UIColor *)color; +- (void)setTheme:(NSDictionary *)themeConfig; + - (void)appendTags:(NSArray *)tags; - (void)resetTags; diff --git a/ios/RNInstabug/InstabugReactBridge.m b/ios/RNInstabug/InstabugReactBridge.m index a48851ba8..52d5917fc 100644 --- a/ios/RNInstabug/InstabugReactBridge.m +++ b/ios/RNInstabug/InstabugReactBridge.m @@ -41,7 +41,9 @@ - (dispatch_queue_t)methodQueue { invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception - codePushVersion:(NSString *)codePushVersion) { + codePushVersion:(NSString *)codePushVersion + options:(nullable NSDictionary *)options + ) { IBGInvocationEvent invocationEvents = 0; for (NSNumber *boxedValue in invocationEventsArray) { @@ -62,8 +64,8 @@ - (dispatch_queue_t)methodQueue { RCT_EXPORT_METHOD(setReproStepsConfig:(IBGUserStepsMode)bugMode :(IBGUserStepsMode)crashMode:(IBGUserStepsMode)sessionReplayMode) { [Instabug setReproStepsFor:IBGIssueTypeBug withMode:bugMode]; - [Instabug setReproStepsFor:IBGIssueTypeCrash withMode:crashMode]; - [Instabug setReproStepsFor:IBGIssueTypeSessionReplay withMode:sessionReplayMode]; + [Instabug setReproStepsFor:IBGIssueTypeAllCrashes withMode:crashMode]; + [Instabug setReproStepsFor:IBGIssueTypeSessionReplay withMode:sessionReplayMode]; } RCT_EXPORT_METHOD(setFileAttachment:(NSString *)fileLocation) { @@ -173,6 +175,87 @@ - (dispatch_queue_t)methodQueue { Instabug.tintColor = color; } +RCT_EXPORT_METHOD(setTheme:(NSDictionary *)themeConfig) { + IBGTheme *theme = [[IBGTheme alloc] init]; + + NSDictionary *colorMapping = @{ + @"primaryColor": ^(UIColor *color) { theme.primaryColor = color; }, + @"backgroundColor": ^(UIColor *color) { theme.backgroundColor = color; }, + @"titleTextColor": ^(UIColor *color) { theme.titleTextColor = color; }, + @"subtitleTextColor": ^(UIColor *color) { theme.subtitleTextColor = color; }, + @"primaryTextColor": ^(UIColor *color) { theme.primaryTextColor = color; }, + @"secondaryTextColor": ^(UIColor *color) { theme.secondaryTextColor = color; }, + @"callToActionTextColor": ^(UIColor *color) { theme.callToActionTextColor = color; }, + @"headerBackgroundColor": ^(UIColor *color) { theme.headerBackgroundColor = color; }, + @"footerBackgroundColor": ^(UIColor *color) { theme.footerBackgroundColor = color; }, + @"rowBackgroundColor": ^(UIColor *color) { theme.rowBackgroundColor = color; }, + @"selectedRowBackgroundColor": ^(UIColor *color) { theme.selectedRowBackgroundColor = color; }, + @"rowSeparatorColor": ^(UIColor *color) { theme.rowSeparatorColor = color; } + }; + + for (NSString *key in colorMapping) { + if (themeConfig[key]) { + NSString *colorString = themeConfig[key]; + UIColor *color = [self colorFromHexString:colorString]; + if (color) { + void (^setter)(UIColor *) = colorMapping[key]; + setter(color); + } + } + } + + [self setFontIfPresent:themeConfig[@"primaryFontPath"] forTheme:theme type:@"primary"]; + [self setFontIfPresent:themeConfig[@"secondaryFontPath"] forTheme:theme type:@"secondary"]; + [self setFontIfPresent:themeConfig[@"ctaFontPath"] forTheme:theme type:@"cta"]; + + Instabug.theme = theme; +} + +- (void)setFontIfPresent:(NSString *)fontPath forTheme:(IBGTheme *)theme type:(NSString *)type { + if (fontPath) { + NSString *fileName = [fontPath lastPathComponent]; + NSString *nameWithoutExtension = [fileName stringByDeletingPathExtension]; + UIFont *font = [UIFont fontWithName:nameWithoutExtension size:17.0]; + if (font) { + if ([type isEqualToString:@"primary"]) { + theme.primaryTextFont = font; + } else if ([type isEqualToString:@"secondary"]) { + theme.secondaryTextFont = font; + } else if ([type isEqualToString:@"cta"]) { + theme.callToActionTextFont = font; + } + } + } +} + +- (UIColor *)colorFromHexString:(NSString *)hexString { + NSString *cleanString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""]; + + if (cleanString.length == 6) { + unsigned int rgbValue = 0; + NSScanner *scanner = [NSScanner scannerWithString:cleanString]; + [scanner scanHexInt:&rgbValue]; + + return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0 + green:((rgbValue & 0xFF00) >> 8) / 255.0 + blue:(rgbValue & 0xFF) / 255.0 + alpha:1.0]; + } else if (cleanString.length == 8) { + unsigned int rgbaValue = 0; + NSScanner *scanner = [NSScanner scannerWithString:cleanString]; + [scanner scanHexInt:&rgbaValue]; + + return [UIColor colorWithRed:((rgbaValue & 0xFF000000) >> 24) / 255.0 + green:((rgbaValue & 0xFF0000) >> 16) / 255.0 + blue:((rgbaValue & 0xFF00) >> 8) / 255.0 + alpha:(rgbaValue & 0xFF) / 255.0]; + } + + return [UIColor blackColor]; +} + + + RCT_EXPORT_METHOD(appendTags:(NSArray *)tags) { [Instabug appendTags:tags]; } @@ -355,18 +438,6 @@ - (dispatch_queue_t)methodQueue { } } -RCT_EXPORT_METHOD(addExperiments:(NSArray *)experiments) { - [Instabug addExperiments:experiments]; -} - -RCT_EXPORT_METHOD(removeExperiments:(NSArray *)experiments) { - [Instabug removeExperiments:experiments]; -} - -RCT_EXPORT_METHOD(clearAllExperiments) { - [Instabug clearAllExperiments]; -} - RCT_EXPORT_METHOD(addFeatureFlags:(NSDictionary *)featureFlagsMap) { NSMutableArray *featureFlags = [NSMutableArray array]; for(id key in featureFlagsMap){ diff --git a/ios/native.rb b/ios/native.rb index 8296dbcdb..fc994abba 100644 --- a/ios/native.rb +++ b/ios/native.rb @@ -1,4 +1,4 @@ -$instabug = { :version => '15.1.26' } +$instabug = { :version => '15.1.31' } def use_instabug! (spec = nil) version = $instabug[:version] diff --git a/package.json b/package.json index d39012128..61af51056 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "instabug-reactnative", "description": "React Native plugin for integrating the Instabug SDK", - "version": "15.0.1", + "version": "15.0.2", "author": "Instabug (https://instabug.com)", "repository": "github:Instabug/Instabug-React-Native", "homepage": "https://www.instabug.com/platforms/react-native", diff --git a/src/index.ts b/src/index.ts index 6e7de0284..0dcb8cafa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ // Models import type { InstabugConfig } from './models/InstabugConfig'; import Report from './models/Report'; -import Trace from './models/Trace'; +import type { ThemeConfig } from './models/ThemeConfig'; // Modules import * as APM from './modules/APM'; import * as BugReporting from './modules/BugReporting'; @@ -19,7 +19,6 @@ import type { SessionMetadata } from './models/SessionMetadata'; export * from './utils/Enums'; export { Report, - Trace, APM, BugReporting, CrashReporting, @@ -29,6 +28,13 @@ export { Replies, Surveys, }; -export type { InstabugConfig, Survey, NetworkData, NetworkDataObfuscationHandler, SessionMetadata }; +export type { + InstabugConfig, + Survey, + NetworkData, + NetworkDataObfuscationHandler, + SessionMetadata, + ThemeConfig, +}; export default Instabug; diff --git a/src/models/InstabugConfig.ts b/src/models/InstabugConfig.ts index 614ade892..af1d6e841 100644 --- a/src/models/InstabugConfig.ts +++ b/src/models/InstabugConfig.ts @@ -19,6 +19,11 @@ export interface InstabugConfig { */ codePushVersion?: string; + /** + * An optional flag to override SDK screenshot security behavior. + */ + ignoreAndroidSecureFlag?: boolean; + /** * An optional network interception mode, this determines whether network interception * is done in the JavaScript side or in the native Android and iOS SDK side. diff --git a/src/models/ThemeConfig.ts b/src/models/ThemeConfig.ts new file mode 100644 index 000000000..fb90347c9 --- /dev/null +++ b/src/models/ThemeConfig.ts @@ -0,0 +1,34 @@ +export type ThemeConfig = { + // Colors + primaryColor?: string; + backgroundColor?: string; + titleTextColor?: string; + subtitleTextColor?: string; + primaryTextColor?: string; + secondaryTextColor?: string; + callToActionTextColor?: string; + headerBackgroundColor?: string; + footerBackgroundColor?: string; + rowBackgroundColor?: string; + selectedRowBackgroundColor?: string; + rowSeparatorColor?: string; + + // Text Styles (Android only) + primaryTextStyle?: 'bold' | 'italic' | 'normal'; + secondaryTextStyle?: 'bold' | 'italic' | 'normal'; + titleTextStyle?: 'bold' | 'italic' | 'normal'; + ctaTextStyle?: 'bold' | 'italic' | 'normal'; + + // Fonts + primaryFontPath?: string; + primaryFontAsset?: string; + secondaryFontPath?: string; + secondaryFontAsset?: string; + ctaFontPath?: string; + ctaFontAsset?: string; + + // Legacy properties (deprecated) + primaryTextType?: string; + secondaryTextType?: string; + ctaTextType?: string; +}; diff --git a/src/models/Trace.ts b/src/models/Trace.ts deleted file mode 100644 index 19cd26d58..000000000 --- a/src/models/Trace.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { NativeAPM } from '../native/NativeAPM'; -import type * as APM from '../modules/APM'; - -export default class Trace { - constructor( - public readonly id: string, - public readonly name: string = '', - public readonly attributes: Record = {}, - ) {} - - /** - * Adds an attribute with a specified key and value to the Trace to be sent. - * - * @param key - The key of the attribute. - * @param value - The value of the attribute. - * - * @deprecated Please migrate to the App Flows APIs: {@link APM.startFlow}, {@link APM.endFlow}, and {@link APM.setFlowAttribute}. - */ - setAttribute(key: string, value: string) { - NativeAPM.setExecutionTraceAttribute(this.id, key, value); - this.attributes[key] = value; - } - - /** - * Ends the execution trace. - * - * @deprecated Please migrate to the App Flows APIs: {@link APM.startFlow}, {@link APM.endFlow}, and {@link APM.setFlowAttribute}. - */ - - end() { - NativeAPM.endExecutionTrace(this.id); - } -} diff --git a/src/modules/APM.ts b/src/modules/APM.ts index d81d3cbb5..bbb0b1b83 100644 --- a/src/modules/APM.ts +++ b/src/modules/APM.ts @@ -1,6 +1,5 @@ import { Platform } from 'react-native'; -import Trace from '../models/Trace'; import { NativeAPM } from '../native/NativeAPM'; import { NativeInstabug } from '../native/NativeInstabug'; @@ -48,29 +47,6 @@ export const setAutoUITraceEnabled = (isEnabled: boolean) => { NativeAPM.setAutoUITraceEnabled(isEnabled); }; -/** - * Starts a custom execution trace. - * - * Returns a promise which resolves with the trace reference if APM is enabled; otherwise, the promise is rejected. - * - * @param name - The name of the trace to start. - * @returns A promise that resolves with a Trace object. - * - * @deprecated Please migrate to the App Flows APIs: {@link startFlow}, {@link endFlow}, and {@link setFlowAttribute}. - */ -export const startExecutionTrace = async (name: string): Promise => { - const TRACE_NOT_STARTED_APM_NOT_ENABLED = `Execution trace "${name}" wasn't created. Please make sure to enable APM first by following the instructions at this link: https://docs.instabug.com/reference#enable-or-disable-apm`; - const timestamp = Date.now() + ''; - - const id = await NativeAPM.startExecutionTrace(name, timestamp); - - if (!id) { - throw new Error(TRACE_NOT_STARTED_APM_NOT_ENABLED); - } - - return new Trace(id, name); -}; - /** * Starts an AppFlow with the specified name. * @@ -144,6 +120,6 @@ export const _ibgSleep = () => { * Enables or disables Screen Render feature * @param isEnabled */ -export const setScreenRenderEnabled = (isEnabled: boolean) => { - NativeAPM.setScreenRenderEnabled(isEnabled); +export const setScreenRenderingEnabled = (isEnabled: boolean) => { + NativeAPM.setScreenRenderingEnabled(isEnabled); }; diff --git a/src/modules/BugReporting.ts b/src/modules/BugReporting.ts index 486169ecc..c514e1ba9 100644 --- a/src/modules/BugReporting.ts +++ b/src/modules/BugReporting.ts @@ -245,7 +245,10 @@ export const setDisclaimerText = (text: string) => { * Sets a minimum number of characters as a requirement for the comments field in the different report types. * @param limit int number of characters. * @param reportTypes (Optional) Array of reportType. If it's not passed, the limit will apply to all report types. + * @platform iOS */ export const setCommentMinimumCharacterCount = (limit: number, reportTypes?: ReportType[]) => { - NativeBugReporting.setCommentMinimumCharacterCount(limit, reportTypes ?? []); + if (Platform.OS === 'ios') { + NativeBugReporting.setCommentMinimumCharacterCount(limit, reportTypes ?? []); + } }; diff --git a/src/modules/Instabug.ts b/src/modules/Instabug.ts index f7d582e70..72553b188 100644 --- a/src/modules/Instabug.ts +++ b/src/modules/Instabug.ts @@ -1,10 +1,4 @@ -import { - AppState, - type AppStateStatus, - findNodeHandle, - Platform, - processColor, -} from 'react-native'; +import { AppState, type AppStateStatus, findNodeHandle, Platform } from 'react-native'; import type { NavigationContainerRefWithCurrent, @@ -42,6 +36,7 @@ import { NativeNetworkLogger } from '../native/NativeNetworkLogger'; import InstabugConstants from '../utils/InstabugConstants'; import { InstabugRNConfig } from '../utils/config'; import { Logger } from '../utils/logger'; +import type { ThemeConfig } from '../models/ThemeConfig'; let _currentScreen: string | null = null; let _lastScreen: string | null = null; @@ -84,13 +79,13 @@ function reportCurrentViewForAndroid(screenName: string | null) { * Should be called in constructor of the AppRegistry component * @param config SDK configurations. See {@link InstabugConfig} for more info. */ -export const init = async (config: InstabugConfig) => { +export const init = (config: InstabugConfig) => { if (Platform.OS === 'android') { // Add android feature flags listener for android registerFeatureFlagsListener(); addOnFeatureUpdatedListener(config); } else { - isNativeInterceptionFeatureEnabled = await NativeNetworkLogger.isNativeInterceptionEnabled(); + isNativeInterceptionFeatureEnabled = NativeNetworkLogger.isNativeInterceptionEnabled(); // Add app state listener to handle background/foreground transitions addAppStateListener(async (nextAppState) => handleAppStateChange(nextAppState, config)); @@ -133,7 +128,6 @@ const handleAppStateChange = async (nextAppState: AppStateStatus, config: Instab // Checks if the app has come to the foreground if (['inactive', 'background'].includes(_currentAppState) && nextAppState === 'active') { const isUpdated = await fetchApmNetworkFlags(); - if (isUpdated) { refreshAPMNetworkConfigs(config); } @@ -147,8 +141,7 @@ const handleAppStateChange = async (nextAppState: AppStateStatus, config: Instab */ const fetchApmNetworkFlags = async () => { let isUpdated = false; - const newNativeInterceptionFeatureEnabled = - await NativeNetworkLogger.isNativeInterceptionEnabled(); + const newNativeInterceptionFeatureEnabled = NativeNetworkLogger.isNativeInterceptionEnabled(); if (isNativeInterceptionFeatureEnabled !== newNativeInterceptionFeatureEnabled) { isNativeInterceptionFeatureEnabled = newNativeInterceptionFeatureEnabled; isUpdated = true; @@ -275,6 +268,11 @@ const initializeNativeInstabug = (config: InstabugConfig) => { shouldEnableNativeInterception && config.networkInterceptionMode === NetworkInterceptionMode.native, config.codePushVersion, + config.ignoreAndroidSecureFlag != null + ? { + ignoreAndroidSecureFlag: config.ignoreAndroidSecureFlag, + } + : undefined, ); }; @@ -389,9 +387,10 @@ export const setColorTheme = (sdkTheme: ColorTheme) => { * To use, import processColor and pass to it with argument the color hex * as argument. * @param color A color to set the UI elements of the SDK to. + * @deprecated Please migrate to the new UI customization API: {@link setTheme} */ export const setPrimaryColor = (color: string) => { - NativeInstabug.setPrimaryColor(processColor(color)); + NativeInstabug.setTheme({ primaryColor: color }); }; /** @@ -775,35 +774,6 @@ export const reportScreenChange = (screenName: string) => { NativeInstabug.reportScreenChange(screenName); }; -/** - * Add experiments to next report. - * @param experiments An array of experiments to add to the next report. - * - * @deprecated Please migrate to the new Feature Flags APIs: {@link addFeatureFlags}. - */ -export const addExperiments = (experiments: string[]) => { - NativeInstabug.addExperiments(experiments); -}; - -/** - * Remove experiments from next report. - * @param experiments An array of experiments to remove from the next report. - * - * @deprecated Please migrate to the new Feature Flags APIs: {@link removeFeatureFlags}. - */ -export const removeExperiments = (experiments: string[]) => { - NativeInstabug.removeExperiments(experiments); -}; - -/** - * Clear all experiments - * - * @deprecated Please migrate to the new Feature Flags APIs: {@link removeAllFeatureFlags}. - */ -export const clearAllExperiments = () => { - NativeInstabug.clearAllExperiments(); -}; - /** * Add feature flags to the next report. * @param featureFlags An array of feature flags to add to the next report. @@ -895,3 +865,50 @@ export const _registerFeatureFlagsChangeListener = ( export const enableAutoMasking = (autoMaskingTypes: AutoMaskingType[]) => { NativeInstabug.enableAutoMasking(autoMaskingTypes); }; + +/** + * Sets a custom theme for Instabug UI elements. + * + * This method provides comprehensive theming support. It will automatically use IBGTheme + * if available in the SDK version, otherwise falls back to individual theming methods. + * + * @param theme - Configuration object containing theme properties + * + * @example + * ```typescript + * // Basic usage with primary color (always supported) + * Instabug.setTheme({ + * primaryColor: '#FF6B6B' + * }); + * + * // Comprehensive theming (uses IBGTheme when available) + * Instabug.setTheme({ + * primaryColor: '#FF6B6B', + * secondaryTextColor: '#666666', + * primaryTextColor: '#333333', + * titleTextColor: '#000000', + * backgroundColor: '#FFFFFF', + * primaryTextStyle: 'bold', + * secondaryTextStyle: 'normal', + * titleTextStyle: 'bold', + * ctaTextStyle: 'bold', + * primaryFontPath: '/data/user/0/com.yourapp/files/fonts/YourFont.ttf', + * secondaryFontPath: '/data/user/0/com.yourapp/files/fonts/YourFont.ttf', + * ctaTextType: '/data/user/0/com.yourapp/files/fonts/YourFont.ttf', + * primaryFontAsset: 'fonts/YourFont.ttf', + * secondaryFontAsset: 'fonts/YourFont.ttf' + * }); + * ``` + */ +export const setTheme = (theme: ThemeConfig) => { + NativeInstabug.setTheme(theme); +}; +/** + * Enables or disables displaying in full-screen mode, hiding the status and navigation bars. + * @param isEnabled A boolean to enable/disable setFullscreen. + */ +export const setFullscreen = (isEnabled: boolean) => { + if (Platform.OS === 'android') { + NativeInstabug.setFullscreen(isEnabled); + } +}; diff --git a/src/native/NativeAPM.ts b/src/native/NativeAPM.ts index 67c7d8cd1..33c986ea8 100644 --- a/src/native/NativeAPM.ts +++ b/src/native/NativeAPM.ts @@ -34,10 +34,6 @@ export interface ApmNativeModule extends NativeModule { endAppLaunch(): void; // Execution Traces APIs // - startExecutionTrace(name: string, timestamp: string): Promise; - setExecutionTraceAttribute(id: string, key: string, value: string): void; - endExecutionTrace(id: string): void; - // App Flows APIs // startFlow(name: string): void; endFlow(name: string): void; @@ -50,7 +46,7 @@ export interface ApmNativeModule extends NativeModule { ibgSleep(): void; // Screen Rendering // - setScreenRenderEnabled(isEnabled: boolean): void; + setScreenRenderingEnabled(isEnabled: boolean): void; } export const NativeAPM = NativeModules.IBGAPM; diff --git a/src/native/NativeInstabug.ts b/src/native/NativeInstabug.ts index 7032bbc07..51cd08c08 100644 --- a/src/native/NativeInstabug.ts +++ b/src/native/NativeInstabug.ts @@ -14,6 +14,7 @@ import type { import type { NativeConstants } from './NativeConstants'; import type { W3cExternalTraceAttributes } from '../models/W3cExternalTraceAttributes'; import { NativeModules } from './NativePackage'; +import type { ThemeConfig } from '../models/ThemeConfig'; export interface InstabugNativeModule extends NativeModule { getConstants(): NativeConstants; @@ -26,6 +27,9 @@ export interface InstabugNativeModule extends NativeModule { debugLogsLevel: LogLevel, useNativeNetworkInterception: boolean, codePushVersion?: string, + options?: { + ignoreAndroidSecureFlag?: boolean; + }, ): void; show(): void; @@ -118,10 +122,6 @@ export interface InstabugNativeModule extends NativeModule { getTags(): Promise; // Experiments APIs // - addExperiments(experiments: string[]): void; - removeExperiments(experiments: string[]): void; - clearAllExperiments(): void; - addFeatureFlags(featureFlags: Record): void; removeFeatureFlags(featureFlags: string[]): void; @@ -158,9 +158,12 @@ export interface InstabugNativeModule extends NativeModule { setOnFeaturesUpdatedListener(handler?: (params: any) => void): void; // android only enableAutoMasking(autoMaskingTypes: AutoMaskingType[]): void; getNetworkBodyMaxSize(): Promise; + + setTheme(theme: ThemeConfig): void; + setFullscreen(isEnabled: boolean): void; } -export const NativeInstabug = NativeModules.Instabug; +export const NativeInstabug = NativeModules.Instabug as InstabugNativeModule; export enum NativeEvents { PRESENDING_HANDLER = 'IBGpreSendingHandler', diff --git a/src/native/NativeNetworkLogger.ts b/src/native/NativeNetworkLogger.ts index 4162a0fbf..c38f11873 100644 --- a/src/native/NativeNetworkLogger.ts +++ b/src/native/NativeNetworkLogger.ts @@ -8,7 +8,7 @@ export enum NetworkListenerType { } export interface NetworkLoggerNativeModule extends NativeModule { - isNativeInterceptionEnabled(): Promise; + isNativeInterceptionEnabled(): boolean; registerNetworkLogsListener(type?: NetworkListenerType): void; diff --git a/test/mocks/mockAPM.ts b/test/mocks/mockAPM.ts index beb0b068b..623e654fd 100644 --- a/test/mocks/mockAPM.ts +++ b/test/mocks/mockAPM.ts @@ -6,9 +6,6 @@ const mockAPM: ApmNativeModule = { setEnabled: jest.fn(), setAppLaunchEnabled: jest.fn(), setAutoUITraceEnabled: jest.fn(), - startExecutionTrace: jest.fn(), - setExecutionTraceAttribute: jest.fn(), - endExecutionTrace: jest.fn(), startFlow: jest.fn(), setFlowAttribute: jest.fn(), endFlow: jest.fn(), @@ -17,7 +14,7 @@ const mockAPM: ApmNativeModule = { endAppLaunch: jest.fn(), ibgSleep: jest.fn(), networkLogAndroid: jest.fn(), - setScreenRenderEnabled: jest.fn(), + setScreenRenderingEnabled: jest.fn(), }; export default mockAPM; diff --git a/test/mocks/mockInstabug.ts b/test/mocks/mockInstabug.ts index 391a00a38..96b052d20 100644 --- a/test/mocks/mockInstabug.ts +++ b/test/mocks/mockInstabug.ts @@ -49,9 +49,6 @@ const mockInstabug: InstabugNativeModule = { setPreSendingHandler: jest.fn(), reportScreenChange: jest.fn(), reportCurrentViewChange: jest.fn(), - addExperiments: jest.fn(), - removeExperiments: jest.fn(), - clearAllExperiments: jest.fn(), networkLogIOS: jest.fn(), networkLogAndroid: jest.fn(), addFeatureFlags: jest.fn(), @@ -77,6 +74,8 @@ const mockInstabug: InstabugNativeModule = { setOnFeaturesUpdatedListener: jest.fn(), enableAutoMasking: jest.fn(), getNetworkBodyMaxSize: jest.fn().mockResolvedValue(10240), // 10 KB + setTheme: jest.fn(), + setFullscreen: jest.fn(), }; export default mockInstabug; diff --git a/test/models/Trace.spec.ts b/test/models/Trace.spec.ts deleted file mode 100644 index 8421b419a..000000000 --- a/test/models/Trace.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import Trace from '../../src/models/Trace'; -import { NativeAPM } from '../../src/native/NativeAPM'; - -describe('Trace Model', () => { - it('should set the id, name and attributes if passed', () => { - const id = 'trace-id'; - const name = 'my-trace'; - const attributes = { screen: 'login' }; - const trace = new Trace(id, name, attributes); - - expect(trace.id).toBe(id); - expect(trace.name).toBe(name); - expect(trace.attributes).toBe(attributes); - }); - - it('should set execution trace attributes', () => { - const attribute = { key: 'isAuthenticated', value: 'yes' }; - - const trace = new Trace('trace-id'); - trace.setAttribute(attribute.key, attribute.value); - - expect(trace.attributes[attribute.key]).toBe(attribute.value); - expect(NativeAPM.setExecutionTraceAttribute).toBeCalledTimes(1); - expect(NativeAPM.setExecutionTraceAttribute).toBeCalledWith( - trace.id, - attribute.key, - attribute.value, - ); - }); - - it('should end execution trace', () => { - const trace = new Trace('trace-id'); - - trace.end(); - - expect(NativeAPM.endExecutionTrace).toBeCalledTimes(1); - expect(NativeAPM.endExecutionTrace).toBeCalledWith(trace.id); - }); -}); diff --git a/test/modules/APM.spec.ts b/test/modules/APM.spec.ts index 39d5df4be..fbdde4497 100644 --- a/test/modules/APM.spec.ts +++ b/test/modules/APM.spec.ts @@ -1,11 +1,8 @@ import { Platform } from 'react-native'; -import { mocked } from 'jest-mock'; - -import Trace from '../../src/models/Trace'; -import * as APM from '../../src/modules/APM'; import { NativeAPM } from '../../src/native/NativeAPM'; import { NativeInstabug } from '../../src/native/NativeInstabug'; +import * as APM from '../../src/modules/APM'; describe('APM Module', () => { it('should call the native method setEnabled', () => { @@ -51,57 +48,6 @@ describe('APM Module', () => { expect(NativeAPM.setAutoUITraceEnabled).toBeCalledWith(true); }); - it('should call the native method startExecutionTrace', () => { - mocked(NativeAPM).startExecutionTrace.mockResolvedValueOnce('trace-id'); - - APM.startExecutionTrace('trace'); - - expect(NativeAPM.startExecutionTrace).toBeCalledTimes(1); - expect(NativeAPM.startExecutionTrace).toBeCalledWith('trace', expect.any(String)); - }); - - it("should throw an error if native startExecutionTrace didn't return an ID", async () => { - mocked(NativeAPM).startExecutionTrace.mockResolvedValueOnce(null); - const promise = APM.startExecutionTrace('trace'); - - await expect(promise).rejects.toThrowError(/trace "trace" wasn't created/i); - }); - - it('should resolve with an Trace object if native startExecutionTrace returned an ID', async () => { - mocked(NativeAPM).startExecutionTrace.mockResolvedValueOnce('trace-id'); - - const promise = APM.startExecutionTrace('trace'); - - await expect(promise).resolves.toBeInstanceOf(Trace); - await expect(promise).resolves.toHaveProperty('name', 'trace'); - }); - - it('should call the native method setExecutionTraceAttribute', () => { - mocked(NativeAPM).startExecutionTrace.mockResolvedValueOnce('trace-id'); - - APM.startExecutionTrace('trace').then((trace) => { - trace.setAttribute('key', 'value'); - - expect(NativeAPM.setExecutionTraceAttribute).toBeCalledTimes(1); - expect(NativeAPM.setExecutionTraceAttribute).toBeCalledWith( - expect.any(String), - 'key', - 'value', - ); - }); - }); - - it('should call the native method endExecutionTrace', () => { - mocked(NativeAPM).startExecutionTrace.mockResolvedValueOnce('trace-id'); - - APM.startExecutionTrace('trace').then((trace) => { - trace.end(); - - expect(NativeAPM.endExecutionTrace).toBeCalledTimes(1); - expect(NativeAPM.endExecutionTrace).toBeCalledWith(expect.any(String)); - }); - }); - it('should call the native method startFlow', () => { const appFlowName = 'flowName'; @@ -157,9 +103,9 @@ describe('APM Module', () => { }); it('should call the native method setScreenRenderEnabled', () => { - APM.setScreenRenderEnabled(true); + APM.setScreenRenderingEnabled(true); - expect(NativeAPM.setScreenRenderEnabled).toBeCalledTimes(1); - expect(NativeAPM.setScreenRenderEnabled).toBeCalledWith(true); + expect(NativeAPM.setScreenRenderingEnabled).toBeCalledTimes(1); + expect(NativeAPM.setScreenRenderingEnabled).toBeCalledWith(true); }); }); diff --git a/test/modules/Instabug.spec.ts b/test/modules/Instabug.spec.ts index f6e36d8e4..ddfa254b1 100644 --- a/test/modules/Instabug.spec.ts +++ b/test/modules/Instabug.spec.ts @@ -1,7 +1,7 @@ import '../mocks/mockInstabugUtils'; import '../mocks/mockNetworkLogger'; -import { findNodeHandle, Platform, processColor } from 'react-native'; +import { findNodeHandle, Platform } from 'react-native'; import type { NavigationContainerRefWithCurrent } from '@react-navigation/native'; // Import the hook import { mocked } from 'jest-mock'; import waitForExpect from 'wait-for-expect'; @@ -69,8 +69,8 @@ describe('Instabug Module', () => { expect(NativeInstabug.reportScreenChange).toBeCalledWith(screenName); }); - it("componentDidAppearListener shouldn't call the native method reportScreenChange if first screen", async () => { - await Instabug.init({ + it("componentDidAppearListener shouldn't call the native method reportScreenChange if first screen", () => { + Instabug.init({ token: 'some-token', invocationEvents: [InvocationEvent.none], }); @@ -81,7 +81,7 @@ describe('Instabug Module', () => { componentType: 'Component', }); - await waitForExpect(() => { + waitForExpect(() => { // Only first screen should be reported expect(NativeInstabug.reportScreenChange).toBeCalledTimes(1); expect(NativeInstabug.reportScreenChange).toBeCalledWith('Initial Screen'); @@ -89,6 +89,11 @@ describe('Instabug Module', () => { }); it("componentDidAppearListener shouldn't call the native method reportScreenChange twice if same screen", (done) => { + Instabug.init({ + token: 'some-token', + invocationEvents: [InvocationEvent.none], + }); + Array(5).forEach(() => { Instabug.componentDidAppearListener({ componentId: '1', @@ -107,7 +112,7 @@ describe('Instabug Module', () => { // 2. Second+ calls: // The screen name is the same as _lastScreen (stored in 1st call) // so it doesn't report a screen change - expect(NativeInstabug.reportScreenChange).not.toBeCalled(); + expect(NativeInstabug.reportScreenChange).toBeCalledTimes(1); done(); }, 1500); }); @@ -283,16 +288,17 @@ describe('Instabug Module', () => { expect(onStateChangeMock).toHaveBeenCalledWith(mockNavigationContainerRef.getRootState()); }); - it('should call the native method init', async () => { + it('should call the native method init', () => { const instabugConfig = { token: 'some-token', invocationEvents: [InvocationEvent.floatingButton, InvocationEvent.shake], debugLogsLevel: LogLevel.debug, codePushVersion: '1.1.0', + ignoreAndroidSecureFlag: true, }; const usesNativeNetworkInterception = false; - await Instabug.init(instabugConfig); + Instabug.init(instabugConfig); expect(NetworkLogger.setEnabled).toBeCalledWith(true); expect(NativeInstabug.init).toBeCalledTimes(1); @@ -302,6 +308,7 @@ describe('Instabug Module', () => { instabugConfig.debugLogsLevel, usesNativeNetworkInterception, instabugConfig.codePushVersion, + { ignoreAndroidSecureFlag: instabugConfig.ignoreAndroidSecureFlag }, ); }); @@ -314,22 +321,21 @@ describe('Instabug Module', () => { expect(NativeInstabug.setCodePushVersion).toBeCalledWith(codePushVersion); }); - it('init should disable JavaScript interceptor when using native interception mode', async () => { + it('init should disable JavaScript interceptor when using native interception mode', () => { const instabugConfig = { token: 'some-token', invocationEvents: [InvocationEvent.floatingButton, InvocationEvent.shake], debugLogsLevel: LogLevel.debug, networkInterceptionMode: NetworkInterceptionMode.native, codePushVersion: '1.1.0', + ignoreAndroidSecureFlag: true, }; // Stubbing Network feature flags - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(true)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(true)); - await Instabug.init(instabugConfig); + Instabug.init(instabugConfig); if (Platform.OS === 'android') { expect(NetworkLogger.setEnabled).not.toBeCalled(); @@ -353,6 +359,7 @@ describe('Instabug Module', () => { // usesNativeNetworkInterception should be true when using native interception mode with iOS true, instabugConfig.codePushVersion, + { ignoreAndroidSecureFlag: instabugConfig.ignoreAndroidSecureFlag }, ); } }); @@ -455,12 +462,13 @@ describe('Instabug Module', () => { expect(NativeInstabug.setColorTheme).toBeCalledWith(theme); }); - it('should call the native method setPrimaryColor', () => { + it('should call the native method setPrimaryColor on iOS', () => { + Platform.OS = 'ios'; const color = '#fff'; - Instabug.setPrimaryColor(color); + Instabug.setTheme({ primaryColor: color }); - expect(NativeInstabug.setPrimaryColor).toBeCalledTimes(1); - expect(NativeInstabug.setPrimaryColor).toBeCalledWith(processColor(color)); + expect(NativeInstabug.setTheme).toBeCalledTimes(1); + expect(NativeInstabug.setTheme).toBeCalledWith({ primaryColor: color }); }); it('should call the native method appendTags', () => { @@ -825,25 +833,6 @@ describe('Instabug Module', () => { expect(emitter.listenerCount(NativeEvents.PRESENDING_HANDLER)).toBe(1); }); - it('should call native addExperiments method', () => { - const experiments = ['exp1', 'exp2']; - Instabug.addExperiments(experiments); - expect(NativeInstabug.addExperiments).toBeCalledTimes(1); - expect(NativeInstabug.addExperiments).toBeCalledWith(experiments); - }); - - it('should call native removeExperiments method', () => { - const experiments = ['exp1', 'exp2']; - Instabug.removeExperiments(experiments); - expect(NativeInstabug.removeExperiments).toBeCalledTimes(1); - expect(NativeInstabug.removeExperiments).toBeCalledWith(experiments); - }); - - it('should call native clearAllExperiments method', () => { - Instabug.clearAllExperiments(); - expect(NativeInstabug.clearAllExperiments).toBeCalledTimes(1); - }); - it('should call native addFeatureFlags method', () => { const featureFlags: Array = [ { @@ -900,7 +889,7 @@ describe('Instabug Module', () => { expect(NativeInstabug.willRedirectToStore).toBeCalledTimes(1); }); - it('should register feature flag listener', async () => { + it('should register feature flag listener', () => { const callback = jest.fn(); Instabug._registerFeatureFlagsChangeListener(callback); @@ -939,10 +928,10 @@ describe('Instabug iOS initialization tests', () => { jest.advanceTimersByTime(1000); }); - it('should initialize correctly with javascript interception mode', async () => { + it('should initialize correctly with javascript interception mode', () => { config.networkInterceptionMode = NetworkInterceptionMode.javascript; - await Instabug.init(config); + Instabug.init(config); expect(NativeNetworkLogger.isNativeInterceptionEnabled).toHaveBeenCalled(); expect(NetworkLogger.setEnabled).toHaveBeenCalledWith(true); @@ -952,15 +941,14 @@ describe('Instabug iOS initialization tests', () => { config.debugLogsLevel, false, // Disable native interception config.codePushVersion, + config.ignoreAndroidSecureFlag, ); }); - it('should initialize correctly with native interception mode when [isNativeInterceptionEnabled] == ture', async () => { - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(true)); + it('should initialize correctly with native interception mode when [isNativeInterceptionEnabled] == ture', () => { + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true); - await Instabug.init(config); + Instabug.init(config); expect(NativeNetworkLogger.isNativeInterceptionEnabled).toHaveBeenCalled(); expect(NetworkLogger.setEnabled).toHaveBeenCalledWith(false); @@ -970,15 +958,14 @@ describe('Instabug iOS initialization tests', () => { config.debugLogsLevel, true, // Enable native interception config.codePushVersion, + config.ignoreAndroidSecureFlag, ); }); - it('should disable native interception mode when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', async () => { - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + it('should disable native interception mode when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', () => { + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); - await Instabug.init(config); + Instabug.init(config); expect(NativeNetworkLogger.isNativeInterceptionEnabled).toHaveBeenCalled(); expect(NetworkLogger.setEnabled).toHaveBeenCalled(); @@ -988,16 +975,15 @@ describe('Instabug iOS initialization tests', () => { config.debugLogsLevel, false, // Disable native interception config.codePushVersion, + config.ignoreAndroidSecureFlag, ); }); - it('should display error message when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', async () => { - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + it('should display error message when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', () => { + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); const logSpy = jest.spyOn(global.console, 'error'); - await Instabug.init(config); + Instabug.init(config); expect(logSpy).toBeCalledTimes(1); expect(logSpy).toBeCalledWith( @@ -1020,9 +1006,9 @@ describe('Instabug Android initialization tests', () => { }; }); - it('should initialize correctly with native interception enabled', async () => { + it('should initialize correctly with native interception enabled', () => { config.networkInterceptionMode = NetworkInterceptionMode.native; - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(NativeInstabug.setOnFeaturesUpdatedListener).toHaveBeenCalled(); expect(NetworkLogger.setEnabled).toHaveBeenCalledWith(true); @@ -1032,18 +1018,17 @@ describe('Instabug Android initialization tests', () => { config.debugLogsLevel, false, // always disable native interception to insure sending network logs to core (Bugs & Crashes). config.codePushVersion, + { ignoreAndroidSecureFlag: config.ignoreAndroidSecureFlag }, ); }); }); - it('should show warning message when networkInterceptionMode == javascript and user added APM plugin', async () => { - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(true)); + it('should show warning message when networkInterceptionMode == javascript and user added APM plugin', () => { + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(true)); const logSpy = jest.spyOn(global.console, 'warn'); - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(logSpy).toBeCalledTimes(1); expect(logSpy).toBeCalledWith( @@ -1052,16 +1037,14 @@ describe('Instabug Android initialization tests', () => { }); }); - it('should show error message when networkInterceptionMode == native and user did not add APM plugin', async () => { + it('should show error message when networkInterceptionMode == native and user did not add APM plugin', () => { config.networkInterceptionMode = NetworkInterceptionMode.native; - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(true)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(false)); const logSpy = jest.spyOn(global.console, 'error'); - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(logSpy).toBeCalledTimes(1); @@ -1071,16 +1054,14 @@ describe('Instabug Android initialization tests', () => { }); }); - it('should show error message when networkInterceptionMode == native and user did not add APM plugin and the isNativeInterceptionEnabled is disabled', async () => { + it('should show error message when networkInterceptionMode == native and user did not add APM plugin and the isNativeInterceptionEnabled is disabled', () => { config.networkInterceptionMode = NetworkInterceptionMode.native; - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(false)); const logSpy = jest.spyOn(global.console, 'error'); - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(logSpy).toBeCalledTimes(1); @@ -1090,15 +1071,13 @@ describe('Instabug Android initialization tests', () => { }); }); - it('should show error message when networkInterceptionMode == native and the isNativeInterceptionEnabled is disabled', async () => { + it('should show error message when networkInterceptionMode == native and the isNativeInterceptionEnabled is disabled', () => { config.networkInterceptionMode = NetworkInterceptionMode.native; - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(true)); const logSpy = jest.spyOn(global.console, 'error'); - await Instabug.init(config); + Instabug.init(config); fakeTimer(() => { expect(logSpy).toBeCalledTimes(1); diff --git a/test/utils/InstabugUtils.spec.ts b/test/utils/InstabugUtils.spec.ts index 11a5c8d1a..49ce13c58 100644 --- a/test/utils/InstabugUtils.spec.ts +++ b/test/utils/InstabugUtils.spec.ts @@ -273,11 +273,9 @@ describe('reportNetworkLog', () => { it('reportNetworkLog should send network logs to native with the correct parameters on Android', async () => { Platform.OS = 'android'; - jest - .spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled') - .mockReturnValue(Promise.resolve(false)); + jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false); jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(false)); - await Instabug.init({ token: '', invocationEvents: [InvocationEvent.none] }); + Instabug.init({ token: '', invocationEvents: [InvocationEvent.none] }); const requestHeaders = JSON.stringify(network.requestHeaders); const responseHeaders = JSON.stringify(network.responseHeaders);