diff --git a/.circleci/config.yml b/.circleci/config.yml
index afebbdeaf..2ba5d1653 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -14,9 +14,6 @@ references:
- validate_shell_files
- sync_generated_files
- test_ios
- - e2e_ios
- - e2e_android
-
dream11_prepare_config: &dream11_prepare_config
prepare_steps:
- prepare_dream11
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 55cd87389..9f892abcd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,29 @@
# 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))
+
+- Add Support Eas updates. ([#1391](https://github.com/Instabug/Instabug-React-Native/pull/1391))
+
+- Add support for uploading sourcemap files in expo apps. ([#1392](https://github.com/Instabug/Instabug-React-Native/pull/1392))
+
+### 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.2 ([#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/README.md b/README.md
index ded285e95..5fbf38c18 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,21 @@ For more info, visit [Instabug.com](https://www.instabug.com).
yarn add instabug-reactnative
```
-2. CocoaPods on iOS needs this extra step:
+2. if you are using expo you need to add `instabug-reactnative` plugin to `app.json`:
+
+ ```json
+ "plugins" : [
+ [
+ "instabug-reactnative",
+ {
+ // optional that add Mic,Photo permission on iOS and FOREGROUND_SERVICE_MEDIA_PROJECTION on android
+ "addScreenRecordingBugReportingPermission": true
+ }
+ ]
+ ]
+ ```
+
+3. CocoaPods on iOS needs this extra step:
```bash
cd ios && pod install && cd ..
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..e5b2fb9db 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 {
@@ -15,11 +15,13 @@ gradle.projectsEvaluated {
def flavor = name.substring(start, end).uncapitalize()
def defaultVersion = getDefaultVersion(flavor)
- task.finalizedBy createUploadSourcemapsTask(flavor, defaultVersion.name, defaultVersion.code)
+
+
+ task.finalizedBy createUploadSourcemapsTask(flavor, defaultVersion.name, defaultVersion.code,task)
}
}
-Task createUploadSourcemapsTask(String flavor, String defaultVersionName, String defaultVersionCode) {
+Task createUploadSourcemapsTask(String flavor, String defaultVersionName, String defaultVersionCode, Task task) {
def name = 'uploadSourcemaps' + flavor.capitalize()
// Don't recreate the task if it already exists.
@@ -39,18 +41,26 @@ Task createUploadSourcemapsTask(String flavor, String defaultVersionName, String
try {
def appProject = project(':app')
def appDir = appProject.projectDir
- def sourceMapFile = getSourceMapFile(appDir, flavor)
+ def sourceMapFile = getSourceMapFile(appDir, flavor,task)
+ println "✅ Resolved sourcemap file path: ${sourceMapFile.absolutePath}"
def jsProjectDir = rootDir.parentFile
def instabugDir = new File(['node', '-p', 'require.resolve("instabug-reactnative/package.json")'].execute(null, rootDir).text.trim()).getParentFile()
- def tokenShellFile = new File(instabugDir, 'scripts/find-token.sh')
- def inferredToken = executeShellScript(tokenShellFile, jsProjectDir)
+ def tokenJsFile = new File(instabugDir, 'scripts/find-token.js')
+ def inferredToken = executeNodeScript(tokenJsFile, jsProjectDir)
+
+ if (!inferredToken) {
+ throw new GradleException("❌ Unable to infer Instabug token from script: ${tokenShellFile.absolutePath}")
+ }
+
def appToken = resolveVar('App Token', 'INSTABUG_APP_TOKEN', inferredToken)
def versionName = resolveVar('Version Name', 'INSTABUG_VERSION_NAME', defaultVersionName)
def versionCode = resolveVar('Version Code', 'INSTABUG_VERSION_CODE', defaultVersionCode)
+ println "📦 Uploading with versionName=${versionName}, versionCode=${versionCode}, appToken=${appToken.take(5)}..."
+
exec {
def osCompatibility = Os.isFamily(Os.FAMILY_WINDOWS) ? ['cmd', '/c'] : []
def args = [
@@ -67,6 +77,8 @@ Task createUploadSourcemapsTask(String flavor, String defaultVersionName, String
} catch (exception) {
project.logger.error "Failed to upload source map file.\n" +
"Reason: ${exception.message}"
+ throw exception
+
}
}
}
@@ -74,27 +86,48 @@ Task createUploadSourcemapsTask(String flavor, String defaultVersionName, String
return provider.get()
}
-File getSourceMapFile(File appDir, String flavor) {
+File getSourceMapFile(File appDir, String flavor, Task task) {
def defaultFlavorPath = flavor.empty ? 'release' : "${flavor}Release"
def defaultSourceMapDest = "build/generated/sourcemaps/react/${defaultFlavorPath}/index.android.bundle.map"
def defaultSourceMapFile = new File(appDir, defaultSourceMapDest)
+ def props = task.getProperties()
+
+ def bundleAssetName = props.containsKey("bundleAssetName") ? props.bundleAssetName?.getOrNull() : null
+ def jsSourceMapsDir = props.containsKey("jsSourceMapsDir") ? props.jsSourceMapsDir?.getOrNull() : null
+ def jsIntermediateSourceMapsDir = props.containsKey("jsIntermediateSourceMapsDir") ? props.jsIntermediateSourceMapsDir?.getOrNull() : null
+
+ if (bundleAssetName && jsSourceMapsDir) {
+ def outputSourceMap = new File(jsSourceMapsDir.asFile.absolutePath, "${bundleAssetName}.map")
+ if (outputSourceMap.exists()) {
+ return outputSourceMap
+ }
+ }
+
+ if (bundleAssetName && jsIntermediateSourceMapsDir) {
+ def packagerOutputSourceMap = new File(jsIntermediateSourceMapsDir.asFile.absolutePath, "${bundleAssetName}.packager.map")
+ if (packagerOutputSourceMap.exists()) {
+ return packagerOutputSourceMap
+ }
+ }
if (defaultSourceMapFile.exists()) {
return defaultSourceMapFile
}
if (flavor.empty) {
- throw new InvalidUserDataException("Unable to find source map file at: ${defaultSourceMapFile.absolutePath}.")
+ println"Source map file not found at: ${defaultSourceMapFile.absolutePath}. Skipping."
+ return null
}
def fallbackSourceMapDest = "build/generated/sourcemaps/react/${flavor}/release/index.android.bundle.map"
def fallbackSourceMapFile = new File(appDir, fallbackSourceMapDest)
- project.logger.info "Unable to find source map file at: ${defaultSourceMapFile.absolutePath}.\n" +
+ println "Unable to find source map file at: ${defaultSourceMapFile.absolutePath}.\n" +
"Falling back to ${fallbackSourceMapFile.absolutePath}."
if (!fallbackSourceMapFile.exists()) {
- throw new InvalidUserDataException("Unable to find source map file at: ${fallbackSourceMapFile.absolutePath} either.")
+ println "Fallback source map file not found at: ${fallbackSourceMapFile.absolutePath}. Skipping."
+ return null
}
return fallbackSourceMapFile
@@ -155,14 +188,56 @@ String resolveVar(String name, String envKey, String defaultValue) {
return value
}
+static String executeNodeScript(File script, File workingDir) {
+ if (!script.exists()) {
+ println "Script not found: ${script.absolutePath}"
+ return null
+ }
+
+ def output = new StringBuffer()
+ def error = new StringBuffer()
+
+ try {
+ def process = ['node', script.getAbsolutePath()].execute(null, workingDir)
+ process.waitForProcessOutput(output, error)
+
+ if (process.exitValue() != 0) {
+ println "Script failed with exit code ${process.exitValue()}"
+ println "Standard Error:\n${error.toString().trim()}"
+ println "Standard Output:\n${output.toString().trim()}"
+ return null
+ }
+
+ return output.toString().trim()
+
+ } catch (Exception e) {
+ println "Exception while executing Node.js script: ${e.message}"
+ e.printStackTrace()
+ return null
+ }
+}
+
static String executeShellScript(File script, File workingDir) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
return null
}
+ if (!script.canExecute()) {
+ // Try to set executable permission
+ script.setExecutable(true)
+ }
+
def output = new StringBuffer()
+ def error = new StringBuffer()
+
+ // Using 'sh' instead of './' to avoid needing exec permission, but keeping chmod above just in case
def process = ['sh', script.getAbsolutePath()].execute(null, workingDir)
- process?.waitForProcessOutput(output, new StringBuffer())
+ process?.waitForProcessOutput(output, error)
+
+ if (process.exitValue() != 0) {
+ println "Error running script: ${error.toString().trim()}"
+ return null
+ }
- return process?.exitValue() == 0 ? output.toString().trim() : null
+ return output.toString().trim()
}
diff --git a/android/src/main/java/com/instabug/reactlibrary/ArgsRegistry.java b/android/src/main/java/com/instabug/reactlibrary/ArgsRegistry.java
index 15fa45a1d..3c0175198 100644
--- a/android/src/main/java/com/instabug/reactlibrary/ArgsRegistry.java
+++ b/android/src/main/java/com/instabug/reactlibrary/ArgsRegistry.java
@@ -17,6 +17,7 @@
import com.instabug.library.invocation.util.InstabugVideoRecordingButtonPosition;
import com.instabug.library.sessionreplay.model.SessionMetadata;
import com.instabug.library.ui.onboarding.WelcomeMessage;
+import com.instabug.library.util.overairversion.OverAirVersionType;
import com.instabug.library.MaskingType;
import java.util.ArrayList;
@@ -61,6 +62,7 @@ static Map getAll() {
putAll(locales);
putAll(placeholders);
putAll(launchType);
+ putAll(overAirUpdateService);
putAll(autoMaskingTypes);
putAll(userConsentActionType);
}};
@@ -255,6 +257,11 @@ static Map getAll() {
put("warm",SessionMetadata.LaunchType.WARM );
put("unknown","unknown");
}};
+
+ public static ArgsMap overAirUpdateService = new ArgsMap() {{
+ put("expo", OverAirVersionType.EXPO);
+ put("codePush",OverAirVersionType.CODE_PUSH );
+ }};
// Temporary workaround to be removed in future release
// This is used for mapping native `LaunchType` values into React Native enum values.
diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java
index 7c0901936..716fe0e6a 100644
--- a/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java
+++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabug.java
@@ -6,6 +6,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.facebook.react.bridge.ReadableMap;
import com.instabug.apm.APM;
import com.instabug.library.Instabug;
import com.instabug.library.LogLevel;
@@ -59,18 +60,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 +120,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
@@ -161,10 +176,20 @@ public static class Builder {
*/
private String codePushVersion;
+ /**
+ * The overAirUpdate Version to be used for all reports.
+ */
+ private ReadableMap overAirVersion;
+
/**
* 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;
@@ -216,6 +241,16 @@ public Builder setCodePushVersion(String codePushVersion) {
return this;
}
+ /**
+ * Sets over air update version to be used for all reports.
+ *
+ * @param overAirVersion the over air update version and service map.
+ */
+ public Builder setOverAirVersion(ReadableMap overAirVersion) {
+ this.overAirVersion = overAirVersion;
+ return this;
+ }
+
/**
* Sets flag to override SDK screenshot security behavior.
*
@@ -237,6 +272,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,11 +297,25 @@ public void build() {
if (codePushVersion != null) {
instabugBuilder.setCodePushVersion(codePushVersion);
}
+ if(appVariant!=null){
+ instabugBuilder.setAppVariant(appVariant);
+ }
if (ignoreFlagSecure != null) {
instabugBuilder.ignoreFlagSecure(ignoreFlagSecure);
}
+ if (overAirVersion != null ) {
+ if (overAirVersion.hasKey("service") && overAirVersion.hasKey("version"))
+ {
+ if (overAirVersion.getString("service")!=null && overAirVersion.getString("version")!=null)
+ {
+ instabugBuilder.setOverAirVersion(overAirVersion.getString("version"),
+ ArgsRegistry.overAirUpdateService.get(overAirVersion.getString("service")));
+ }
+ }
+ }
+
instabugBuilder.build();
// Temporarily disabling APM hot launches
diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugAPMModule.java
index 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..68a775fe3 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,7 +156,11 @@ public void init(
final String logLevel,
final boolean useNativeNetworkInterception,
@Nullable final String codePushVersion,
- final ReadableMap map
+ @Nullable final String appVariant,
+ final ReadableMap map,
+ @Nullable final ReadableMap overAirVersion
+
+
) {
MainThreadHandler.runOnMainThread(new Runnable() {
@Override
@@ -178,6 +189,19 @@ public void run() {
builder.setCodePushVersion(codePushVersion);
}
}
+ if (appVariant != null) {
+ builder.setAppVariant(appVariant);
+ }
+
+ if(overAirVersion != null ) {
+ if(Instabug.isBuilt()) {
+ Instabug.setOverAirVersion(overAirVersion.getString("version"),
+ ArgsRegistry.overAirUpdateService.get(overAirVersion.getString("service")));
+ } else {
+ builder.setOverAirVersion(overAirVersion);
+ }
+ }
+
builder.build();
}
});
@@ -197,6 +221,22 @@ public void run() {
});
}
+ @ReactMethod
+ public void setOverAirVersion(@Nullable final ReadableMap overAirVersion) {
+ MainThreadHandler.runOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Instabug.setOverAirVersion(overAirVersion.getString("version"),
+ ArgsRegistry.overAirUpdateService.get(overAirVersion.getString("service")));
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
/**
* Adds tag(s) to issues before sending them
@@ -286,26 +326,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 +525,8 @@ public void run() {
});
}
+
+
/**
* Removes user attribute if exists.
*
@@ -954,14 +976,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 +1003,9 @@ public void run() {
try {
final View view = resolveReactView(reactTag);
+ if(view !=null){
Instabug.addPrivateViews(view);
+ }
} catch (Exception e) {
e.printStackTrace();
}
@@ -988,8 +1020,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 +1075,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 +1337,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..3751bea71 100644
--- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java
+++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java
@@ -24,6 +24,7 @@
import com.instabug.library.featuresflags.model.IBGFeatureFlag;
import com.instabug.library.internal.module.InstabugLocale;
import com.instabug.library.ui.onboarding.WelcomeMessage;
+import com.instabug.library.util.overairversion.OverAirVersionType;
import com.instabug.reactlibrary.utils.MainThreadHandler;
import com.instabug.library.MaskingType;
@@ -193,18 +194,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";
@@ -214,6 +203,21 @@ public void testSetCodePushVersion() {
mockInstabug.verify(() -> Instabug.setCodePushVersion(codePushVersion));
}
+ @Test
+ public void testSetOverAirVersion() {
+ WritableMap mockMap = mock(WritableMap.class);
+
+ String version="D0A12345-6789-4B3C-A123-4567ABCDEF0";
+
+ when(mockMap.getString("version")).thenReturn(version);
+ when(mockMap.getString("service")).thenReturn("expo");
+
+ rnModule.setOverAirVersion(mockMap);
+
+ mockInstabug.verify(() -> Instabug.setOverAirVersion(
+ version, OverAirVersionType.EXPO));
+ }
+
@Test
public void testIdentifyUserWithNoId() {
// given
@@ -535,51 +539,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 +590,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 +647,7 @@ public void testSetNetworkLogBodyDisabled() {
mockInstabug.verify(() -> Instabug.setNetworkLogBodyEnabled(false));
}
-
+
@Test
public void testEnableAutoMasking(){
@@ -704,4 +673,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/app.plugin.js b/app.plugin.js
new file mode 100644
index 000000000..3ae4fa6e4
--- /dev/null
+++ b/app.plugin.js
@@ -0,0 +1 @@
+module.exports = require('./expo');
diff --git a/cli/commands/UploadEasUpdatesSourcemaps.ts b/cli/commands/UploadEasUpdatesSourcemaps.ts
new file mode 100755
index 000000000..4a39eb769
--- /dev/null
+++ b/cli/commands/UploadEasUpdatesSourcemaps.ts
@@ -0,0 +1,36 @@
+import { Command, Option } from 'commander';
+import { UploadEasUpdatesSourcemaps, UploadEasUpdatesSourcemapsOptions } from '../upload';
+
+export const uploadEasUpdatesSourcemapsCommand = new Command();
+
+uploadEasUpdatesSourcemapsCommand
+ .name('upload-eas-updates-sourcemaps')
+ .addOption(
+ new Option('-f, --file ', 'The path of eas update folder')
+ .makeOptionMandatory()
+ .default('dist'),
+ )
+ .addOption(
+ new Option('-t, --token ', 'Your App Token')
+ .env('INSTABUG_APP_TOKEN')
+ .makeOptionMandatory(),
+ )
+ .addOption(
+ new Option('-n, --name ', 'The app version name')
+ .env('INSTABUG_APP_VERSION_NAME')
+ .makeOptionMandatory(),
+ )
+ .addOption(
+ new Option('-c, --code ', 'The app version code')
+ .env('INSTABUG_APP_VERSION_CODE')
+ .makeOptionMandatory(),
+ )
+ .addOption(
+ new Option('--androidUpdateId ', "The CodePush label if it's a CodePush release"),
+ )
+ .addOption(new Option('--iosUpdateId ', "The CodePush label if it's a CodePush release"))
+ .action(function (this: Command) {
+ const options = this.opts();
+ UploadEasUpdatesSourcemaps(options);
+ })
+ .showHelpAfterError();
diff --git a/cli/index.ts b/cli/index.ts
index 8df747e75..43ac14a9b 100644
--- a/cli/index.ts
+++ b/cli/index.ts
@@ -3,6 +3,7 @@ import { Command } from 'commander';
import { uploadSourcemapsCommand } from './commands/UploadSourcemaps';
import { UploadSoFilesCommand } from './commands/UploadSoFiles';
+import { uploadEasUpdatesSourcemapsCommand } from './commands/UploadEasUpdatesSourcemaps';
const program = new Command();
@@ -12,6 +13,7 @@ program
.description('A CLI for uploading source maps to Instabug dashboard.')
.usage('[command]')
.addCommand(uploadSourcemapsCommand)
- .addCommand(UploadSoFilesCommand);
+ .addCommand(UploadSoFilesCommand)
+ .addCommand(uploadEasUpdatesSourcemapsCommand);
program.parse(process.argv);
diff --git a/cli/upload/index.ts b/cli/upload/index.ts
index b09f4b243..7a2dc8c1a 100644
--- a/cli/upload/index.ts
+++ b/cli/upload/index.ts
@@ -1,2 +1,3 @@
export * from './uploadSourcemaps';
export * from './uploadSoFiles';
+export * from './uploadEasUpdatesSourcemaps';
diff --git a/cli/upload/uploadEasUpdatesSourcemaps.ts b/cli/upload/uploadEasUpdatesSourcemaps.ts
new file mode 100644
index 000000000..12ef00ed4
--- /dev/null
+++ b/cli/upload/uploadEasUpdatesSourcemaps.ts
@@ -0,0 +1,74 @@
+import fs from 'fs';
+import { uploadSourcemaps } from './uploadSourcemaps';
+import * as path from 'path';
+
+export interface UploadEasUpdatesSourcemapsOptions {
+ file: string;
+ token: string;
+ name: string;
+ code: string;
+ androidUpdateId?: string;
+ iosUpdateId?: string;
+ /**
+ * Disables logging to the console and prevents process exit on error.
+ *
+ * @default false
+ * */
+ silent?: boolean;
+}
+
+function getMapFile(folderPath: string): string | null {
+ try {
+ if (fs.existsSync(folderPath)) {
+ const files = fs.readdirSync(folderPath);
+ const mapFile = files.find((file) => file.endsWith('.map'));
+ if (!mapFile) {
+ return null;
+ }
+ return path.join(folderPath, mapFile);
+ }
+ return null;
+ } catch (err) {
+ console.error('Failed to read folder:', err);
+ return null;
+ }
+}
+
+/**
+ * Uploads JavaScript sourcemaps to Instabug.
+ *
+ * @param opts Options for the sourcemaps upload process.
+ * @returns A promise that resolves to a boolean indicating whether the upload was successful.
+ */
+export const UploadEasUpdatesSourcemaps = async (
+ opts: UploadEasUpdatesSourcemapsOptions,
+): Promise => {
+ const jsFolderPath = path.join(opts.file, '_expo', 'static', 'js');
+
+ const androidFile = getMapFile(path.join(jsFolderPath, 'android'));
+ const iosFile = getMapFile(path.join(jsFolderPath, 'ios'));
+ if (androidFile && fs.existsSync(androidFile)) {
+ await uploadSourcemaps({
+ platform: 'android',
+ name: opts.name,
+ code: opts.code,
+ token: opts.token,
+ label: opts.androidUpdateId,
+ file: androidFile,
+ silent: opts.silent,
+ });
+ }
+
+ if (iosFile && fs.existsSync(iosFile)) {
+ await uploadSourcemaps({
+ platform: 'ios',
+ name: opts.name,
+ code: opts.code,
+ token: opts.token,
+ label: opts.iosUpdateId,
+ file: iosFile,
+ silent: opts.silent,
+ });
+ }
+ return true;
+};
diff --git a/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj b/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj
index fb1253b31..5ccd8c8b7 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 && node $instabug_dir/scripts/find-token.js)\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..9798ed665 100644
--- a/examples/default/ios/InstabugTests/InstabugSampleTests.m
+++ b/examples/default/ios/InstabugTests/InstabugSampleTests.m
@@ -69,21 +69,32 @@ - (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];
+ NSDictionary *overAirVersion = @{
+ @"service":@"expo",
+ @"version":@"D0A12345-6789-4B3C-A123-4567ABCDEF01"
+ };
BOOL useNativeNetworkInterception = YES;
IBGSDKDebugLogsLevel sdkDebugLogsLevel = IBGSDKDebugLogsLevelDebug;
+ IBGOverAirType service = [ArgsRegistry.overAirServices[overAirVersion[@"service"]] intValue];
OCMStub([mock setCodePushVersion:codePushVersion]);
+ OCMStub([mock setOverAirVersion:overAirVersion[@"version"] withType:service]);
- [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 overAirVersion:overAirVersion ];
OCMVerify([mock setCodePushVersion:codePushVersion]);
+ OCMVerify([mock setOverAirVersion:overAirVersion[@"version"] withType:[overAirVersion[@"service"] intValue]]);
+
+
+ XCTAssertEqual(Instabug.appVariant, appVariant);
+
OCMVerify([self.mRNInstabug initWithToken:appToken invocationEvents:floatingButtonInvocationEvent debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception]);
}
-- (void)testSetCodePushVersion {
+- (void)test {
id mock = OCMClassMock([Instabug class]);
NSString *codePushVersion = @"123";
@@ -92,6 +103,20 @@ - (void)testSetCodePushVersion {
OCMVerify([mock setCodePushVersion:codePushVersion]);
}
+- (void)testSetOverAirVersion {
+ id mock = OCMClassMock([Instabug class]);
+ NSDictionary *overAirVersion = @{
+ @"service":@"expo",
+ @"version":@"D0A12345-6789-4B3C-A123-4567ABCDEF01"
+ };
+
+ [self.instabugBridge setOverAirVersion:overAirVersion];
+
+ IBGOverAirType service = [ArgsRegistry.overAirServices[overAirVersion[@"service"]] intValue];
+
+ OCMVerify([mock setOverAirVersion:overAirVersion[@"version"] withType:[overAirVersion[@"service"] intValue]]);
+}
+
- (void)testSetUserData {
id mock = OCMClassMock([Instabug class]);
NSString *userData = @"user_data";
@@ -101,6 +126,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 +176,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 +219,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 +261,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 +508,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 +649,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/InstabugTests/RNInstabugTests.m b/examples/default/ios/InstabugTests/RNInstabugTests.m
index abf355614..69a1b0fcd 100644
--- a/examples/default/ios/InstabugTests/RNInstabugTests.m
+++ b/examples/default/ios/InstabugTests/RNInstabugTests.m
@@ -73,4 +73,26 @@ - (void) testSetCodePushVersion {
OCMVerify([self.mInstabug setCodePushVersion:codePushVersion]);
}
+- (void)testSetOverAirVersionExpo {
+ NSDictionary *overAirVersion = @{
+ @"service":@(IBGOverAirTypeExpo),
+ @"version":@"D0A12345-6789-4B3C-A123-4567ABCDEF01"
+ };
+
+ [RNInstabug setOverAirVersion:overAirVersion];
+
+ OCMVerify([self.mInstabug setOverAirVersion:overAirVersion[@"version"] withType:[overAirVersion[@"service"] intValue]]);
+}
+
+- (void)testSetOverAirVersionCodepush {
+ NSDictionary *overAirVersion = @{
+ @"service":@(IBGOverAirTypeCodePush),
+ @"version":@"2.0.0"
+ };
+
+ [RNInstabug setOverAirVersion:overAirVersion];
+
+ OCMVerify([self.mInstabug setOverAirVersion:overAirVersion[@"version"] withType:[overAirVersion[@"service"] intValue]]);
+}
+
@end
diff --git a/examples/default/ios/Podfile b/examples/default/ios/Podfile
index e1dda08e3..f5b776d5b 100644
--- a/examples/default/ios/Podfile
+++ b/examples/default/ios/Podfile
@@ -16,7 +16,7 @@ target 'InstabugExample' do
rn_maps_path = '../node_modules/react-native-maps'
pod 'react-native-google-maps', :path => rn_maps_path
- # Flags change depending on the env values.
+ # add this line
flags = get_default_flags()
use_react_native!(
diff --git a/examples/default/ios/Podfile.lock b/examples/default/ios/Podfile.lock
index 274dbfc09..8e27864fd 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.2)
- 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.2)
- 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: 125f729dea4e4a43e815ae06f9db0332e2a5fd60
instabug-reactnative-ndk: d765ac289d56e8896398d02760d9abf2562fc641
OCMock: 589f2c84dacb1f5aaf6e4cec1f292551fe748e74
RCT-Folly: 4464f4d875961fce86008d45f4ecf6cef6de0740
@@ -2090,7 +2090,7 @@ SPEC CHECKSUMS:
ReactCommon: 6a952e50c2a4b694731d7682aaa6c79bc156e4ad
RNCClipboard: 2821ac938ef46f736a8de0c8814845dde2dcbdfb
RNGestureHandler: 511250b190a284388f9dd0d2e56c1df76f14cfb8
- RNInstabug: c4d26c830b40c474422012d1a216d8ea37c88151
+ RNInstabug: f06cf043f071311456d3ad14b4f9da628f2cd29b
RNReanimated: f42a5044d121d68e91680caacb0293f4274228eb
RNScreens: c7ceced6a8384cb9be5e7a5e88e9e714401fd958
RNSVG: 8b1a777d54096b8c2a0fd38fc9d5a454332bbb4d
@@ -2098,6 +2098,6 @@ SPEC CHECKSUMS:
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
Yoga: 055f92ad73f8c8600a93f0e25ac0b2344c3b07e6
-PODFILE CHECKSUM: 837b933596e1616ff02cc206bb17dee4f611fdbc
+PODFILE CHECKSUM: ac02ce223b69d8b05ac5901eaaac229f19e6d881
COCOAPODS: 1.14.0
diff --git a/examples/default/react-native.config.js b/examples/default/react-native.config.js
new file mode 100644
index 000000000..cbdf34c94
--- /dev/null
+++ b/examples/default/react-native.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ assets: ['./assets/fonts/'],
+};
diff --git a/examples/default/src/App.tsx b/examples/default/src/App.tsx
index ad1c32579..540086a97 100644
--- a/examples/default/src/App.tsx
+++ b/examples/default/src/App.tsx
@@ -13,6 +13,7 @@ import Instabug, {
NetworkLogger,
ReproStepsMode,
SessionReplay,
+ OverAirUpdateServices,
} from 'instabug-reactnative';
import { NativeBaseProvider } from 'native-base';
@@ -49,6 +50,8 @@ export const App: React.FC = () => {
invocationEvents: [InvocationEvent.floatingButton],
debugLogsLevel: LogLevel.verbose,
networkInterceptionMode: NetworkInterceptionMode.javascript,
+ appVariant: 'App variant',
+ overAirVersion: { service: OverAirUpdateServices.codePush, version: '1.0.0' },
});
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/expo.d.ts b/expo.d.ts
new file mode 100644
index 000000000..020de8e4b
--- /dev/null
+++ b/expo.d.ts
@@ -0,0 +1 @@
+export * from './plugin/build';
diff --git a/expo.js b/expo.js
new file mode 100644
index 000000000..3c7d11b61
--- /dev/null
+++ b/expo.js
@@ -0,0 +1 @@
+module.exports = require('./plugin/build');
diff --git a/ios/RNInstabug/ArgsRegistry.h b/ios/RNInstabug/ArgsRegistry.h
index c760ae36c..2197a8c31 100644
--- a/ios/RNInstabug/ArgsRegistry.h
+++ b/ios/RNInstabug/ArgsRegistry.h
@@ -23,6 +23,7 @@ typedef NSDictionary ArgsDictionary;
+ (ArgsDictionary *) locales;
+ (ArgsDictionary *)nonFatalExceptionLevel;
+ (ArgsDictionary *) launchType;
++ (ArgsDictionary *) overAirServices;
+ (ArgsDictionary *) userConsentActionTypes;
+ (NSDictionary *) placeholders;
diff --git a/ios/RNInstabug/ArgsRegistry.m b/ios/RNInstabug/ArgsRegistry.m
index 8fb1e9b77..b96229775 100644
--- a/ios/RNInstabug/ArgsRegistry.m
+++ b/ios/RNInstabug/ArgsRegistry.m
@@ -21,6 +21,8 @@ + (NSMutableDictionary *) getAll {
[all addEntriesFromDictionary:ArgsRegistry.nonFatalExceptionLevel];
[all addEntriesFromDictionary:ArgsRegistry.placeholders];
[all addEntriesFromDictionary:ArgsRegistry.launchType];
+ [all addEntriesFromDictionary:ArgsRegistry.overAirServices];
+
[all addEntriesFromDictionary:ArgsRegistry.autoMaskingTypes];
[all addEntriesFromDictionary:ArgsRegistry.userConsentActionTypes];
@@ -256,6 +258,12 @@ + (ArgsDictionary *) launchType {
@"unknown":@(LaunchTypeUnknown)
};
}
++ (ArgsDictionary *) overAirServices {
+ return @{
+ @"expo":@(IBGOverAirTypeExpo) ,
+ @"codePush":@(IBGOverAirTypeCodePush),
+ };
+}
+ (ArgsDictionary *)autoMaskingTypes {
return @{
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..79f8c1c23 100644
--- a/ios/RNInstabug/InstabugReactBridge.h
+++ b/ios/RNInstabug/InstabugReactBridge.h
@@ -26,13 +26,16 @@
- (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 overAirVersion:(NSDictionary *)overAirVersion;
- (void)setCodePushVersion:(NSString *)version;
+- (void)setOverAirVersion:(NSDictionary *)overAirVersion;
+
- (void)setUserData:(NSString *)userData;
+- (void)setAppVariant:(NSString *)appVariant;
+
- (void)setTrackUserSteps:(BOOL)isEnabled;
- (void)setSessionProfilerEnabled:(BOOL)sessionProfilerEnabled;
@@ -43,6 +46,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..1fb21af3f 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
+ overAirVersion :(NSDictionary *)overAirVersion
+ ) {
+
+ if(appVariant != nil){
+ Instabug.appVariant = appVariant;
+ }
+
IBGInvocationEvent invocationEvents = 0;
for (NSNumber *boxedValue in invocationEventsArray) {
@@ -52,6 +59,8 @@ - (dispatch_queue_t)methodQueue {
[Instabug setCodePushVersion:codePushVersion];
+ [Instabug setOverAirVersion:overAirVersion[@"version"] withType:[overAirVersion[@"service"] intValue]];
+
[RNInstabug initWithToken:token
invocationEvents:invocationEvents
debugLogsLevel:sdkDebugLogsLevel
@@ -62,10 +71,18 @@ - (dispatch_queue_t)methodQueue {
[Instabug setCodePushVersion:version];
}
+RCT_EXPORT_METHOD(setOverAirVersion:(NSDictionary *)overAirVersion) {
+ [Instabug setOverAirVersion:overAirVersion[@"version"] withType:[overAirVersion[@"service"] intValue]];
+}
+
+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 +188,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 +452,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/RNInstabug/RNInstabug.h b/ios/RNInstabug/RNInstabug.h
index 70612fef7..1f93a44e4 100644
--- a/ios/RNInstabug/RNInstabug.h
+++ b/ios/RNInstabug/RNInstabug.h
@@ -2,6 +2,7 @@
#define RNInstabug_h
#import
+#import "ArgsRegistry.h"
@interface RNInstabug : NSObject
@@ -27,6 +28,8 @@ useNativeNetworkInterception:(BOOL)useNativeNetworkInterception;
*/
+ (void)setCodePushVersion:(NSString *)codePushVersion;
++ (void)setOverAirVersion:(NSDictionary *)overAirVersion;
+
@end
#endif /* RNInstabug_h */
diff --git a/ios/RNInstabug/RNInstabug.m b/ios/RNInstabug/RNInstabug.m
index 3ea51ae59..ccf496ca5 100644
--- a/ios/RNInstabug/RNInstabug.m
+++ b/ios/RNInstabug/RNInstabug.m
@@ -61,6 +61,11 @@ + (void)setCodePushVersion:(NSString *)codePushVersion {
[Instabug setCodePushVersion:codePushVersion];
}
++ (void)setOverAirVersion:(NSDictionary *)overAirVersion {
+ [Instabug setOverAirVersion:overAirVersion[@"version"] withType:[overAirVersion[@"service"] intValue]];
+}
+
+
// Note: This function is used to bridge IBGNSLog with RCTLogFunction.
// This log function should not be used externally and is only an implementation detail.
void RNIBGLog(IBGLogLevel logLevel, NSString *format, ...) {
diff --git a/ios/native.rb b/ios/native.rb
index 41f497687..c351a93c3 100644
--- a/ios/native.rb
+++ b/ios/native.rb
@@ -1,4 +1,4 @@
-$instabug = { :version => '15.1.1' }
+$instabug = { :version => '16.0.2' }
def use_instabug! (spec = nil)
version = $instabug[:version]
diff --git a/ios/sourcemaps.sh b/ios/sourcemaps.sh
index 455247c4a..134eb90b1 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,11 +31,18 @@ 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')"))
- local inferred_token=$(cd $js_project_dir && source $instabug_dir/scripts/find-token.sh)
+ local inferred_token=$(cd $js_project_dir && node $instabug_dir/scripts/find-token.js)
local app_token=$(resolve_var "App Token" "INSTABUG_APP_TOKEN" "$inferred_token" | tail -n 1)
local inferred_name=$(/usr/libexec/PlistBuddy -c 'print CFBundleShortVersionString' "$PROJECT_DIR/$INFOPLIST_FILE")
@@ -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..1e3f32515 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",
@@ -54,7 +54,8 @@
"@types/jest": "^29.5.3",
"@types/node": "^20.4.8",
"@types/react-native": "^0.72.2",
- "axios": "^1.2.2",
+ "axios": "1.11.0",
+ "@expo/config-plugins": "7.8.4",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "^29.6.2",
"commander": "^11.0.0",
@@ -80,5 +81,10 @@
"typescript": "^4.8.4",
"wait-for-expect": "^3.0.2",
"xhr2": "^0.2.1"
+ },
+ "peerDependenciesMeta": {
+ "expo": {
+ "optional": true
+ }
}
}
diff --git a/plugin/src/index.ts b/plugin/src/index.ts
new file mode 100644
index 000000000..e701c4217
--- /dev/null
+++ b/plugin/src/index.ts
@@ -0,0 +1,5 @@
+import { withInstabug } from './withInstabug';
+
+export { withInstabug };
+
+export default withInstabug;
diff --git a/plugin/src/withInstabug.ts b/plugin/src/withInstabug.ts
new file mode 100644
index 000000000..d4eff3ad5
--- /dev/null
+++ b/plugin/src/withInstabug.ts
@@ -0,0 +1,57 @@
+import type { ConfigPlugin } from 'expo/config-plugins';
+import { createRunOncePlugin } from 'expo/config-plugins';
+
+import { withInstabugAndroid } from './withInstabugAndroid';
+import { withInstabugIOS } from './withInstabugIOS';
+
+export interface PluginProps {
+ name?: string;
+ forceUploadSourceMaps?: boolean;
+ addScreenRecordingBugReportingPermission?: boolean;
+ addBugReportingIosMediaPermission?: boolean;
+}
+
+const instabugPackage = require('../../package.json') as {
+ name: string;
+ version: string;
+};
+
+const withInstabugPlugin: ConfigPlugin = (config, props = {}) => {
+ const {
+ forceUploadSourceMaps = false,
+ addScreenRecordingBugReportingPermission = false,
+ addBugReportingIosMediaPermission = true,
+ } = props;
+
+ const sharedProps = {
+ ...props,
+ name: instabugPackage.name,
+ forceUploadSourceMaps,
+ addScreenRecordingBugReportingPermission,
+ addBugReportingIosMediaPermission,
+ };
+
+ let updatedConfig = config;
+
+ // Android configuration (only if source maps are enabled)
+ try {
+ updatedConfig = withInstabugAndroid(updatedConfig, sharedProps);
+ } catch (err) {
+ console.warn('[Instabug] Failed to configure Android project:', (err as Error).message ?? err);
+ }
+
+ // iOS configuration
+ try {
+ updatedConfig = withInstabugIOS(updatedConfig, sharedProps);
+ } catch (err) {
+ console.warn('[Instabug] Failed to configure iOS project:', (err as Error).message ?? err);
+ }
+
+ return updatedConfig;
+};
+
+export const withInstabug = createRunOncePlugin(
+ withInstabugPlugin,
+ instabugPackage.name,
+ instabugPackage.version,
+);
diff --git a/plugin/src/withInstabugAndroid.ts b/plugin/src/withInstabugAndroid.ts
new file mode 100644
index 000000000..e827beb70
--- /dev/null
+++ b/plugin/src/withInstabugAndroid.ts
@@ -0,0 +1,99 @@
+import type { ConfigPlugin } from 'expo/config-plugins';
+import { withAppBuildGradle, withAndroidManifest } from 'expo/config-plugins';
+import type { PluginProps } from './withInstabug';
+
+export const withInstabugAndroid: ConfigPlugin = (config, props) => {
+ config = withAppBuildGradle(config, (configAndroid) => {
+ if (props.forceUploadSourceMaps) {
+ const gradle = configAndroid.modResults;
+ const packageName = props.name;
+
+ if (!packageName) {
+ console.warn('[Instabug] Missing "name" in plugin props. Skipping Android configuration.');
+ return configAndroid;
+ }
+
+ if (gradle.language === 'groovy') {
+ gradle.contents = injectGroovyScript(gradle.contents, packageName);
+ } else if (gradle.language === 'kt') {
+ gradle.contents = injectKotlinScript(gradle.contents, packageName);
+ } else {
+ throw new Error(
+ '[Instabug] Unsupported Gradle language. Only Groovy and Kotlin DSL are supported.',
+ );
+ }
+ }
+ return configAndroid;
+ });
+
+ // Inject the permission if requested
+ if (props.addScreenRecordingBugReportingPermission) {
+ config = withAndroidManifest(config, (configAndroid) => {
+ const manifest = configAndroid.modResults;
+
+ const permissionName = 'android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION';
+ const alreadyExists = manifest.manifest['uses-permission']?.some(
+ (permission: any) => permission.$?.['android:name'] === permissionName,
+ );
+
+ if (!alreadyExists) {
+ manifest.manifest['uses-permission'] = [
+ ...(manifest.manifest['uses-permission'] || []),
+ {
+ $: {
+ 'android:name': permissionName,
+ },
+ },
+ ];
+ }
+
+ return configAndroid;
+ });
+ }
+
+ return config;
+};
+
+// --- Helper Functions ---
+
+function injectGroovyScript(buildGradle: string, packageName: string): string {
+ if (buildGradle.includes('sourcemaps.gradle')) {
+ return buildGradle;
+ }
+
+ const androidBlockPattern = /^android\s*{/m;
+ if (!androidBlockPattern.test(buildGradle)) {
+ console.warn('[Instabug] Could not find "android {" block in Groovy build.gradle.');
+ return buildGradle;
+ }
+
+ const script = `
+def instabugPath = ["node", "--print", "require('path').dirname(require.resolve('${packageName}/package.json'))"]
+ .execute()
+ .text
+ .trim()
+apply from: new File(instabugPath, "android/sourcemaps.gradle")
+`.trim();
+
+ return buildGradle.replace(androidBlockPattern, `${script}\n\nandroid {`);
+}
+
+function injectKotlinScript(buildGradle: string, packageName: string): string {
+ if (buildGradle.includes('sourcemaps.gradle')) {
+ return buildGradle;
+ }
+
+ const androidBlockPattern = /^android\s*{/m;
+ if (!androidBlockPattern.test(buildGradle)) {
+ console.warn('[Instabug] Could not find "android {" block in Kotlin build.gradle.kts.');
+ return buildGradle;
+ }
+
+ const script = `
+val instabugPath = listOf("node", "--print", "require('path').dirname(require.resolve("${packageName}/package.json"))")
+ .let { ProcessBuilder(it).start().inputStream.bufferedReader().readText().trim() }
+apply(from = File(instabugPath, "android/sourcemaps.gradle"))
+`.trim();
+
+ return buildGradle.replace(androidBlockPattern, `${script}\n\nandroid {`);
+}
diff --git a/plugin/src/withInstabugIOS.ts b/plugin/src/withInstabugIOS.ts
new file mode 100644
index 000000000..0815e0f26
--- /dev/null
+++ b/plugin/src/withInstabugIOS.ts
@@ -0,0 +1,109 @@
+import type { ConfigPlugin, XcodeProject } from 'expo/config-plugins';
+import { withXcodeProject, withInfoPlist } from 'expo/config-plugins';
+import type { PluginProps } from './withInstabug';
+import * as path from 'path';
+import * as fs from 'fs';
+
+const BUILD_PHASE = 'PBXShellScriptBuildPhase';
+const PHASE_COMMENT = 'Bundle React Native code and images';
+const INSTABUG_BUILD_PHASE = '[instabug-reactnative] Upload Sourcemap';
+
+export const withInstabugIOS: ConfigPlugin = (config, props) => {
+ let updatedConfig = withXcodeProject(config, (configXcode) => {
+ const xcodeProject = configXcode.modResults;
+ const buildPhases = xcodeProject.hash.project.objects[BUILD_PHASE];
+
+ if (!buildPhases) {
+ console.warn('[Instabug] No build phases found in Xcode project.');
+ return configXcode;
+ }
+
+ // Add Instabug build phase if not already present
+ const hasInstabugPhase = Boolean(findBuildPhase(buildPhases, INSTABUG_BUILD_PHASE));
+
+ if (!hasInstabugPhase && props.forceUploadSourceMaps) {
+ addInstabugBuildPhase(xcodeProject, props.name);
+ }
+
+ // Patch bundle React Native phase with source map export
+ const bundlePhase = xcodeProject.pbxItemByComment(PHASE_COMMENT, BUILD_PHASE);
+ if (bundlePhase?.shellScript) {
+ bundlePhase.shellScript = injectSourceMapExport(bundlePhase.shellScript);
+ }
+
+ return configXcode;
+ });
+
+ // Add media permissions to Info.plist if enabled
+ if (props.addBugReportingIosMediaPermission) {
+ const instabugConfig = config.extra?.instabug ?? {};
+
+ const microphonePermission =
+ instabugConfig.microphonePermission ||
+ 'This needs access to your microphone so you can attach voice notes.';
+
+ const photoLibraryPermission =
+ instabugConfig.photoLibraryPermission ||
+ 'This needs access to your photo library so you can attach images.';
+
+ updatedConfig = withInfoPlist(updatedConfig, (configXcode) => {
+ const plist = configXcode.ios.infoPlist ?? {};
+
+ if (!plist.NSMicrophoneUsageDescription) {
+ plist.NSMicrophoneUsageDescription = microphonePermission;
+ }
+
+ if (!plist.NSPhotoLibraryUsageDescription) {
+ plist.NSPhotoLibraryUsageDescription = photoLibraryPermission;
+ }
+
+ configXcode.ios.infoPlist = plist;
+ return configXcode;
+ });
+ }
+
+ return updatedConfig;
+};
+
+// Find a build phase by its clean name
+function findBuildPhase(buildPhases: any, targetName: string): any | undefined {
+ const target = targetName.toLowerCase().trim();
+ return Object.values(buildPhases).find((phase: any) => {
+ const rawName = phase?.name ?? '';
+ const cleanName = rawName
+ .toLowerCase()
+ .replace('[cp-user] ', '')
+ .replace(/^"+|"+$/g, '')
+ .trim();
+ return cleanName === target;
+ });
+}
+
+// Inject Instabug shell script phase
+function addInstabugBuildPhase(xcodeProject: XcodeProject, packageName: string): void {
+ try {
+ const packagePath = require.resolve(`${packageName}/package.json`);
+ const sourcemapScriptPath = path.join(path.dirname(packagePath), 'ios/sourcemaps.sh');
+
+ if (!fs.existsSync(sourcemapScriptPath)) {
+ console.warn(`[Instabug] sourcemaps.sh not found at: ${sourcemapScriptPath}`);
+ return;
+ }
+
+ xcodeProject.addBuildPhase([], BUILD_PHASE, INSTABUG_BUILD_PHASE, null, {
+ shellPath: '/bin/sh',
+ shellScript: `/bin/sh ${sourcemapScriptPath}`,
+ });
+ } catch (err) {
+ console.warn(`[Instabug] Failed to resolve package path for "${packageName}":`, err);
+ }
+}
+
+// Inject source map export line into the shell script
+function injectSourceMapExport(script: string): string {
+ const exportLine = 'export SOURCEMAP_FILE="$DERIVED_FILE_DIR/main.jsbundle.map"';
+ const escapedLine = exportLine.replace(/\$/g, '\\$').replace(/"/g, '\\"');
+ const injectedLine = `${escapedLine}\\n`;
+
+ return script.includes(escapedLine) ? script : script.replace(/^"/, `"${injectedLine}`);
+}
diff --git a/plugin/tsconfig.json b/plugin/tsconfig.json
new file mode 100644
index 000000000..6b7ac0e4d
--- /dev/null
+++ b/plugin/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "compilerOptions": {
+ "outDir": "build",
+ "rootDir": "src"
+ },
+ "include": ["./src"]
+}
diff --git a/rollup.config.js b/rollup.config.js
index ae91a8906..62bb06ced 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -23,6 +23,14 @@ export default [
},
plugins: [...commonPlugins, typescript({ tsconfig: './tsconfig.cli.json' })],
},
+ {
+ input: ['plugin/src/index.ts'],
+ output: {
+ dir: 'plugin/build',
+ format: 'cjs',
+ },
+ plugins: [...commonPlugins, typescript({ tsconfig: './plugin/tsconfig.json' })],
+ },
{
input: ['cli/upload/index.ts'],
output: {
diff --git a/scripts/find-token.js b/scripts/find-token.js
new file mode 100755
index 000000000..1a69dca60
--- /dev/null
+++ b/scripts/find-token.js
@@ -0,0 +1,58 @@
+const fs = require('fs');
+const path = require('path');
+
+const IGNORED_DIRS = new Set(['node_modules', 'ios', 'android']);
+const INCLUDED_EXTENSIONS = new Set(['.js', '.ts', '.jsx', '.tsx']);
+
+function getAllFiles(dir, fileList = []) {
+ const files = fs.readdirSync(dir);
+ for (const file of files) {
+ const fullPath = path.join(dir, file);
+ const stat = fs.statSync(fullPath);
+ if (stat.isDirectory()) {
+ if (!IGNORED_DIRS.has(file)) {
+ getAllFiles(fullPath, fileList);
+ }
+ } else {
+ if (INCLUDED_EXTENSIONS.has(path.extname(fullPath))) {
+ fileList.push(fullPath);
+ }
+ }
+ }
+ return fileList;
+}
+
+function extractTokenFromInit(content) {
+ const initMatch = content.match(/Instabug\.init\(\s*{[\s\S]*?token:\s*['"]([0-9a-zA-Z]+)['"]/);
+ return initMatch ? initMatch[1] : null;
+}
+
+function extractTokenFromStart(content) {
+ const startMatch = content.match(/Instabug\.start\(\s*['"]([0-9a-zA-Z]+)['"]/);
+ return startMatch ? startMatch[1] : null;
+}
+
+function findInstabugToken() {
+ const allFiles = getAllFiles('.');
+
+ for (const file of allFiles) {
+ const content = fs.readFileSync(file, 'utf-8');
+
+ const initToken = extractTokenFromInit(content);
+ if (initToken) {
+ console.log(initToken);
+ process.exit(0);
+ }
+
+ const startToken = extractTokenFromStart(content);
+ if (startToken) {
+ console.log(startToken);
+ process.exit(0);
+ }
+ }
+
+ console.log("Couldn't find Instabug's app token");
+ process.exit(1);
+}
+
+findInstabugToken();
diff --git a/scripts/find-token.sh b/scripts/find-token.sh
old mode 100644
new mode 100755
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..4d7e231e0 100644
--- a/src/models/InstabugConfig.ts
+++ b/src/models/InstabugConfig.ts
@@ -1,4 +1,5 @@
import type { InvocationEvent, LogLevel, NetworkInterceptionMode } from '../utils/Enums';
+import type { OverAirUpdate } from './OverAirUpdate';
export interface InstabugConfig {
/**
@@ -24,6 +25,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.
@@ -34,4 +40,9 @@ export interface InstabugConfig {
* @default NetworkInterceptionMode.javascript
*/
networkInterceptionMode?: NetworkInterceptionMode;
+
+ /**
+ * An optional over air service update version to be used for all reports.
+ */
+ overAirVersion?: OverAirUpdate;
}
diff --git a/src/models/OverAirUpdate.ts b/src/models/OverAirUpdate.ts
new file mode 100644
index 000000000..7808445fe
--- /dev/null
+++ b/src/models/OverAirUpdate.ts
@@ -0,0 +1,14 @@
+import type { OverAirUpdateServices } from '../utils/Enums';
+export interface OverAirUpdate {
+ /**
+ * the name of OTA service
+ * e.g. `codePush` or `expo`
+ */
+ service: OverAirUpdateServices;
+
+ /**
+ * The version or UUID of the OTA service
+ */
+
+ version: string;
+}
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..8bf40e711 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,8 @@ import { NativeNetworkLogger } from '../native/NativeNetworkLogger';
import InstabugConstants from '../utils/InstabugConstants';
import { InstabugRNConfig } from '../utils/config';
import { Logger } from '../utils/logger';
+import type { OverAirUpdate } from '../models/OverAirUpdate';
+import type { ThemeConfig } from '../models/ThemeConfig';
let _currentScreen: string | null = null;
let _lastScreen: string | null = null;
@@ -126,6 +122,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,11 +277,13 @@ const initializeNativeInstabug = (config: InstabugConfig) => {
shouldEnableNativeInterception &&
config.networkInterceptionMode === NetworkInterceptionMode.native,
config.codePushVersion,
+ config.appVariant,
config.ignoreAndroidSecureFlag != null
? {
ignoreAndroidSecureFlag: config.ignoreAndroidSecureFlag,
}
: undefined,
+ config.overAirVersion,
);
};
@@ -320,11 +326,22 @@ function addOnFeatureUpdatedListener(config: InstabugConfig) {
/**
* Sets the Code Push version to be sent with each report.
* @param version the Code Push version.
+ *
+ * @deprecated Use {@link setOverAirVersion} instead.
*/
export const setCodePushVersion = (version: string) => {
NativeInstabug.setCodePushVersion(version);
};
+/**
+ * Sets over air update version to be sent with each report.
+ * @param version the OTA version.
+ *
+ */
+export const setOverAirVersion = (OTAserviceVersion: OverAirUpdate) => {
+ NativeInstabug.setOverAirVersion(OTAserviceVersion);
+};
+
/**
* Attaches user data to each report being sent.
* Each call to this method overrides the user data to be attached.
@@ -392,9 +409,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 +796,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 +887,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/NativeConstants.ts b/src/native/NativeConstants.ts
index f95634caf..22891ebf3 100644
--- a/src/native/NativeConstants.ts
+++ b/src/native/NativeConstants.ts
@@ -14,6 +14,7 @@ export type NativeConstants = NativeSdkDebugLogsLevel &
NativeNonFatalErrorLevel &
NativeStringKey &
NativeLaunchType &
+ NativeOverAirUpdateServices &
NativeAutoMaskingType &
NativeUserConsentActionType;
@@ -202,6 +203,10 @@ interface NativeLaunchType {
unknown: any;
}
+interface NativeOverAirUpdateServices {
+ expo: any;
+ codePush: any;
+}
interface NativeAutoMaskingType {
labels: any;
textInputs: any;
diff --git a/src/native/NativeInstabug.ts b/src/native/NativeInstabug.ts
index c9c078f37..1acecb5e4 100644
--- a/src/native/NativeInstabug.ts
+++ b/src/native/NativeInstabug.ts
@@ -14,6 +14,8 @@ import type {
import type { NativeConstants } from './NativeConstants';
import type { W3cExternalTraceAttributes } from '../models/W3cExternalTraceAttributes';
import { NativeModules } from './NativePackage';
+import type { OverAirUpdate } from '../models/OverAirUpdate';
+import type { ThemeConfig } from '../models/ThemeConfig';
export interface InstabugNativeModule extends NativeModule {
getConstants(): NativeConstants;
@@ -26,14 +28,18 @@ export interface InstabugNativeModule extends NativeModule {
debugLogsLevel: LogLevel,
useNativeNetworkInterception: boolean,
codePushVersion?: string,
+ appVariant?: string,
options?: {
ignoreAndroidSecureFlag?: boolean;
},
+ overAirVersion?: OverAirUpdate,
): void;
show(): void;
// Misc APIs //
setCodePushVersion(version: string): void;
+ setOverAirVersion(OTAserviceVersion: OverAirUpdate): void;
+ setAppVariant(appVariant: string): void;
setIBGLogPrintsToConsole(printsToConsole: boolean): void;
setSessionProfilerEnabled(isEnabled: boolean): void;
@@ -121,10 +127,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 +163,12 @@ export interface InstabugNativeModule extends NativeModule {
setOnFeaturesUpdatedListener(handler?: (params: any) => void): void; // android only
enableAutoMasking(autoMaskingTypes: AutoMaskingType[]): void;
getNetworkBodyMaxSize(): Promise;
+
+ setTheme(theme: ThemeConfig): void;
+ setFullscreen(isEnabled: boolean): void;
}
-export const NativeInstabug = NativeModules.Instabug;
+export const NativeInstabug = NativeModules.Instabug as InstabugNativeModule;
export enum NativeEvents {
PRESENDING_HANDLER = 'IBGpreSendingHandler',
diff --git a/src/utils/Enums.ts b/src/utils/Enums.ts
index 1859ed2be..7044f49a2 100644
--- a/src/utils/Enums.ts
+++ b/src/utils/Enums.ts
@@ -250,6 +250,14 @@ export enum LaunchType {
*/
warm = constants.warm,
}
+
+/**
+ * Over Air Update Service
+ */
+export enum OverAirUpdateServices {
+ codePush = constants.codePush,
+ expo = constants.expo,
+}
export enum AutoMaskingType {
labels = constants.labels,
textInputs = constants.textInputs,
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..01e1a59da 100644
--- a/test/mocks/mockInstabug.ts
+++ b/test/mocks/mockInstabug.ts
@@ -14,6 +14,7 @@ const mockInstabug: InstabugNativeModule = {
setEnabled: jest.fn(),
init: jest.fn(),
setCodePushVersion: jest.fn(),
+ setOverAirVersion: jest.fn(),
setUserData: jest.fn(),
setTrackUserSteps: jest.fn(),
setIBGLogPrintsToConsole: jest.fn(),
@@ -42,6 +43,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 +51,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 +76,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..efae19f65 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';
@@ -18,6 +18,7 @@ import {
Locale,
LogLevel,
NetworkInterceptionMode,
+ OverAirUpdateServices,
ReproStepsMode,
StringKey,
WelcomeMessageMode,
@@ -295,6 +296,10 @@ describe('Instabug Module', () => {
debugLogsLevel: LogLevel.debug,
codePushVersion: '1.1.0',
ignoreAndroidSecureFlag: true,
+ overAirVersion: {
+ service: OverAirUpdateServices.expo,
+ version: 'D0A12345-6789-4B3C-A123-4567ABCDEF01',
+ },
};
const usesNativeNetworkInterception = false;
@@ -308,7 +313,9 @@ describe('Instabug Module', () => {
instabugConfig.debugLogsLevel,
usesNativeNetworkInterception,
instabugConfig.codePushVersion,
+ undefined,
{ ignoreAndroidSecureFlag: instabugConfig.ignoreAndroidSecureFlag },
+ instabugConfig.overAirVersion,
);
});
@@ -321,6 +328,18 @@ describe('Instabug Module', () => {
expect(NativeInstabug.setCodePushVersion).toBeCalledWith(codePushVersion);
});
+ it('setOverAirVersion should call native method setOverAirVersion', () => {
+ const OTAversion = {
+ service: OverAirUpdateServices.expo,
+ version: 'D0A12345-6789-4B3C-A123-4567ABCDEF01',
+ };
+
+ Instabug.setOverAirVersion(OTAversion);
+
+ expect(NativeInstabug.setOverAirVersion).toBeCalledTimes(1);
+ expect(NativeInstabug.setOverAirVersion).toBeCalledWith(OTAversion);
+ });
+
it('init should disable JavaScript interceptor when using native interception mode', () => {
const instabugConfig = {
token: 'some-token',
@@ -329,6 +348,10 @@ describe('Instabug Module', () => {
networkInterceptionMode: NetworkInterceptionMode.native,
codePushVersion: '1.1.0',
ignoreAndroidSecureFlag: true,
+ overAirVersion: {
+ service: OverAirUpdateServices.expo,
+ version: 'D0A12345-6789-4B3C-A123-4567ABCDEF01',
+ },
};
// Stubbing Network feature flags
@@ -348,6 +371,7 @@ describe('Instabug Module', () => {
// usesNativeNetworkInterception should be false when using native interception mode with Android
false,
instabugConfig.codePushVersion,
+ instabugConfig.overAirVersion,
);
} else {
expect(NativeInstabug.init).toBeCalledTimes(1);
@@ -359,7 +383,9 @@ describe('Instabug Module', () => {
// usesNativeNetworkInterception should be true when using native interception mode with iOS
true,
instabugConfig.codePushVersion,
+ undefined,
{ ignoreAndroidSecureFlag: instabugConfig.ignoreAndroidSecureFlag },
+ instabugConfig.overAirVersion,
);
}
});
@@ -462,12 +488,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 +859,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 = [
{
@@ -941,6 +949,10 @@ describe('Instabug iOS initialization tests', () => {
debugLogsLevel: LogLevel.debug,
networkInterceptionMode: NetworkInterceptionMode.native,
codePushVersion: '1.1.0',
+ overAirVersion: {
+ service: OverAirUpdateServices.expo,
+ version: 'D0A12345-6789-4B3C-A123-4567ABCDEF01',
+ },
};
// Fast-forward until all timers have been executed
jest.advanceTimersByTime(1000);
@@ -960,6 +972,8 @@ describe('Instabug iOS initialization tests', () => {
false, // Disable native interception
config.codePushVersion,
config.ignoreAndroidSecureFlag,
+ undefined,
+ config.overAirVersion,
);
});
@@ -976,7 +990,9 @@ describe('Instabug iOS initialization tests', () => {
config.debugLogsLevel,
true, // Enable native interception
config.codePushVersion,
- config.ignoreAndroidSecureFlag,
+ undefined,
+ undefined,
+ config.overAirVersion,
);
});
@@ -994,6 +1010,8 @@ describe('Instabug iOS initialization tests', () => {
false, // Disable native interception
config.codePushVersion,
config.ignoreAndroidSecureFlag,
+ undefined,
+ config.overAirVersion,
);
});
@@ -1021,6 +1039,10 @@ describe('Instabug Android initialization tests', () => {
debugLogsLevel: LogLevel.debug,
networkInterceptionMode: NetworkInterceptionMode.javascript,
codePushVersion: '1.1.0',
+ overAirVersion: {
+ service: OverAirUpdateServices.expo,
+ version: 'D0A12345-6789-4B3C-A123-4567ABCDEF01',
+ },
};
});
@@ -1037,6 +1059,8 @@ describe('Instabug Android initialization tests', () => {
false, // always disable native interception to insure sending network logs to core (Bugs & Crashes).
config.codePushVersion,
{ ignoreAndroidSecureFlag: config.ignoreAndroidSecureFlag },
+ undefined,
+ config.overAirVersion,
);
});
});
@@ -1104,4 +1128,22 @@ 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,
+ config.overAirVersion,
+ );
+ });
+ });
});
diff --git a/yarn.lock b/yarn.lock
index 7d8e53b23..d5cf44ade 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -41,6 +41,13 @@
dependencies:
"@babel/highlight" "^7.22.5"
+"@babel/code-frame@~7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
+ integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
+ dependencies:
+ "@babel/highlight" "^7.10.4"
+
"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9":
version "7.22.9"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730"
@@ -254,6 +261,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
+"@babel/helper-validator-identifier@^7.25.9":
+ version "7.27.1"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
+ integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
+
"@babel/helper-validator-option@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac"
@@ -277,6 +289,16 @@
"@babel/traverse" "^7.22.6"
"@babel/types" "^7.22.5"
+"@babel/highlight@^7.10.4":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.9.tgz#8141ce68fc73757946f983b343f1231f4691acc6"
+ integrity sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.25.9"
+ chalk "^2.4.2"
+ js-tokens "^4.0.0"
+ picocolors "^1.0.0"
+
"@babel/highlight@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031"
@@ -855,6 +877,77 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.46.0.tgz#3f7802972e8b6fe3f88ed1aabc74ec596c456db6"
integrity sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==
+"@expo/config-plugins@7.8.4":
+ version "7.8.4"
+ resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-7.8.4.tgz#533b5d536c1dc8b5544d64878b51bda28f2e1a1f"
+ integrity sha512-hv03HYxb/5kX8Gxv/BTI8TLc9L06WzqAfHRRXdbar4zkLcP2oTzvsLEF4/L/TIpD3rsnYa0KU42d0gWRxzPCJg==
+ dependencies:
+ "@expo/config-types" "^50.0.0-alpha.1"
+ "@expo/fingerprint" "^0.6.0"
+ "@expo/json-file" "~8.3.0"
+ "@expo/plist" "^0.1.0"
+ "@expo/sdk-runtime-versions" "^1.0.0"
+ "@react-native/normalize-color" "^2.0.0"
+ chalk "^4.1.2"
+ debug "^4.3.1"
+ find-up "~5.0.0"
+ getenv "^1.0.0"
+ glob "7.1.6"
+ resolve-from "^5.0.0"
+ semver "^7.5.3"
+ slash "^3.0.0"
+ slugify "^1.6.6"
+ xcode "^3.0.1"
+ xml2js "0.6.0"
+
+"@expo/config-types@^50.0.0-alpha.1":
+ version "50.0.1"
+ resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-50.0.1.tgz#12d889214dedf64fbf2322c9d9e75c9d5ca7f695"
+ integrity sha512-EZHMgzkWRB9SMHO1e9m8s+OMahf92XYTnsCFjxhSfcDrcEoSdFPyJWDJVloHZPMGhxns7Fi2+A+bEVN/hD4NKA==
+
+"@expo/fingerprint@^0.6.0":
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/@expo/fingerprint/-/fingerprint-0.6.1.tgz#763ae79b06f60e10853596bfa2bd730bfb13f2b0"
+ integrity sha512-ggLn6unI6qowlA1FihdQwPpLn16VJulYkvYAEL50gaqVahfNEglRQMSH2giZzjD0d6xq2/EQuUdFyHaJfyJwOQ==
+ dependencies:
+ "@expo/spawn-async" "^1.5.0"
+ chalk "^4.1.2"
+ debug "^4.3.4"
+ find-up "^5.0.0"
+ minimatch "^3.0.4"
+ p-limit "^3.1.0"
+ resolve-from "^5.0.0"
+
+"@expo/json-file@~8.3.0":
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.3.3.tgz#7926e3592f76030ce63d6b1308ac8f5d4d9341f4"
+ integrity sha512-eZ5dld9AD0PrVRiIWpRkm5aIoWBw3kAyd8VkuWEy92sEthBKDDDHAnK2a0dw0Eil6j7rK7lS/Qaq/Zzngv2h5A==
+ dependencies:
+ "@babel/code-frame" "~7.10.4"
+ json5 "^2.2.2"
+ write-file-atomic "^2.3.0"
+
+"@expo/plist@^0.1.0":
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.1.3.tgz#b4fbee2c4f7a88512a4853d85319f4d95713c529"
+ integrity sha512-GW/7hVlAylYg1tUrEASclw1MMk9FP4ZwyFAY/SUTJIhPDQHtfOlXREyWV3hhrHdX/K+pS73GNgdfT6E/e+kBbg==
+ dependencies:
+ "@xmldom/xmldom" "~0.7.7"
+ base64-js "^1.2.3"
+ xmlbuilder "^14.0.0"
+
+"@expo/sdk-runtime-versions@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz#d7ebd21b19f1c6b0395e50d78da4416941c57f7c"
+ integrity sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==
+
+"@expo/spawn-async@^1.5.0":
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.7.2.tgz#fcfe66c3e387245e72154b1a7eae8cada6a47f58"
+ integrity sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==
+ dependencies:
+ cross-spawn "^7.0.3"
+
"@gitbeaker/core@^21.7.0":
version "21.7.0"
resolved "https://registry.yarnpkg.com/@gitbeaker/core/-/core-21.7.0.tgz#fcf7a12915d39f416e3f316d0a447a814179b8e5"
@@ -1563,6 +1656,11 @@
resolved "https://registry.yarnpkg.com/@react-native/js-polyfills/-/js-polyfills-0.72.1.tgz#905343ef0c51256f128256330fccbdb35b922291"
integrity sha512-cRPZh2rBswFnGt5X5EUEPs0r+pAsXxYsifv/fgy9ZLQokuT52bPH+9xjDR+7TafRua5CttGW83wP4TntRcWNDA==
+"@react-native/normalize-color@^2.0.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91"
+ integrity sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA==
+
"@react-native/normalize-colors@*":
version "0.73.0"
resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.73.0.tgz#23e15cf2a2b73ac7e5e6df8d5b86b173cfb35a3f"
@@ -2032,6 +2130,16 @@
dependencies:
tslib "^2.3.0"
+"@xmldom/xmldom@^0.8.8":
+ version "0.8.11"
+ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz#b79de2d67389734c57c52595f7a7305e30c2d608"
+ integrity sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==
+
+"@xmldom/xmldom@~0.7.7":
+ version "0.7.13"
+ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.13.tgz#ff34942667a4e19a9f4a0996a76814daac364cf3"
+ integrity sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==
+
abort-controller@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
@@ -2265,13 +2373,13 @@ available-typed-arrays@^1.0.5:
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
-axios@^1.2.2:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f"
- integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==
+axios@1.11.0:
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.11.0.tgz#c2ec219e35e414c025b2095e8b8280278478fdb6"
+ integrity sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==
dependencies:
- follow-redirects "^1.15.0"
- form-data "^4.0.0"
+ follow-redirects "^1.15.6"
+ form-data "^4.0.4"
proxy-from-env "^1.1.0"
babel-core@7.0.0-bridge.0, babel-core@^7.0.0-bridge.0:
@@ -2413,7 +2521,7 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-base64-js@^1.1.2, base64-js@^1.3.1:
+base64-js@^1.1.2, base64-js@^1.2.3, base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
@@ -2423,6 +2531,11 @@ before-after-hook@^2.2.0:
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c"
integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==
+big-integer@1.6.x:
+ version "1.6.52"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85"
+ integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==
+
big-integer@^1.6.44:
version "1.6.51"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
@@ -2437,6 +2550,20 @@ bl@^4.1.0:
inherits "^2.0.4"
readable-stream "^3.4.0"
+bplist-creator@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/bplist-creator/-/bplist-creator-0.1.0.tgz#018a2d1b587f769e379ef5519103730f8963ba1e"
+ integrity sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==
+ dependencies:
+ stream-buffers "2.2.x"
+
+bplist-parser@0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.3.1.tgz#e1c90b2ca2a9f9474cc72f6862bbf3fee8341fd1"
+ integrity sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==
+ dependencies:
+ big-integer "1.6.x"
+
bplist-parser@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e"
@@ -2543,6 +2670,14 @@ cacheable-request@^7.0.2:
normalize-url "^6.0.1"
responselike "^2.0.0"
+call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
+ integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
+ dependencies:
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+
call-bind@^1.0.0, call-bind@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
@@ -2590,7 +2725,7 @@ caniuse-lite@^1.0.30001517:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601"
integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==
-chalk@^2.0.0, chalk@^2.3.0:
+chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -2912,6 +3047,13 @@ debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
dependencies:
ms "2.1.2"
+debug@^4.3.1:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
+ integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
+ dependencies:
+ ms "^2.1.3"
+
decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@@ -3052,6 +3194,15 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
+dunder-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
+ integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
+ dependencies:
+ call-bind-apply-helpers "^1.0.1"
+ es-errors "^1.3.0"
+ gopd "^1.2.0"
+
ecdsa-sig-formatter@1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
@@ -3163,6 +3314,23 @@ es-abstract@^1.19.0, es-abstract@^1.20.4:
unbox-primitive "^1.0.2"
which-typed-array "^1.1.10"
+es-define-property@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
+ integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
+
+es-errors@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+ integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
+
+es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
+ integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
+ dependencies:
+ es-errors "^1.3.0"
+
es-set-tostringtag@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8"
@@ -3172,6 +3340,16 @@ es-set-tostringtag@^2.0.1:
has "^1.0.3"
has-tostringtag "^1.0.0"
+es-set-tostringtag@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d"
+ integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==
+ dependencies:
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.6"
+ has-tostringtag "^1.0.2"
+ hasown "^2.0.2"
+
es-shim-unscopables@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241"
@@ -3616,7 +3794,7 @@ find-up@^4.0.0, find-up@^4.1.0:
locate-path "^5.0.0"
path-exists "^4.0.0"
-find-up@^5.0.0:
+find-up@^5.0.0, find-up@~5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
@@ -3652,10 +3830,10 @@ flow-parser@^0.206.0:
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.206.0.tgz#f4f794f8026535278393308e01ea72f31000bfef"
integrity sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==
-follow-redirects@^1.15.0:
- version "1.15.6"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
- integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
+follow-redirects@^1.15.6:
+ version "1.15.11"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340"
+ integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==
for-each@^0.3.3:
version "0.3.3"
@@ -3682,6 +3860,17 @@ form-data@^4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
+form-data@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4"
+ integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ es-set-tostringtag "^2.1.0"
+ hasown "^2.0.2"
+ mime-types "^2.1.12"
+
fresh@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@@ -3716,6 +3905,11 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
function.prototype.name@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
@@ -3751,11 +3945,35 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@
has-proto "^1.0.1"
has-symbols "^1.0.3"
+get-intrinsic@^1.2.6:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
+ integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
+ dependencies:
+ call-bind-apply-helpers "^1.0.2"
+ es-define-property "^1.0.1"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.1.1"
+ function-bind "^1.1.2"
+ get-proto "^1.0.1"
+ gopd "^1.2.0"
+ has-symbols "^1.1.0"
+ hasown "^2.0.2"
+ math-intrinsics "^1.1.0"
+
get-package-type@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+get-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
+ integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
+ dependencies:
+ dunder-proto "^1.0.1"
+ es-object-atoms "^1.0.0"
+
get-stdin@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
@@ -3781,6 +3999,11 @@ get-symbol-description@^1.0.0:
call-bind "^1.0.2"
get-intrinsic "^1.1.1"
+getenv@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/getenv/-/getenv-1.0.0.tgz#874f2e7544fbca53c7a4738f37de8605c3fcfc31"
+ integrity sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==
+
git-config-path@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/git-config-path/-/git-config-path-1.0.1.tgz#6d33f7ed63db0d0e118131503bab3aca47d54664"
@@ -3804,6 +4027,18 @@ glob-parent@^6.0.2:
dependencies:
is-glob "^4.0.3"
+glob@7.1.6:
+ version "7.1.6"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+ integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
glob@^7.1.3, glob@^7.1.4:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
@@ -3865,6 +4100,11 @@ gopd@^1.0.1:
dependencies:
get-intrinsic "^1.1.3"
+gopd@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
+ integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
+
got@^11.1.4:
version "11.8.6"
resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
@@ -3936,6 +4176,11 @@ has-symbols@^1.0.2, has-symbols@^1.0.3:
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+has-symbols@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
+ integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
+
has-tostringtag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
@@ -3943,6 +4188,13 @@ has-tostringtag@^1.0.0:
dependencies:
has-symbols "^1.0.2"
+has-tostringtag@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
+ integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
+ dependencies:
+ has-symbols "^1.0.3"
+
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
@@ -3950,6 +4202,13 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
+hasown@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+ integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
+ dependencies:
+ function-bind "^1.1.2"
+
hermes-estree@0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.12.0.tgz#8a289f9aee854854422345e6995a48613bac2ca8"
@@ -5190,6 +5449,11 @@ makeerror@1.0.12:
dependencies:
tmpl "1.0.5"
+math-intrinsics@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
+ integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
+
memfs-or-file-map-to-github-branch@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.2.1.tgz#fdb9a85408262316a9bd5567409bf89be7d72f96"
@@ -5609,7 +5873,7 @@ ms@2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-ms@2.1.3, ms@^2.1.1:
+ms@2.1.3, ms@^2.1.1, ms@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@@ -6076,6 +6340,15 @@ pkg-dir@^4.2.0:
dependencies:
find-up "^4.0.0"
+plist@^3.0.5:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9"
+ integrity sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==
+ dependencies:
+ "@xmldom/xmldom" "^0.8.8"
+ base64-js "^1.5.1"
+ xmlbuilder "^15.1.1"
+
pod-install@^0.1.38:
version "0.1.38"
resolved "https://registry.yarnpkg.com/pod-install/-/pod-install-0.1.38.tgz#1c16a800a5fc1abea0cafcc0e190f376368c76ab"
@@ -6608,6 +6881,11 @@ safe-regex-test@^1.0.0:
get-intrinsic "^1.1.3"
is-regex "^1.1.4"
+sax@>=0.6.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
+ integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
+
scheduler@0.24.0-canary-efb381bbf-20230505:
version "0.24.0-canary-efb381bbf-20230505"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz#5dddc60e29f91cd7f8b983d7ce4a99c2202d178f"
@@ -6721,6 +6999,15 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+simple-plist@^1.1.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/simple-plist/-/simple-plist-1.3.1.tgz#16e1d8f62c6c9b691b8383127663d834112fb017"
+ integrity sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==
+ dependencies:
+ bplist-creator "0.1.0"
+ bplist-parser "0.3.1"
+ plist "^3.0.5"
+
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
@@ -6745,6 +7032,11 @@ slice-ansi@^2.0.0:
astral-regex "^1.0.0"
is-fullwidth-code-point "^2.0.0"
+slugify@^1.6.6:
+ version "1.6.6"
+ resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.6.tgz#2d4ac0eacb47add6af9e04d3be79319cbcc7924b"
+ integrity sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==
+
source-map-support@0.5.13:
version "0.5.13"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
@@ -6838,6 +7130,11 @@ statuses@~1.5.0:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
+stream-buffers@2.2.x:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
+ integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==
+
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
@@ -7297,6 +7594,11 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+uuid@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
+ integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
+
v8-to-istanbul@^9.0.1:
version "9.1.0"
resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265"
@@ -7444,11 +7746,42 @@ xcase@^2.0.1:
resolved "https://registry.yarnpkg.com/xcase/-/xcase-2.0.1.tgz#c7fa72caa0f440db78fd5673432038ac984450b9"
integrity sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw==
+xcode@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/xcode/-/xcode-3.0.1.tgz#3efb62aac641ab2c702458f9a0302696146aa53c"
+ integrity sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==
+ dependencies:
+ simple-plist "^1.1.0"
+ uuid "^7.0.3"
+
xhr2@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.2.1.tgz#4e73adc4f9cfec9cbd2157f73efdce3a5f108a93"
integrity sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw==
+xml2js@0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.0.tgz#07afc447a97d2bd6507a1f76eeadddb09f7a8282"
+ integrity sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==
+ dependencies:
+ sax ">=0.6.0"
+ xmlbuilder "~11.0.0"
+
+xmlbuilder@^14.0.0:
+ version "14.0.0"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-14.0.0.tgz#876b5aec4f05ffd5feb97b0a871c855d16fbeb8c"
+ integrity sha512-ts+B2rSe4fIckR6iquDjsKbQFK2NlUk6iG5nf14mDEyldgoc2nEKZ3jZWMPTxGQwVgToSjt6VGIho1H8/fNFTg==
+
+xmlbuilder@^15.1.1:
+ version "15.1.1"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
+ integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==
+
+xmlbuilder@~11.0.0:
+ version "11.0.1"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
+ integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
+
xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"