UNPKG

instabug-reactnative

Version:

React Native plugin for integrating the Instabug SDK

937 lines (844 loc) 30 kB
import { AppState, type AppStateStatus, findNodeHandle, Platform } from 'react-native'; import type { NavigationContainerRefWithCurrent, NavigationState as NavigationStateV5, } from '@react-navigation/native'; import type { ComponentDidAppearEvent } from 'react-native-navigation'; import type { NavigationAction, NavigationState as NavigationStateV4 } from 'react-navigation'; import type { InstabugConfig } from '../models/InstabugConfig'; import Report from '../models/Report'; import { emitter, NativeEvents, NativeInstabug } from '../native/NativeInstabug'; import { registerFeatureFlagsListener } from '../utils/FeatureFlags'; import { AutoMaskingType, ColorTheme, Locale, LogLevel, NetworkInterceptionMode, ReproStepsMode, StringKey, WelcomeMessageMode, } from '../utils/Enums'; import InstabugUtils, { checkNetworkRequestHandlers, resetNativeObfuscationListener, setApmNetworkFlagsIfChanged, stringifyIfNotString, } from '../utils/InstabugUtils'; import * as NetworkLogger from './NetworkLogger'; import { captureUnhandledRejections } from '../utils/UnhandledRejectionTracking'; import type { ReproConfig } from '../models/ReproConfig'; import type { FeatureFlag } from '../models/FeatureFlag'; import { addAppStateListener } from '../utils/AppStatesHandler'; 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; let _isFirstScreen = false; const firstScreen = 'Initial Screen'; let _currentAppState = AppState.currentState; let isNativeInterceptionFeatureEnabled = false; // Checks the value of "cp_native_interception_enabled" backend flag. let hasAPMNetworkPlugin = false; // Android only: checks if the APM plugin is installed. let shouldEnableNativeInterception = false; // For Android: used to disable APM logging inside reportNetworkLog() -> NativeAPM.networkLogAndroid(), For iOS: used to control native interception (true == enabled , false == disabled) /** * Enables or disables Instabug functionality. * @param isEnabled A boolean to enable/disable Instabug. */ export const setEnabled = (isEnabled: boolean) => { NativeInstabug.setEnabled(isEnabled); }; /** * Reports that the screen name been changed (Current View field on dashboard). * only for android. * * Normally reportScreenChange handles taking a screenshot for reproduction * steps and the Current View field on the dashboard. But we've faced issues * in android where we needed to separate them, that's why we only call it * for android. * * @param screenName string containing the screen name */ function reportCurrentViewForAndroid(screenName: string | null) { if (Platform.OS === 'android' && screenName != null) { NativeInstabug.reportCurrentViewChange(screenName); } } /** * Initializes the SDK. * This is the main SDK method that does all the magic. This is the only * method that SHOULD be called. * Should be called in constructor of the AppRegistry component * @param config SDK configurations. See {@link InstabugConfig} for more info. */ export const init = (config: InstabugConfig) => { if (Platform.OS === 'android') { // Add android feature flags listener for android registerFeatureFlagsListener(); addOnFeatureUpdatedListener(config); } else { isNativeInterceptionFeatureEnabled = NativeNetworkLogger.isNativeInterceptionEnabled(); // Add app state listener to handle background/foreground transitions addAppStateListener(async (nextAppState) => handleAppStateChange(nextAppState, config)); handleNetworkInterceptionMode(config); //Set APM networking flags for the first time setApmNetworkFlagsIfChanged({ isNativeInterceptionFeatureEnabled: isNativeInterceptionFeatureEnabled, hasAPMNetworkPlugin: hasAPMNetworkPlugin, shouldEnableNativeInterception: shouldEnableNativeInterception, }); } // call Instabug native init method initializeNativeInstabug(config); // Set up error capturing and rejection handling InstabugUtils.captureJsErrors(); captureUnhandledRejections(); _isFirstScreen = true; _currentScreen = firstScreen; InstabugRNConfig.debugLogsLevel = config.debugLogsLevel ?? LogLevel.error; reportCurrentViewForAndroid(firstScreen); setTimeout(() => { if (_currentScreen === firstScreen) { NativeInstabug.reportScreenChange(firstScreen); _currentScreen = null; } }, 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. */ const handleAppStateChange = async (nextAppState: AppStateStatus, config: InstabugConfig) => { // Checks if the app has come to the foreground if (['inactive', 'background'].includes(_currentAppState) && nextAppState === 'active') { const isUpdated = await fetchApmNetworkFlags(); if (isUpdated) { refreshAPMNetworkConfigs(config); } } _currentAppState = nextAppState; }; /** * Fetches the current APM network flags. */ const fetchApmNetworkFlags = async () => { let isUpdated = false; const newNativeInterceptionFeatureEnabled = NativeNetworkLogger.isNativeInterceptionEnabled(); if (isNativeInterceptionFeatureEnabled !== newNativeInterceptionFeatureEnabled) { isNativeInterceptionFeatureEnabled = newNativeInterceptionFeatureEnabled; isUpdated = true; } if (Platform.OS === 'android') { const newHasAPMNetworkPlugin = await NativeNetworkLogger.hasAPMNetworkPlugin(); if (hasAPMNetworkPlugin !== newHasAPMNetworkPlugin) { hasAPMNetworkPlugin = newHasAPMNetworkPlugin; isUpdated = true; } } return isUpdated; }; /** * Handles platform-specific checks and updates the network interception mode. */ const handleNetworkInterceptionMode = (config: InstabugConfig) => { // Default networkInterceptionMode to JavaScript if not set if (config.networkInterceptionMode == null) { config.networkInterceptionMode = NetworkInterceptionMode.javascript; } if (Platform.OS === 'android') { handleInterceptionModeForAndroid(config); config.networkInterceptionMode = NetworkInterceptionMode.javascript; // Need to enable JS interceptor in all scenarios for Bugs & Crashes network logs } else if (Platform.OS === 'ios') { handleInterceptionModeForIOS(config); //enable | disable native obfuscation and filtering synchronously NetworkLogger.setNativeInterceptionEnabled(shouldEnableNativeInterception); } if (config.networkInterceptionMode === NetworkInterceptionMode.javascript) { NetworkLogger.setEnabled(true); } }; /** * Handles the network interception logic for Android if the user set * network interception mode with [NetworkInterceptionMode.javascript]. */ function handleAndroidJSInterception() { if (isNativeInterceptionFeatureEnabled && hasAPMNetworkPlugin) { shouldEnableNativeInterception = true; Logger.warn( InstabugConstants.IBG_APM_TAG + InstabugConstants.SWITCHED_TO_NATIVE_INTERCEPTION_MESSAGE, ); } } /** * Handles the network interception logic for Android if the user set * network interception mode with [NetworkInterceptionMode.native]. */ function handleAndroidNativeInterception() { if (isNativeInterceptionFeatureEnabled) { shouldEnableNativeInterception = hasAPMNetworkPlugin; if (!hasAPMNetworkPlugin) { Logger.error(InstabugConstants.IBG_APM_TAG + InstabugConstants.PLUGIN_NOT_INSTALLED_MESSAGE); } } else { shouldEnableNativeInterception = false; // rollback to use JS interceptor for APM & Core. Logger.error( InstabugConstants.IBG_APM_TAG + InstabugConstants.NATIVE_INTERCEPTION_DISABLED_MESSAGE, ); } } /** * Control either to enable or disable the native interception for iOS after the init method is called. */ function handleIOSNativeInterception(config: InstabugConfig) { if ( shouldEnableNativeInterception && config.networkInterceptionMode === NetworkInterceptionMode.native ) { NativeNetworkLogger.forceStartNetworkLoggingIOS(); // Enable native iOS automatic network logging. } else { NativeNetworkLogger.forceStopNetworkLoggingIOS(); // Disable native iOS automatic network logging. } } /** * Handles the network interception mode logic for Android. * By deciding which interception mode should be enabled (Native or JavaScript). */ const handleInterceptionModeForAndroid = (config: InstabugConfig) => { const { networkInterceptionMode } = config; if (networkInterceptionMode === NetworkInterceptionMode.javascript) { handleAndroidJSInterception(); } else { handleAndroidNativeInterception(); } }; /** * Handles the interception mode logic for iOS. * By deciding which interception mode should be enabled (Native or JavaScript). */ const handleInterceptionModeForIOS = (config: InstabugConfig) => { if (config.networkInterceptionMode === NetworkInterceptionMode.native) { if (isNativeInterceptionFeatureEnabled) { shouldEnableNativeInterception = true; NetworkLogger.setEnabled(false); // insure JS interceptor is disabled } else { shouldEnableNativeInterception = false; NetworkLogger.setEnabled(true); // rollback to JS interceptor Logger.error( InstabugConstants.IBG_APM_TAG + InstabugConstants.NATIVE_INTERCEPTION_DISABLED_MESSAGE, ); } } }; /** * Initializes Instabug with the given configuration. */ const initializeNativeInstabug = (config: InstabugConfig) => { NativeInstabug.init( config.token, config.invocationEvents, config.debugLogsLevel ?? LogLevel.error, shouldEnableNativeInterception && config.networkInterceptionMode === NetworkInterceptionMode.native, config.codePushVersion, config.appVariant, config.ignoreAndroidSecureFlag != null ? { ignoreAndroidSecureFlag: config.ignoreAndroidSecureFlag, } : undefined, config.overAirVersion, ); }; /** * Refresh the APM network configurations. */ function refreshAPMNetworkConfigs(config: InstabugConfig, forceRefreshIOS: boolean = true) { handleNetworkInterceptionMode(config); if (Platform.OS === 'ios' && forceRefreshIOS) { handleIOSNativeInterception(config); } setApmNetworkFlagsIfChanged({ isNativeInterceptionFeatureEnabled, hasAPMNetworkPlugin, shouldEnableNativeInterception, }); if (shouldEnableNativeInterception) { checkNetworkRequestHandlers(); } else { // remove any attached [NativeNetworkLogger] Listeners if exists, to avoid memory leaks. resetNativeObfuscationListener(); } } /** * Add Android Listener for native feature flags changes. */ function addOnFeatureUpdatedListener(config: InstabugConfig) { emitter.addListener(NativeEvents.IBG_ON_FEATURES_UPDATED_CALLBACK, (flags) => { const { cpNativeInterceptionEnabled, hasAPMPlugin } = flags; isNativeInterceptionFeatureEnabled = cpNativeInterceptionEnabled; hasAPMNetworkPlugin = hasAPMPlugin; shouldEnableNativeInterception = config.networkInterceptionMode === NetworkInterceptionMode.native; refreshAPMNetworkConfigs(config); }); NativeInstabug.setOnFeaturesUpdatedListener(); } /** * 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. * Maximum size of the string is 1,000 characters. * @param data A string to be attached to each report, with a maximum size of 1,000 characters. */ export const setUserData = (data: string) => { NativeInstabug.setUserData(data); }; /** * Sets whether the SDK is tracking user steps or not. * Enabling user steps would give you an insight on the scenario a user has * performed before encountering a bug or a crash. User steps are attached * with each report being sent. * @param isEnabled A boolean to set user steps tracking to being enabled or disabled. */ export const setTrackUserSteps = (isEnabled: boolean) => { if (Platform.OS === 'ios') { NativeInstabug.setTrackUserSteps(isEnabled); } }; /** * Sets whether IBGLog should also print to Xcode's console log or not. * @param printsToConsole A boolean to set whether printing to * Xcode's console is enabled or not. */ export const setIBGLogPrintsToConsole = (printsToConsole: boolean) => { if (Platform.OS === 'ios') { NativeInstabug.setIBGLogPrintsToConsole(printsToConsole); } }; /** * The session profiler is enabled by default and it attaches to the bug and * crash reports the following information during the last 60 seconds before the report is sent. * @param isEnabled A boolean parameter to enable or disable the feature. */ export const setSessionProfilerEnabled = (isEnabled: boolean) => { NativeInstabug.setSessionProfilerEnabled(isEnabled); }; /** * Sets the SDK's locale. * Use to change the SDK's UI to different language. * Defaults to the device's current locale. * @param sdkLocale A locale to set the SDK to. */ export const setLocale = (sdkLocale: Locale) => { NativeInstabug.setLocale(sdkLocale); }; /** * Sets the color theme of the SDK's whole UI. * @param sdkTheme */ export const setColorTheme = (sdkTheme: ColorTheme) => { NativeInstabug.setColorTheme(sdkTheme); }; /** * Sets the primary color of the SDK's UI. * Sets the color of UI elements indicating interactivity or call to action. * 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.setTheme({ primaryColor: color }); }; /** * Appends a set of tags to previously added tags of reported feedback, * bug or crash. * @param tags An array of tags to append to current tags. */ export const appendTags = (tags: string[]) => { NativeInstabug.appendTags(tags); }; /** * Manually removes all tags of reported feedback, bug or crash. */ export const resetTags = () => { NativeInstabug.resetTags(); }; /** * Gets all tags of reported feedback, bug or crash. */ export const getTags = async (): Promise<string[] | null> => { const tags = await NativeInstabug.getTags(); return tags; }; /** * Overrides any of the strings shown in the SDK with custom ones. * Allows you to customize any of the strings shown to users in the SDK. * @param key Key of string to override. * @param string String value to override the default one. */ export const setString = (key: StringKey, string: string) => { // Suffix the repro steps list item numbering title with a # to unify the string key's // behavior between Android and iOS if (Platform.OS === 'android' && key === StringKey.reproStepsListItemNumberingTitle) { string = `${string} #`; } NativeInstabug.setString(string, key); }; /** * Sets the default value of the user's email and ID and hides the email field from the reporting UI * and set the user's name to be included with all reports. * It also reset the chats on device to that email and removes user attributes, * user data and completed surveys. * @param email Email address to be set as the user's email. * @param name Name of the user to be set. * @param [id] ID of the user to be set. */ export const identifyUser = (email: string, name: string, id?: string) => { NativeInstabug.identifyUser(email, name, id); }; /** * Sets the default value of the user's email to nil and show email field and remove user name * from all reports * It also reset the chats on device and removes user attributes, user data and completed surveys. */ export const logOut = () => { NativeInstabug.logOut(); }; /** * Logs a user event that happens through the lifecycle of the application. * Logged user events are going to be sent with each report, as well as at the end of a session. * @param name Event name. */ export const logUserEvent = (name: string) => { NativeInstabug.logUserEvent(name); }; /** * Appends a log message to Instabug internal log. * These logs are then sent along the next uploaded report. * All log messages are timestamped. * Logs aren't cleared per single application run. * If you wish to reset the logs, use {@link clearLogs()} * Note: logs passed to this method are **NOT** printed to Logcat. * * @param message the message */ export const logVerbose = (message: string) => { if (!message) { return; } message = stringifyIfNotString(message); NativeInstabug.logVerbose(message); }; /** * Appends a log message to Instabug internal log. * These logs are then sent along the next uploaded report. * All log messages are timestamped. * Logs aren't cleared per single application run. * If you wish to reset the logs, use {@link clearLogs()} * Note: logs passed to this method are **NOT** printed to Logcat. * * @param message the message */ export const logInfo = (message: string) => { if (!message) { return; } message = stringifyIfNotString(message); NativeInstabug.logInfo(message); }; /** * Appends a log message to Instabug internal log. * These logs are then sent along the next uploaded report. * All log messages are timestamped. * Logs aren't cleared per single application run. * If you wish to reset the logs, use {@link clearLogs()} * Note: logs passed to this method are **NOT** printed to Logcat. * * @param message the message */ export const logDebug = (message: string) => { if (!message) { return; } message = stringifyIfNotString(message); NativeInstabug.logDebug(message); }; /** * Appends a log message to Instabug internal log. * These logs are then sent along the next uploaded report. * All log messages are timestamped. * Logs aren't cleared per single application run. * If you wish to reset the logs, use {@link clearLogs()} * Note: logs passed to this method are **NOT** printed to Logcat. * * @param message the message */ export const logError = (message: string) => { if (!message) { return; } message = stringifyIfNotString(message); NativeInstabug.logError(message); }; /** * Appends a log message to Instabug internal log. * These logs are then sent along the next uploaded report. * All log messages are timestamped. * Logs aren't cleared per single application run. * If you wish to reset the logs, use {@link clearLogs()} * Note: logs passed to this method are **NOT** printed to Logcat. * * @param message the message */ export const logWarn = (message: string) => { if (!message) { return; } message = stringifyIfNotString(message); NativeInstabug.logWarn(message); }; /** * Clear all Instabug logs, console logs, network logs and user steps. */ export const clearLogs = () => { NativeInstabug.clearLogs(); }; /** * Sets the repro steps mode for bugs and crashes. * * @param config The repro steps config. * * @example * ```js * Instabug.setReproStepsConfig({ * bug: ReproStepsMode.enabled, * crash: ReproStepsMode.disabled, * sessionReplay: ReproStepsMode.enabled, * }); * ``` */ export const setReproStepsConfig = (config: ReproConfig) => { let bug = config.bug ?? ReproStepsMode.enabled; let crash = config.crash ?? ReproStepsMode.enabledWithNoScreenshots; let sessionReplay = config.sessionReplay ?? ReproStepsMode.enabled; if (config.all != null) { bug = config.all; crash = config.all; sessionReplay = config.all; } NativeInstabug.setReproStepsConfig(bug, crash, sessionReplay); }; /** * Sets user attribute to overwrite it's value or create a new one if it doesn't exist. * * @param key the attribute * @param value the value */ export const setUserAttribute = (key: string, value: string) => { if (!key || typeof key !== 'string' || typeof value !== 'string') { Logger.error(InstabugConstants.SET_USER_ATTRIBUTES_ERROR_TYPE_MESSAGE); return; } NativeInstabug.setUserAttribute(key, value); }; /** * Returns the user attribute associated with a given key. * @param key The attribute key as string */ export const getUserAttribute = async (key: string): Promise<string | null> => { const attribute = await NativeInstabug.getUserAttribute(key); return attribute; }; /** * Removes user attribute if exists. * * @param key the attribute key as string * @see {@link setUserAttribute} */ export const removeUserAttribute = (key: string) => { if (!key || typeof key !== 'string') { Logger.error(InstabugConstants.REMOVE_USER_ATTRIBUTES_ERROR_TYPE_MESSAGE); return; } NativeInstabug.removeUserAttribute(key); }; /** * Returns all user attributes. * set user attributes, or an empty dictionary if no user attributes have been set. */ export const getAllUserAttributes = async (): Promise<Record<string, string>> => { const attributes = await NativeInstabug.getAllUserAttributes(); return attributes; }; /** * Clears all user attributes if exists. */ export const clearAllUserAttributes = () => { NativeInstabug.clearAllUserAttributes(); }; /** * Shows the welcome message in a specific mode. * @param mode An enum to set the welcome message mode to live, or beta. */ export const showWelcomeMessage = (mode: WelcomeMessageMode) => { NativeInstabug.showWelcomeMessageWithMode(mode); }; /** * Sets the welcome message mode to live, beta or disabled. * @param mode An enum to set the welcome message mode to live, beta or disabled. */ export const setWelcomeMessageMode = (mode: WelcomeMessageMode) => { NativeInstabug.setWelcomeMessageMode(mode); }; /** * Add file to be attached to the bug report. * @param filePath * @param fileName */ export const addFileAttachment = (filePath: string, fileName: string) => { if (Platform.OS === 'android') { NativeInstabug.setFileAttachment(filePath, fileName); } else { NativeInstabug.setFileAttachment(filePath); } }; /** * Hides component from screenshots, screen recordings and view hierarchy. * @param viewRef the ref of the component to hide */ export const addPrivateView = (viewRef: number | React.Component | React.ComponentClass) => { const nativeTag = findNodeHandle(viewRef); NativeInstabug.addPrivateView(nativeTag); }; /** * Removes component from the set of hidden views. The component will show again in * screenshots, screen recordings and view hierarchy. * @param viewRef the ref of the component to remove from hidden views */ export const removePrivateView = (viewRef: number | React.Component | React.ComponentClass) => { const nativeTag = findNodeHandle(viewRef); NativeInstabug.removePrivateView(nativeTag); }; /** * Shows default Instabug prompt. */ export const show = () => { NativeInstabug.show(); }; export const onReportSubmitHandler = (handler?: (report: Report) => void) => { emitter.addListener(NativeEvents.PRESENDING_HANDLER, (report) => { const { tags, consoleLogs, instabugLogs, userAttributes, fileAttachments } = report; const reportObj = new Report(tags, consoleLogs, instabugLogs, userAttributes, fileAttachments); handler && handler(reportObj); }); NativeInstabug.setPreSendingHandler(handler); }; export const onNavigationStateChange = ( prevState: NavigationStateV4, currentState: NavigationStateV4, _action: NavigationAction, ) => { const currentScreen = InstabugUtils.getActiveRouteName(currentState); const prevScreen = InstabugUtils.getActiveRouteName(prevState); if (prevScreen !== currentScreen) { reportCurrentViewForAndroid(currentScreen); if (_currentScreen != null && _currentScreen !== firstScreen) { NativeInstabug.reportScreenChange(_currentScreen); _currentScreen = null; } _currentScreen = currentScreen; setTimeout(() => { if (currentScreen && _currentScreen === currentScreen) { NativeInstabug.reportScreenChange(currentScreen); _currentScreen = null; } }, 1000); } }; export const onStateChange = (state?: NavigationStateV5) => { if (!state) { return; } const currentScreen = InstabugUtils.getFullRoute(state); reportCurrentViewForAndroid(currentScreen); if (_currentScreen !== null && _currentScreen !== firstScreen) { NativeInstabug.reportScreenChange(_currentScreen); _currentScreen = null; } _currentScreen = currentScreen; setTimeout(() => { if (_currentScreen === currentScreen) { NativeInstabug.reportScreenChange(currentScreen); _currentScreen = null; } }, 1000); }; /** * Sets a listener for screen change * @param navigationRef a refrence of a navigation container * */ export const setNavigationListener = ( navigationRef: NavigationContainerRefWithCurrent<ReactNavigation.RootParamList>, ) => { return navigationRef.addListener('state', () => { onStateChange(navigationRef.getRootState()); }); }; export const reportScreenChange = (screenName: string) => { NativeInstabug.reportScreenChange(screenName); }; /** * Add feature flags to the next report. * @param featureFlags An array of feature flags to add to the next report. */ export const addFeatureFlags = (featureFlags: FeatureFlag[]) => { const entries = featureFlags.map((item) => [item.name, item.variant || '']); const flags = Object.fromEntries(entries); NativeInstabug.addFeatureFlags(flags); }; /** * Add a feature flag to the to next report. */ export const addFeatureFlag = (featureFlag: FeatureFlag) => { addFeatureFlags([featureFlag]); }; /** * Remove feature flags from the next report. * @param featureFlags An array of feature flags to remove from the next report. */ export const removeFeatureFlags = (featureFlags: string[]) => { NativeInstabug.removeFeatureFlags(featureFlags); }; /** * Remove a feature flag from the next report. * @param name the name of the feature flag to remove from the next report. */ export const removeFeatureFlag = (name: string) => { removeFeatureFlags([name]); }; /** * Clear all feature flags */ export const removeAllFeatureFlags = () => { NativeInstabug.removeAllFeatureFlags(); }; /** * This API has to be call when using custom app rating prompt */ export const willRedirectToStore = () => { NativeInstabug.willRedirectToStore(); }; /** * This API has be called when changing the default Metro server port (8081) to exclude the DEV URL from network logging. */ export const setMetroDevServerPort = (port: number) => { InstabugRNConfig.metroDevServerPort = port.toString(); }; export const componentDidAppearListener = (event: ComponentDidAppearEvent) => { if (_isFirstScreen) { _lastScreen = event.componentName; _isFirstScreen = false; return; } if (_lastScreen !== event.componentName) { NativeInstabug.reportScreenChange(event.componentName); _lastScreen = event.componentName; } }; /** * Sets listener to feature flag changes * @param handler A callback that gets the update value of the flag */ export const _registerFeatureFlagsChangeListener = ( handler: (payload: { isW3ExternalTraceIDEnabled: boolean; isW3ExternalGeneratedHeaderEnabled: boolean; isW3CaughtHeaderEnabled: boolean; networkBodyLimit: number; }) => void, ) => { emitter.addListener(NativeEvents.ON_FEATURE_FLAGS_CHANGE, (payload) => { handler(payload); }); NativeInstabug.registerFeatureFlagsChangeListener(); }; /** * Sets the auto mask screenshots types. * @param autoMaskingTypes The masking type to be applied. */ 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); } };