The BugSnag Performance SDK for React Native can either process and deliver spans on its own or it can be “attached” to the native Android and iOS SDKs for enhanced functionality if you are interested in how the native part of your app behaves.
With the native integration configured, you can:
With the BugSnag React Native Performance SDK already installed, follow the native integration guides to add performance monitoring to your Android and iOS projects:
| SDK | Minimum version | Docs |
|---|---|---|
bugsnag-android-performance |
v1.11.0 | Integration guide » |
bugsnag-cocoa-performance |
v1.11.1 | Integration guide » |
Next, install the @bugsnag/plugin-react-native-span-access package:
yarn add @bugsnag/plugin-react-native-span-access
# or
npm install --save @bugsnag/plugin-react-native-span-access
Add the following dependencies to your Module Gradle Settings, usually found at <project_dir>/android/app/build.gradle or build.gradle.kts:
dependencies {
// ...
implementation project(':bugsnag_plugin-react-native-span-access')
}
dependencies {
// ...
implementation(project(":bugsnag_plugin-react-native-span-access"))
}
run pod install in your iOS project directory to ensure the plugin is linked correctly:
npx pod-install
To use the native integration, the BugSnag React Native Performance SDK is “attached” to the native SDK, reading its configuration from the native layer.
In index.js, import and attach the BugSnag performance client as follows, replacing the existing call to start (if present):
import BugsnagPerformance from '@bugsnag/react-native-performance'
BugsnagPerformance.attach()
Configuration options that are common to the React Native and native SDKs should be set in native code and will be picked up by the React Native SDK when you call attach. Any configuration that only applies to @bugsnag/react-native-performance can be passed to the attach method:
BugsnagPerformance.attach({
codeBundleId: '12345',
})
Use the Configuration options page to see which options are available to the attach method.
To assist in tracking custom spans which you wish to reference on both the native and JavaScript layers of your React Native app, you can use the BugsnagNativeSpansPlugin and BugsnagJavascriptSpansPlugin plugins to allow each SDK to access spans created by the other.
See the named span access guide for detailed setup and usage instructions.
For improved cross-layer performance monitoring, you can configure React Native app starts to be children of native view loads using the BugsnagReactNativeAppStartPlugin. This allows developers to see a full breakdown of the time taken to load a React Native view from the native layer through to the JavaScript component being rendered.
For full React Native apps, this means the app start time will be included in the native app start span. For hybrid/brownfield apps, this means the React Native initialization time will be included in each native view load span.
Add the BugsnagReactNativeAppStartPlugin to your native Android and iOS setup code:
import com.bugsnag.reactnative.performance.nativespans.BugsnagReactNativeAppStartPlugin;
PerformanceConfiguration config = PerformanceConfiguration.load(this);
config.addPlugin(new BugsnagReactNativeAppStartPlugin());
BugsnagPerformance.start(config);
import com.bugsnag.reactnative.performance.nativespans.BugsnagReactNativeAppStartPlugin
val config = PerformanceConfiguration.load(this);
config.addPlugin(new BugsnagReactNativeAppStartPlugin());
BugsnagPerformance.start(config);
#import "BugsnagReactNativeAppStartPlugin.h"
BugsnagReactNativePerformanceConfiguration *config =
[BugsnagReactNativePerformanceConfiguration loadConfig];
[config addPlugin:[[BugsnagReactNativeAppStartPlugin new]]];
[BugsnagReactNativePerformance startWithConfiguration:config];
import BugsnagNativeSpans
let config = BugsnagReactNativePerformanceConfiguration.loadConfig()
config.addPlugin(BugsnagReactNativeAppStartPlugin())
BugsnagReactNativePerformance.start(configuration: config)
By default, the root view in a React Native iOS app is created in a way that is incompatible with the native BugSnag view load instrumentation. To allow this to be instrumented, a custom view controller implementation is required.
This limitation only applies to regular React Native apps where the React Native screen is loaded immediately. Hybrid/brownfield apps that load the React Native view via a custom view controller are not affected.
First, create a custom view controller:
// ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (nonatomic, copy, nullable) UIView *(^viewFactory)();
@end
// ViewController.swift
import UIKit
class ViewController: UIViewController {
var viewFactory: (() -> UIView)?
override func loadView() {
if let viewFactory = viewFactory {
self.view = viewFactory()
}
}
}
If using Objective-C, you will also need to implement the view controller:
// ViewController.m
#import "ViewController.h"
@implementation ViewController
- (void)loadView {
if (self.viewFactory) {
self.view = self.viewFactory();
}
}
@end
Finally, update your AppDelegate to use this custom view controller for the React Native root view:
// AppDelegate.mm
- (UIViewController *)createRootViewController
{
return [ViewController new]; // Your custom view controller class
}
- (void)setRootView:(UIView *)rootView
toRootViewController:(UIViewController *)rootViewController
{
if ([rootViewController isKindOfClass:[ViewController class]]) {
((ViewController *)rootViewController).viewFactory = ^UIView *{
return rootView;
};
} else {
[super setRootView:rootView toRootViewController:rootViewController];
}
}
// AppDelegate.swift
override func createRootViewController() -> UIViewController {
return ViewController() // Your custom view controller class
}
override func setRootView(
_ rootView: UIView,
toRootViewController rootViewController: UIViewController
) {
if let viewController = rootViewController as? ViewController {
viewController.viewFactory = {
return rootView
}
} else {
super.setRootView(rootView, toRootViewController: rootViewController)
}
}