diff --git a/CHANGELOG.md b/CHANGELOG.md
index 55cd87389..5af4b937c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,25 @@
# Changelog
+## [Unreleased](https://github.com/Instabug/Instabug-React-Native/compare/v15.0.2...dev)
+
+### Added
+
+- Add support for App variant. ([#1409](https://github.com/Instabug/Instabug-React-Native/pull/1409))
+
+- Add Support Advanced UI customization. ([#1411](https://github.com/Instabug/Instabug-React-Native/pull/1411))
+
+### Changed
+
+- **BREAKING** Remove deprecated APIs ([#1424](https://github.com/Instabug/Instabug-React-Native/pull/1424)). See migration guide for more details.
+
+- Bump Instabug iOS SDK to v16.0.1 ([#1436](https://github.com/Instabug/Instabug-React-Native/pull/1436)). [See release notes](https://github.com/Instabug/Instabug-iOS/releases/tag/16.0.1).
+
+- Bump Instabug Android SDK to v16.0.0 ([#1436](https://github.com/Instabug/Instabug-React-Native/pull/1436)). [See release notes](https://github.com/Instabug/Instabug-Android/releases/tag/v16.0.1).
+
+### Fixed
+
+- Masking private views on newer React native Versions ([#1403](https://github.com/Instabug/Instabug-React-Native/pull/1403))
+
## [15.0.2](https://github.com/Instabug/Instabug-React-Native/compare/v15.2.0...dev)
### 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 faa3246cd..f4b2e9818 100644
--- a/android/native.gradle
+++ b/android/native.gradle
@@ -1,5 +1,5 @@
project.ext.instabug = [
- version: '15.0.1'
+ version: '16.0.0'
]
dependencies {
diff --git a/android/sourcemaps.gradle b/android/sourcemaps.gradle
index f544974d2..5558c01ba 100644
--- a/android/sourcemaps.gradle
+++ b/android/sourcemaps.gradle
@@ -1,6 +1,6 @@
import org.apache.tools.ant.taskdefs.condition.Os
-gradle.projectsEvaluated {
+project.afterEvaluate {
// Works for both `bundleReleaseJsAndAssets` and `createBundleReleaseJsAndAssets` and product flavors
def suffix = 'ReleaseJsAndAssets'
def bundleTasks = project(':app').tasks.findAll {
diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java
index 7c0901936..28de7d950 100644
--- a/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java
+++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java
@@ -59,18 +59,30 @@ public void init(
@NonNull Application application,
@NonNull String applicationToken,
int logLevel,
+ String codePushVersion,
+ String appVariant,
Boolean ignoreSecureFlag,
@NonNull InstabugInvocationEvent... InvocationEvent
+
+
) {
try {
setBaseUrlForDeprecationLogs();
setCurrentPlatform();
- Instabug.Builder builder = new Instabug.Builder(application, applicationToken)
+ Instabug.Builder builder= new Instabug.Builder(application, applicationToken)
.setInvocationEvents(InvocationEvent)
.setSdkDebugLogsLevel(logLevel);
+ if(codePushVersion!=null){
+ builder.setCodePushVersion(codePushVersion);
+ }
+ if(appVariant!=null)
+ builder.setAppVariant(appVariant);
+
+
+
if (ignoreSecureFlag != null) {
builder.ignoreFlagSecure(ignoreSecureFlag);
}
@@ -107,9 +119,11 @@ public void init(
public void init(
@NonNull Application application,
@NonNull String applicationToken,
+ String codePushVersion,
+ String appVariant,
@NonNull InstabugInvocationEvent... invocationEvent
) {
- init(application, applicationToken, LogLevel.ERROR,null, invocationEvent);
+ init(application, applicationToken, LogLevel.ERROR,codePushVersion,appVariant, null,invocationEvent);
}
@VisibleForTesting
@@ -165,6 +179,11 @@ public static class Builder {
* The events that trigger the SDK's user interface.
*/
private InstabugInvocationEvent[] invocationEvents;
+ /**
+ * The App variant name to be used for all reports.
+ */
+ private String appVariant;
+
private Boolean ignoreFlagSecure;
@@ -237,6 +256,16 @@ public Builder setInvocationEvents(InstabugInvocationEvent... invocationEvents)
return this;
}
+ /**
+ * Sets the the current App variant
+ *
+ * @param appVariant the current App variant to work with.
+ */
+ public Builder setAppVariant(String appVariant) {
+ this.appVariant = appVariant;
+ return this;
+ }
+
/**
* Builds the Instabug instance with the provided configurations.
*/
@@ -252,6 +281,9 @@ public void build() {
if (codePushVersion != null) {
instabugBuilder.setCodePushVersion(codePushVersion);
}
+ if(appVariant!=null){
+ instabugBuilder.setAppVariant(appVariant);
+ }
if (ignoreFlagSecure != null) {
instabugBuilder.ignoreFlagSecure(ignoreFlagSecure);
diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java
index d75b4f75b..6ed3541cb 100644
--- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java
+++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java
@@ -12,7 +12,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;
@@ -33,8 +32,6 @@ public RNInstabugAPMModule(ReactApplicationContext reactApplicationContext) {
super(reactApplicationContext);
}
- @Deprecated
- HashMap traces = new HashMap();
@Nonnull
@Override
@@ -207,81 +204,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
*
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 21bcf4f44..0dffd60c2 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;
@@ -20,10 +24,12 @@
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.UIManager;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.UIManagerModule;
import com.instabug.apm.InternalAPM;
import com.instabug.apm.configuration.cp.APMFeature;
@@ -45,6 +51,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;
@@ -149,6 +156,7 @@ public void init(
final String logLevel,
final boolean useNativeNetworkInterception,
@Nullable final String codePushVersion,
+ @Nullable final String appVariant,
final ReadableMap map
) {
MainThreadHandler.runOnMainThread(new Runnable() {
@@ -178,6 +186,9 @@ public void run() {
builder.setCodePushVersion(codePushVersion);
}
}
+ if (appVariant != null) {
+ builder.setAppVariant(appVariant);
+ }
builder.build();
}
});
@@ -286,26 +297,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.
@@ -505,6 +496,8 @@ public void run() {
});
}
+
+
/**
* Removes user attribute if exists.
*
@@ -954,14 +947,22 @@ public void networkLogAndroid(final String url,
@UiThread
@Nullable
private View resolveReactView(final int reactTag) {
+ try {
final ReactApplicationContext reactContext = getReactApplicationContext();
final UIManagerModule uiManagerModule = reactContext.getNativeModule(UIManagerModule.class);
if (uiManagerModule == null) {
+ UIManager uiNewManagerModule = UIManagerHelper.getUIManagerForReactTag(reactContext, reactTag);
+ if (uiNewManagerModule != null) {
+ return uiNewManagerModule.resolveView(reactTag);
+ }
return null;
}
return uiManagerModule.resolveView(reactTag);
+ } catch (Exception e) {
+ return null;
+ }
}
@@ -973,7 +974,9 @@ public void run() {
try {
final View view = resolveReactView(reactTag);
+ if(view !=null){
Instabug.addPrivateViews(view);
+ }
} catch (Exception e) {
e.printStackTrace();
}
@@ -988,8 +991,10 @@ public void removePrivateView(final int reactTag) {
public void run() {
try {
final View view = resolveReactView(reactTag);
+ if(view !=null){
Instabug.removePrivateViews(view);
+ }
} catch (Exception e) {
e.printStackTrace();
}
@@ -1041,60 +1046,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) {
@@ -1356,4 +1308,270 @@ public void run() {
}
});
}
+
+ /**
+ * Sets current App variant
+ *
+ * @param appVariant The app variant name .
+ */
+ @ReactMethod
+ public void setAppVariant(@NonNull String appVariant) {
+ try {
+ Instabug.setAppVariant(appVariant);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ * 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 85ca1384d..b10058f48 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() {
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..3a0edc5f0 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() {
@@ -631,6 +574,16 @@ public void testRemoveAllFeatureFlags() {
mockInstabug.verify(() -> Instabug.removeAllFeatureFlags());
}
+ @Test
+ public void testSetAppVariant() {
+ String appVariant="App-variant";
+ // when
+ rnModule.setAppVariant(appVariant);
+
+ // then
+ mockInstabug.verify(() -> Instabug.setAppVariant(appVariant));
+ }
+
@Test
public void testWillRedirectToStore() {
// when
@@ -678,7 +631,7 @@ public void testSetNetworkLogBodyDisabled() {
mockInstabug.verify(() -> Instabug.setNetworkLogBodyEnabled(false));
}
-
+
@Test
public void testEnableAutoMasking(){
@@ -704,4 +657,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 625eab1c9..643a1e136 100644
--- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java
+++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugTest.java
@@ -67,7 +67,7 @@ public void testInitWithLogLevel() {
when(mock.setInvocationEvents(any())).thenReturn(mock);
});
- sut.init(mContext, token, logLevel, true, invocationEvents);
+ sut.init(mContext, token, logLevel, null, null,true, invocationEvents);
Instabug.Builder builder = mInstabugBuilder.constructed().get(0);
@@ -89,16 +89,19 @@ public void testInitWithoutLogLevel() {
final InstabugInvocationEvent[] invocationEvents = new InstabugInvocationEvent[]{InstabugInvocationEvent.FLOATING_BUTTON};
final String token = "fde....";
final int defaultLogLevel = LogLevel.ERROR;
+ final String appVariant = "app-variant";
MockedConstruction mInstabugBuilder = mockConstruction(
Instabug.Builder.class, (mock, context) -> {
when(mock.setSdkDebugLogsLevel(anyInt())).thenReturn(mock);
when(mock.setInvocationEvents(any())).thenReturn(mock);
+ when(mock.setAppVariant(any())).thenReturn(mock);
+
});
- sut.init(mContext, token, invocationEvents);
+ sut.init(mContext, token, null, appVariant, invocationEvents);
- verify(sut).init(mContext, token, defaultLogLevel, null,invocationEvents);
+ verify(sut).init(mContext, token, defaultLogLevel, null, appVariant, null,invocationEvents);
mInstabugBuilder.close();
}
diff --git a/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj b/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj
index fb1253b31..0778e9a59 100644
--- a/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj
+++ b/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj
@@ -430,7 +430,7 @@
name = "[CP-User] [instabug-reactnative] Upload Sourcemap";
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "#!/bin/sh\n\nmain() {\n # Read environment variables from ios/.xcode.env if it exists\n env_path=\"$PODS_ROOT/../.xcode.env\"\n if [ -f \"$env_path\" ]; then\n source \"$env_path\"\n fi\n\n # Read environment variables from ios/.xcode.env.local if it exists\n local_env_path=\"${ENV_PATH}.local\"\n if [ -f \"$local_env_path\" ]; then\n source \"$local_env_path\"\n fi\n\n if [[ \"$INSTABUG_SOURCEMAPS_UPLOAD_DISABLE\" = true ]]; then\n echo \"[Info] \\`INSTABUG_SOURCEMAPS_UPLOAD_DISABLE\\` was set to true, skipping sourcemaps upload...\"\n exit 0\n fi\n\n if [[ \"$CONFIGURATION\" = \"Debug\" ]]; then\n echo \"[Info] Building in debug mode, skipping sourcemaps upload...\"\n exit 0\n fi\n\n if [[ -z \"$INFOPLIST_FILE\" ]] || [[ -z \"$PROJECT_DIR\" ]]; then\n echo \"[Error] Instabug sourcemaps script must be invoked by Xcode\"\n exit 0\n fi\n\n local source_map_file=$(generate_sourcemaps | tail -n 1)\n\n local js_project_dir=\"$PROJECT_DIR/..\"\n local instabug_dir=$(dirname $(node -p \"require.resolve('instabug-reactnative/package.json')\"))\n local inferred_token=$(cd $js_project_dir && source $instabug_dir/scripts/find-token.sh)\n local app_token=$(resolve_var \"App Token\" \"INSTABUG_APP_TOKEN\" \"$inferred_token\" | tail -n 1)\n\n local inferred_name=$(/usr/libexec/PlistBuddy -c 'print CFBundleShortVersionString' \"$PROJECT_DIR/$INFOPLIST_FILE\")\n local version_name=$(resolve_var \"Version Name\" \"INSTABUG_APP_VERSION_NAME\" \"$inferred_name\" | tail -n 1)\n\n local inferred_code=$(/usr/libexec/PlistBuddy -c 'print CFBundleVersion' \"$PROJECT_DIR/$INFOPLIST_FILE\")\n local version_code=$(resolve_var \"Version Code\" \"INSTABUG_APP_VERSION_CODE\" \"$inferred_code\" | tail -n 1)\n\n node $instabug_dir/bin/index.js upload-sourcemaps \\\n --platform ios \\\n --file $source_map_file \\\n --token $app_token \\\n --name $version_name \\\n --code $version_code\n}\n\ngenerate_sourcemaps() {\n local react_native_dir=$(dirname $(node -p \"require.resolve('react-native/package.json')\"))\n\n # Fixes an issue with react-native prior to v0.67.0\n # For more info: https://github.com/facebook/react-native/issues/32168\n export RN_DIR=$react_native_dir\n\n # Used withing `react-native-xcode.sh` to generate sourcemap file\n export SOURCEMAP_FILE=\"$(pwd)/main.jsbundle.map\";\n\n source \"$react_native_dir/scripts/react-native-xcode.sh\"\n\n if [[ ! -f \"$SOURCEMAP_FILE\" ]]; then\n echo \"[Error] Unable to find source map file at: $SOURCEMAP_FILE\"\n exit 0\n fi\n\n echo $SOURCEMAP_FILE\n}\n\nresolve_var() {\n local name=$1\n local env_key=$2\n local default_value=$3\n\n local env_value=\"${!env_key}\"\n\n if [[ -n \"$env_value\" ]] && [[ -n \"$default_value\" ]] && [[ \"$env_value\" != default_value ]]; then\n echo \"[Warning] Environment variable \\`$env_key\\` might have incorrect value, make sure this was intentional:\"\n echo \" Environment Value: $env_value\"\n echo \" Default Value: $default_value\"\n fi\n\n local value=\"${env_value:-$default_value}\"\n\n if [[ -z \"$value\" ]]; then\n echo \"[Error] Unable to find $name! Set the environment variable \\`$env_key\\` and try again.\"\n exit 0\n fi\n\n echo $value\n}\n\nmain \"$@\"; exit\n";
+ shellScript = "#!/bin/sh\n\n\nexport SOURCEMAP_FILE=\"$DERIVED_FILE_DIR/main.jsbundle.map\"\n\nmain() {\n # Read environment variables from ios/.xcode.env if it exists\n env_path=\"$PODS_ROOT/../.xcode.env\"\n if [ -f \"$env_path\" ]; then\n source \"$env_path\"\n fi\n\n # Read environment variables from ios/.xcode.env.local if it exists\n local_env_path=\"${ENV_PATH}.local\"\n if [ -f \"$local_env_path\" ]; then\n source \"$local_env_path\"\n fi\n\n if [[ \"$INSTABUG_SOURCEMAPS_UPLOAD_DISABLE\" = true ]]; then\n echo \"[Info] \\`INSTABUG_SOURCEMAPS_UPLOAD_DISABLE\\` was set to true, skipping sourcemaps upload...\"\n exit 0\n fi\n\n if [[ \"$CONFIGURATION\" = \"Debug\" ]]; then\n echo \"[Info] Building in debug mode, skipping sourcemaps upload...\"\n exit 0\n fi\n\n if [[ -z \"$INFOPLIST_FILE\" ]] || [[ -z \"$PROJECT_DIR\" ]]; then\n echo \"[Error] Instabug sourcemaps script must be invoked by Xcode\"\n exit 0\n fi\n\n\nlocal sourcemap_file=\"\"\n # Use existing sourcemap if available\n if [[ -f \"$SOURCEMAP_FILE\" ]]; then\n sourcemap_file=\"$SOURCEMAP_FILE\"\n else\n sourcemap_file=$(generate_sourcemaps | tail -n 1)\nfi\n\n local js_project_dir=\"$PROJECT_DIR/..\"\n local instabug_dir=$(dirname $(node -p \"require.resolve('instabug-reactnative/package.json')\"))\n local inferred_token=$(cd $js_project_dir && source $instabug_dir/scripts/find-token.sh)\n local app_token=$(resolve_var \"App Token\" \"INSTABUG_APP_TOKEN\" \"$inferred_token\" | tail -n 1)\n\n local inferred_name=$(/usr/libexec/PlistBuddy -c 'print CFBundleShortVersionString' \"$PROJECT_DIR/$INFOPLIST_FILE\")\n local version_name=$(resolve_var \"Version Name\" \"INSTABUG_APP_VERSION_NAME\" \"$inferred_name\" | tail -n 1)\n\n local inferred_code=$(/usr/libexec/PlistBuddy -c 'print CFBundleVersion' \"$PROJECT_DIR/$INFOPLIST_FILE\")\n local version_code=$(resolve_var \"Version Code\" \"INSTABUG_APP_VERSION_CODE\" \"$inferred_code\" | tail -n 1)\n\nif [ -n \"$sourcemap_file\" ]; then\n node $instabug_dir/bin/index.js upload-sourcemaps \\\n --platform ios \\\n --file $sourcemap_file \\\n --token $app_token \\\n --name $version_name \\\n --code $version_code\n fi\n}\n\ngenerate_sourcemaps() {\n local react_native_dir=$(dirname $(node -p \"require.resolve('react-native/package.json')\"))\n\n # Fixes an issue with react-native prior to v0.67.0\n # For more info: https://github.com/facebook/react-native/issues/32168\n export RN_DIR=$react_native_dir\n\n # Used withing `react-native-xcode.sh` to generate sourcemap file\n export SOURCEMAP_FILE=\"$(pwd)/main.jsbundle.map\";\n\n source \"$react_native_dir/scripts/react-native-xcode.sh\"\n\n if [[ ! -f \"$SOURCEMAP_FILE\" ]]; then\n echo \"[Error] Unable to find source map file at: $SOURCEMAP_FILE\"\n exit 0\n fi\n\n echo $SOURCEMAP_FILE\n}\n\nresolve_var() {\n local name=$1\n local env_key=$2\n local default_value=$3\n\n local env_value=\"${!env_key}\"\n\n if [[ -n \"$env_value\" ]] && [[ -n \"$default_value\" ]] && [[ \"$env_value\" != default_value ]]; then\n echo \"[Warning] Environment variable \\`$env_key\\` might have incorrect value, make sure this was intentional:\"\n echo \" Environment Value: $env_value\"\n echo \" Default Value: $default_value\"\n fi\n\n local value=\"${env_value:-$default_value}\"\n\n if [[ -z \"$value\" ]]; then\n echo \"[Error] Unable to find $name! Set the environment variable \\`$env_key\\` and try again.\"\n exit 0\n fi\n\n echo $value\n}\n\nmain \"$@\"; exit\n";
};
B77A7BA143DBD17E8AAFD0B4 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
diff --git a/examples/default/ios/InstabugTests/InstabugAPMTests.m b/examples/default/ios/InstabugTests/InstabugAPMTests.m
index 949393adb..40fae6129 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]);
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 34fe9cfe3..50e1cb2b9 100644
--- a/examples/default/ios/InstabugTests/InstabugSampleTests.m
+++ b/examples/default/ios/InstabugTests/InstabugSampleTests.m
@@ -69,17 +69,19 @@ - (void)testInit {
IBGInvocationEvent floatingButtonInvocationEvent = IBGInvocationEventFloatingButton;
NSString *appToken = @"app_token";
NSString *codePushVersion = @"1.0.0(1)";
+ NSString *appVariant = @"variant 1";
+
NSArray *invocationEvents = [NSArray arrayWithObjects:[NSNumber numberWithInteger:floatingButtonInvocationEvent], nil];
BOOL useNativeNetworkInterception = YES;
IBGSDKDebugLogsLevel sdkDebugLogsLevel = IBGSDKDebugLogsLevelDebug;
OCMStub([mock setCodePushVersion:codePushVersion]);
- [self.instabugBridge init:appToken invocationEvents:invocationEvents debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception codePushVersion:codePushVersion
- options:nil
- ];
+ [self.instabugBridge init:appToken invocationEvents:invocationEvents debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception codePushVersion:codePushVersion appVariant:appVariant options:nil ];
OCMVerify([mock setCodePushVersion:codePushVersion]);
+ XCTAssertEqual(Instabug.appVariant, appVariant);
+
OCMVerify([self.mRNInstabug initWithToken:appToken invocationEvents:floatingButtonInvocationEvent debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception]);
}
@@ -101,6 +103,14 @@ - (void)testSetUserData {
OCMVerify([mock setUserData:userData]);
}
+- (void)testSetAppVariant {
+ id mock = OCMClassMock([Instabug class]);
+ NSString *appVariant = @"appVariant";
+
+ [self.instabugBridge setAppVariant: appVariant];
+ XCTAssertEqual(Instabug.appVariant, appVariant);
+}
+
- (void)testSetTrackUserSteps {
id mock = OCMClassMock([Instabug class]);
BOOL isEnabled = true;
@@ -143,19 +153,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"];
@@ -199,7 +196,7 @@ - (void)testIdentifyUser {
NSString *email = @"em@il.com";
NSString *name = @"this is my name";
- OCMStub([mock identifyUserWithEmail:email name:name]);
+ OCMStub([mock identifyUserWithID:nil email:email name:name]);
[self.instabugBridge identifyUser:email name:name userId:nil];
OCMVerify([mock identifyUserWithID:nil email:email name:name]);
}
@@ -241,7 +238,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]);
}
@@ -488,30 +485,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]);
@@ -653,6 +626,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.lock b/examples/default/ios/Podfile.lock
index 274dbfc09..01837ec1a 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.1)
+ - Instabug (16.0.1)
- instabug-reactnative-ndk (0.1.0):
- DoubleConversion
- glog
@@ -1625,8 +1625,8 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- - RNInstabug (15.0.2):
- - Instabug (= 15.1.1)
+ - RNInstabug (16.0.0):
+ - Instabug (= 16.0.1)
- React-Core
- RNReanimated (3.16.1):
- DoubleConversion
@@ -2022,7 +2022,7 @@ SPEC CHECKSUMS:
Google-Maps-iOS-Utils: f77eab4c4326d7e6a277f8e23a0232402731913a
GoogleMaps: 032f676450ba0779bd8ce16840690915f84e57ac
hermes-engine: ea92f60f37dba025e293cbe4b4a548fd26b610a0
- Instabug: 3e7af445c14d7823fcdecba223f09b5f7c0c6ce1
+ Instabug: f31a27e70cb6580aef656d1abf8c57a5bb5633d0
instabug-reactnative-ndk: d765ac289d56e8896398d02760d9abf2562fc641
OCMock: 589f2c84dacb1f5aaf6e4cec1f292551fe748e74
RCT-Folly: 4464f4d875961fce86008d45f4ecf6cef6de0740
@@ -2090,7 +2090,7 @@ SPEC CHECKSUMS:
ReactCommon: 6a952e50c2a4b694731d7682aaa6c79bc156e4ad
RNCClipboard: 2821ac938ef46f736a8de0c8814845dde2dcbdfb
RNGestureHandler: 511250b190a284388f9dd0d2e56c1df76f14cfb8
- RNInstabug: c4d26c830b40c474422012d1a216d8ea37c88151
+ RNInstabug: 6cf5149b0b50ad7d6806d761fc2014ce27bae779
RNReanimated: f42a5044d121d68e91680caacb0293f4274228eb
RNScreens: c7ceced6a8384cb9be5e7a5e88e9e714401fd958
RNSVG: 8b1a777d54096b8c2a0fd38fc9d5a454332bbb4d
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 ad1c32579..82be996c5 100644
--- a/examples/default/src/App.tsx
+++ b/examples/default/src/App.tsx
@@ -49,6 +49,7 @@ export const App: React.FC = () => {
invocationEvents: [InvocationEvent.floatingButton],
debugLogsLevel: LogLevel.verbose,
networkInterceptionMode: NetworkInterceptionMode.javascript,
+ appVariant: 'App variant',
});
CrashReporting.setNDKCrashesEnabled(true);
diff --git a/examples/default/src/navigation/HomeStack.tsx b/examples/default/src/navigation/HomeStack.tsx
index 090aa6587..f3ebbf79b 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 { TracesScreen } from '../screens/apm/TracesScreen';
import { NetworkScreen } from '../screens/apm/NetworkScreen';
import { FlowsScreen } from '../screens/apm/FlowsScreen';
import { SessionReplayScreen } from '../screens/SessionReplayScreen';
@@ -140,7 +139,6 @@ export const HomeStackNavigator: React.FC = () => {
-
APM.endAppLaunch()} />
navigation.navigate('NetworkTraces')} />
- navigation.navigate('ExecutionTraces')} />
navigation.navigate('AppFlows')} />
navigation.navigate('WebViews')} />
navigation.navigate('ComplexViews')} />
diff --git a/examples/default/src/screens/apm/TracesScreen.tsx b/examples/default/src/screens/apm/TracesScreen.tsx
deleted file mode 100644
index bd3e41838..000000000
--- a/examples/default/src/screens/apm/TracesScreen.tsx
+++ /dev/null
@@ -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 TracesScreen: 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/ios/RNInstabug/InstabugAPMBridge.h b/ios/RNInstabug/InstabugAPMBridge.h
index 0a0ea397c..6b09dba6b 100644
--- a/ios/RNInstabug/InstabugAPMBridge.h
+++ b/ios/RNInstabug/InstabugAPMBridge.h
@@ -15,12 +15,6 @@
- (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;
diff --git a/ios/RNInstabug/InstabugAPMBridge.m b/ios/RNInstabug/InstabugAPMBridge.m
index c28c7f425..ab49af6fb 100644
--- a/ios/RNInstabug/InstabugAPMBridge.m
+++ b/ios/RNInstabug/InstabugAPMBridge.m
@@ -2,7 +2,6 @@
#import "InstabugAPMBridge.h"
#import
-#import
#import
#import
#import
@@ -27,12 +26,9 @@ + (BOOL)requiresMainQueueSetup
RCT_EXPORT_MODULE(IBGAPM)
-NSMutableDictionary *traces;
-
- (id) init
{
self = [super init];
- traces = [[NSMutableDictionary alloc] init];
return self;
}
@@ -61,41 +57,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) {
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/InstabugReactBridge.h b/ios/RNInstabug/InstabugReactBridge.h
index 45c075098..187caa6c6 100644
--- a/ios/RNInstabug/InstabugReactBridge.h
+++ b/ios/RNInstabug/InstabugReactBridge.h
@@ -26,13 +26,14 @@
- (void)setEnabled:(BOOL)isEnabled;
-- (void)init:(NSString *)token invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception codePushVersion:(NSString *)codePushVersion
-options:(nullable NSDictionary *)options;
+- (void)init:(NSString *)token invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception codePushVersion:(NSString *)codePushVersion appVariant:(NSString *)appVariant options:(nullable NSDictionary *)options;
- (void)setCodePushVersion:(NSString *)version;
- (void)setUserData:(NSString *)userData;
+- (void)setAppVariant:(NSString *)appVariant;
+
- (void)setTrackUserSteps:(BOOL)isEnabled;
- (void)setSessionProfilerEnabled:(BOOL)sessionProfilerEnabled;
@@ -43,6 +44,8 @@ options:(nullable NSDictionary *)options;
- (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 682896515..fe9e11e8a 100644
--- a/ios/RNInstabug/InstabugReactBridge.m
+++ b/ios/RNInstabug/InstabugReactBridge.m
@@ -42,8 +42,15 @@ - (dispatch_queue_t)methodQueue {
debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel
useNativeNetworkInterception:(BOOL)useNativeNetworkInterception
codePushVersion:(NSString *)codePushVersion
- options:(nullable NSDictionary *)options
- ) {
+ appVariant:(NSString *)appVariant
+ options:(nullable NSDictionary *)options
+
+ ) {
+
+ if(appVariant != nil){
+ Instabug.appVariant = appVariant;
+ }
+
IBGInvocationEvent invocationEvents = 0;
for (NSNumber *boxedValue in invocationEventsArray) {
@@ -62,10 +69,14 @@ - (dispatch_queue_t)methodQueue {
[Instabug setCodePushVersion:version];
}
+RCT_EXPORT_METHOD(setAppVariant:(NSString *)appVariant) {
+ Instabug.appVariant = appVariant;
+}
+
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) {
@@ -171,10 +182,88 @@ - (dispatch_queue_t)methodQueue {
[Instabug setColorTheme:colorTheme];
}
-RCT_EXPORT_METHOD(setPrimaryColor:(UIColor *)color) {
- 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];
}
@@ -357,18 +446,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 41f497687..6c1848522 100644
--- a/ios/native.rb
+++ b/ios/native.rb
@@ -1,4 +1,4 @@
-$instabug = { :version => '15.1.1' }
+$instabug = { :version => '16.0.1' }
def use_instabug! (spec = nil)
version = $instabug[:version]
diff --git a/ios/sourcemaps.sh b/ios/sourcemaps.sh
index 455247c4a..6b9eee7df 100644
--- a/ios/sourcemaps.sh
+++ b/ios/sourcemaps.sh
@@ -1,5 +1,8 @@
#!/bin/sh
+
+export SOURCEMAP_FILE="$DERIVED_FILE_DIR/main.jsbundle.map"
+
main() {
# Read environment variables from ios/.xcode.env if it exists
env_path="$PODS_ROOT/../.xcode.env"
@@ -28,7 +31,14 @@ main() {
exit 0
fi
- local source_map_file=$(generate_sourcemaps | tail -n 1)
+
+local sourcemap_file=""
+ # Use existing sourcemap if available
+ if [[ -f "$SOURCEMAP_FILE" ]]; then
+ sourcemap_file="$SOURCEMAP_FILE"
+ else
+ sourcemap_file=$(generate_sourcemaps | tail -n 1)
+fi
local js_project_dir="$PROJECT_DIR/.."
local instabug_dir=$(dirname $(node -p "require.resolve('instabug-reactnative/package.json')"))
@@ -41,12 +51,14 @@ main() {
local inferred_code=$(/usr/libexec/PlistBuddy -c 'print CFBundleVersion' "$PROJECT_DIR/$INFOPLIST_FILE")
local version_code=$(resolve_var "Version Code" "INSTABUG_APP_VERSION_CODE" "$inferred_code" | tail -n 1)
+if [ -n "$sourcemap_file" ]; then
node $instabug_dir/bin/index.js upload-sourcemaps \
--platform ios \
- --file $source_map_file \
+ --file $sourcemap_file \
--token $app_token \
--name $version_name \
--code $version_code
+ fi
}
generate_sourcemaps() {
diff --git a/package.json b/package.json
index 61af51056..ed64a12c7 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.2",
+ "version": "16.0.0",
"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 af1d6e841..bc3d5c747 100644
--- a/src/models/InstabugConfig.ts
+++ b/src/models/InstabugConfig.ts
@@ -24,6 +24,11 @@ export interface InstabugConfig {
*/
ignoreAndroidSecureFlag?: boolean;
+ /**
+ * An optional current App variant to be used for filtering data.
+ */
+ appVariant?: string;
+
/**
* 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 92d401389..9f2dcbe01 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.
*
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 fd4f17600..96177cd92 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;
@@ -126,6 +121,14 @@ export const init = (config: InstabugConfig) => {
}, 1000);
};
+/**
+ * Set Current App Variant.
+ * @param appVariant the current App variant name
+ */
+export const setAppVariant = (appVariant: string) => {
+ NativeInstabug.setAppVariant(appVariant);
+};
+
/**
* Handles app state changes and updates APM network flags if necessary.
*/
@@ -273,6 +276,7 @@ const initializeNativeInstabug = (config: InstabugConfig) => {
shouldEnableNativeInterception &&
config.networkInterceptionMode === NetworkInterceptionMode.native,
config.codePushVersion,
+ config.appVariant,
config.ignoreAndroidSecureFlag != null
? {
ignoreAndroidSecureFlag: config.ignoreAndroidSecureFlag,
@@ -392,9 +396,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 });
};
/**
@@ -778,35 +783,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.
@@ -898,3 +874,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 9fa30b702..86d017167 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;
diff --git a/src/native/NativeInstabug.ts b/src/native/NativeInstabug.ts
index c9c078f37..c350d705f 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,7 @@ export interface InstabugNativeModule extends NativeModule {
debugLogsLevel: LogLevel,
useNativeNetworkInterception: boolean,
codePushVersion?: string,
+ appVariant?: string,
options?: {
ignoreAndroidSecureFlag?: boolean;
},
@@ -34,6 +36,7 @@ export interface InstabugNativeModule extends NativeModule {
// Misc APIs //
setCodePushVersion(version: string): void;
+ setAppVariant(appVariant: string): void;
setIBGLogPrintsToConsole(printsToConsole: boolean): void;
setSessionProfilerEnabled(isEnabled: boolean): void;
@@ -121,10 +124,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;
@@ -161,9 +160,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/test/mocks/mockAPM.ts b/test/mocks/mockAPM.ts
index 27644c694..7a9c5bac9 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(),
diff --git a/test/mocks/mockInstabug.ts b/test/mocks/mockInstabug.ts
index 391a00a38..e6f41fc73 100644
--- a/test/mocks/mockInstabug.ts
+++ b/test/mocks/mockInstabug.ts
@@ -42,6 +42,7 @@ const mockInstabug: InstabugNativeModule = {
clearAllUserAttributes: jest.fn(),
showWelcomeMessageWithMode: jest.fn(),
setWelcomeMessageMode: jest.fn(),
+ setAppVariant: jest.fn(),
setFileAttachment: jest.fn(),
addPrivateView: jest.fn(),
removePrivateView: jest.fn(),
@@ -49,9 +50,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 +75,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 cf932d25c..ea703d3ea 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';
diff --git a/test/modules/Instabug.spec.ts b/test/modules/Instabug.spec.ts
index eeec8e8e4..bd21b3efc 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';
@@ -308,6 +308,7 @@ describe('Instabug Module', () => {
instabugConfig.debugLogsLevel,
usesNativeNetworkInterception,
instabugConfig.codePushVersion,
+ undefined,
{ ignoreAndroidSecureFlag: instabugConfig.ignoreAndroidSecureFlag },
);
});
@@ -359,6 +360,7 @@ describe('Instabug Module', () => {
// usesNativeNetworkInterception should be true when using native interception mode with iOS
true,
instabugConfig.codePushVersion,
+ undefined,
{ ignoreAndroidSecureFlag: instabugConfig.ignoreAndroidSecureFlag },
);
}
@@ -462,12 +464,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', () => {
@@ -832,25 +835,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 = [
{
@@ -960,6 +944,7 @@ describe('Instabug iOS initialization tests', () => {
false, // Disable native interception
config.codePushVersion,
config.ignoreAndroidSecureFlag,
+ undefined,
);
});
@@ -977,6 +962,7 @@ describe('Instabug iOS initialization tests', () => {
true, // Enable native interception
config.codePushVersion,
config.ignoreAndroidSecureFlag,
+ undefined,
);
});
@@ -994,6 +980,7 @@ describe('Instabug iOS initialization tests', () => {
false, // Disable native interception
config.codePushVersion,
config.ignoreAndroidSecureFlag,
+ undefined,
);
});
@@ -1036,6 +1023,7 @@ describe('Instabug Android initialization tests', () => {
config.debugLogsLevel,
false, // always disable native interception to insure sending network logs to core (Bugs & Crashes).
config.codePushVersion,
+ undefined,
{ ignoreAndroidSecureFlag: config.ignoreAndroidSecureFlag },
);
});
@@ -1104,4 +1092,21 @@ describe('Instabug Android initialization tests', () => {
);
});
});
+
+ it('should initialize correctly with App variant', async () => {
+ config.appVariant = 'App Variant';
+ await Instabug.init(config);
+ fakeTimer(() => {
+ expect(NativeInstabug.setOnFeaturesUpdatedListener).toHaveBeenCalled();
+ expect(NativeInstabug.init).toHaveBeenCalledWith(
+ config.token,
+ config.invocationEvents,
+ config.debugLogsLevel,
+ true,
+ config.codePushVersion,
+ config.appVariant,
+ undefined,
+ );
+ });
+ });
});