diff --git a/docs/getting-started.md b/docs/getting-started.md index fb5f54840..65357ed50 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -8,7 +8,7 @@ Flipper helps you debug Android and iOS apps running in an emulator/simulator or - The desktop app - The native mobile SDKs for Android and iOS -To use Flipper, you need to add the mobile SDK to your app. +To use Flipper, you need to add the mobile SDK to your app. If you are using React Native 0.62 or higher, this is largely done automatically for you. ## Setup @@ -335,398 +335,51 @@ class AppDelegate: UIResponder, UIApplicationDelegate { -## Ready for takeoff +## Enabling plugins on Android / iOS Finally, you need to add plugins to your Flipper client. Above we have only added the Layout Inspector plugin to get you started. See [Network Plugin](setup/network-plugin.md) and [Layout Inspector Plugin](setup/layout-plugin.md) for information on how to add them, and also enable Litho or ComponentKit support. You can check the sample apps in the [GitHub repo](https://github.com/facebook/flipper) for examples of integrating other plugins. ## Setup your React Native app -_Inspired by [a blog post by Ram N](http://blog.nparashuram.com/2019/09/using-flipper-with-react-native.html)._ -
-This version of the tutorial is written against **React Native 0.61.5**. +This version of the tutorial is written against **React Native 0.62.0**. + +* [Flipper on RN < 0.61.5 tutorial](https://github.com/facebook/flipper/blob/da25241f7fbb06dffd913958559044d758c54fb8/docs/getting-started.md#setup-your-react-native-app) +* [Flipper on RN 0.61.5 - 0.62 tutorial](https://github.com/facebook/flipper/blob/4297b3061f14ceca4d184aa3eebd0731b5bf20f5/docs/getting-started.md#setup-your-react-native-app) -You can find versions of this guide for older versions of React Native [here](https://github.com/facebook/flipper/blob/da25241f7fbb06dffd913958559044d758c54fb8/docs/getting-started.md#setup-your-react-native-app).
-Integrating Flipper with React Native is a bit different than with a native app. +After generating your project with `npx react-native init`, the Flipper integration is setup out-of-the-box for debug builds: -### Android +* For Android, start the Flipper Desktop application, and start your project using `yarn android`. Your application should appear in Flipper. +* For iOS, run `pod install` once in the `ios` directory of your project. After that, run `yarn ios` and start Flipper. Your application should show up in Flipper. -First, add this line to your `android/gradle.properties`: +By default, the following plugins will be available: -```groovy -# On Android, React Native currently has issues with higher versions -FLIPPER_VERSION=0.23.4 -``` +* Layout Inspector +* Network +* Databases +* Images +* Shared Preferences +* Crash Reporter +* React DevTools +* Metro Logs -It's recommended that you add the following activity to your `AndroidManifest.xml`, which can help diagnose integration issues and other problems: +Additional plugins might be installed through NPM, please follow the instructions as provided by the plugin authors. -```xml - -``` +To create your own plugins and integrate with Flipper using JavaScript, check out our [writing plugins for React Native](tutorial/react-native) tutorial! -Flipper is distributed via JCenter. Add the dependencies to your `build.gradle` file. -You should also explicitly depend on [`soloader`](https://github.com/facebook/soloader) -instead of relying on transitive dependency resolution which is getting deprecated -with Gradle 5. +If you ever need to update the Flipper SDKs used in your project, the versions can be bumped in the `ios/Podfile` and `android/gradle.properties` files of your project.
-We provide a "no-op" implementation of some oft-used Flipper interfaces you can -use to make it easier to strip Flipper from your release builds. See instructions in [Setup your Android app](setup-your-android-app). - -
- -`android/app/build.gradle` - -```groovy -android { - packagingOptions { - ... - // This line is required to prevent a build failure due to duplicate libs - pickFirst "lib/armeabi-v7a/libc++_shared.so" - pickFirst "lib/arm64-v8a/libc++_shared.so" - pickFirst "lib/x86/libc++_shared.so" - pickFirst "lib/x86_64/libc++_shared.so" - } -} - -dependencies { - ... - implementation 'com.facebook.soloader:soloader:0.6.0+' - - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { - exclude group:'com.facebook.yoga' - exclude group:'com.facebook.flipper', module: 'fbjni' - exclude group:'com.facebook.litho', module: 'litho-annotations' - exclude group:'com.squareup.okhttp3' - } -} -``` - -Now, we create a new file: `android/app/src/debug/java/com/yourappname/ReactNativeFlipper.java`. (Replace the `yourappname` namespace with your app name) - -These are the suggested plugins integrations: - -- Layout Inspector -- Network -- Databases -- Images -- Shared Preferences -- Crash Reporter -- React devtools - -```java -package com.yourappname; // <--- use your own namespace, same as before! - -import android.content.Context; -import com.facebook.flipper.android.AndroidFlipperClient; -import com.facebook.flipper.android.utils.FlipperUtils; -import com.facebook.flipper.core.FlipperClient; -import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; -import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; -import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; -import com.facebook.flipper.plugins.inspector.DescriptorMapping; -import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; -import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; -import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; -import com.facebook.flipper.plugins.react.ReactFlipperPlugin; -import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.modules.network.NetworkingModule; -import okhttp3.OkHttpClient; - -public class ReactNativeFlipper { - - public static void initializeFlipper(Context context) { - ReactNativeFlipper.initializeFlipper(context, null); - } - - public static void initializeFlipper(Context context, final ReactInstanceManager reactInstanceManager) { - if (!FlipperUtils.shouldEnableFlipper(context)) { - return; - } - final FlipperClient client = AndroidFlipperClient.getInstance(context); - - client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); - client.addPlugin(new ReactFlipperPlugin()); - client.addPlugin(new DatabasesFlipperPlugin(context)); - client.addPlugin(new SharedPreferencesFlipperPlugin(context)); - client.addPlugin(CrashReporterPlugin.getInstance()); - - final NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); - NetworkingModule.setCustomClientBuilder( - new NetworkingModule.CustomClientBuilder() { - @Override - public void apply(OkHttpClient.Builder builder) { - builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); - } - }); - client.addPlugin(networkFlipperPlugin); - client.start(); - - // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized - // Hence we run if after all native modules have been initialized - ReactContext reactContext = reactInstanceManager == null ? null : reactInstanceManager.getCurrentReactContext(); - if (reactContext == null) { - reactInstanceManager.addReactInstanceEventListener( - new ReactInstanceManager.ReactInstanceEventListener() { - @Override - public void onReactContextInitialized(ReactContext reactContext) { - reactInstanceManager.removeReactInstanceEventListener(this); - reactContext.runOnNativeModulesQueueThread( - new Runnable() { - @Override - public void run() { - client.addPlugin(new FrescoFlipperPlugin()); - } - }); - } - }); - } else { - client.addPlugin(new FrescoFlipperPlugin()); - } - } -} -``` - -Now you can initialize Flipper in your Application's `onCreate` method, which involves -initializing SoLoader (for loading the C++ part of Flipper) and starting a `FlipperClient`. - -For this, we edit the `android/app/src/main/java/com/yourappname/MainApplication.java` file. - -```java -package com.yourappname;// <--- use your own namespace, same as before! - -import ... -import com.facebook.react.ReactInstanceManager; // <---- add this import - -public class MainApplication extends Application implements ReactApplication { - ... - - @Override - public void onCreate() { - super.onCreate(); - SoLoader.init(this, /* native exopackage */ false); - initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); // <---- start flipper integration - } -} -``` - -In the same file, modify the generated `initializeFlipper` method to - -```java - private static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { - if (BuildConfig.DEBUG) { - try { - /* - We use reflection here to pick up the class that initializes Flipper, - since Flipper library is not available in release mode - */ - Class aClass = Class.forName("com.yourappname.ReactNativeFlipper"); // <--- use your own namespace, same as before! - aClass.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class).invoke(null, context, reactInstanceManager); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - } -``` - -Finally, open the Flipper desktop app, and run `yarn android` in your terminal. - -### iOS - -We support both Swift and Objective-C for Flipper with CocoaPods as build and distribution mechanism. For CocoaPods 1.9+, follow this configuration. - -
- -If you can't build your app after adding Flipper, you may need to configure the Swift compiler. To do so, adding an empty Swift file in your project is the easiest way. - -
- -#### CocoaPods - -`ios/Podfile` - - - - -```ruby -platform :ios, '9.0' - -def flipper_pods() - flipperkit_version = '0.34.0' - pod 'FlipperKit', '~>' + flipperkit_version, :configuration => 'Debug' - pod 'FlipperKit/FlipperKitLayoutPlugin', '~>' + flipperkit_version, :configuration => 'Debug' - pod 'FlipperKit/SKIOSNetworkPlugin', '~>' + flipperkit_version, :configuration => 'Debug' - pod 'FlipperKit/FlipperKitUserDefaultsPlugin', '~>' + flipperkit_version, :configuration => 'Debug' - pod 'FlipperKit/FlipperKitReactPlugin', '~>' + flipperkit_version, :configuration => 'Debug' -end - -# Post Install processing for Flipper -def flipper_post_install(installer) - installer.pods_project.targets.each do |target| - if target.name == 'YogaKit' - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '4.1' - end - end - end - file_name = Dir.glob("*.xcodeproj")[0] - app_project = Xcodeproj::Project.open(file_name) - app_project.native_targets.each do |target| - target.build_configurations.each do |config| - cflags = config.build_settings['OTHER_CFLAGS'] || '$(inherited) ' - unless cflags.include? '-DFB_SONARKIT_ENABLED=1' - puts 'Adding -DFB_SONARKIT_ENABLED=1 in OTHER_CFLAGS...' - cflags << '-DFB_SONARKIT_ENABLED=1' - end - config.build_settings['OTHER_CFLAGS'] = cflags - end - app_project.save - end - installer.pods_project.save -end - -target 'your-app-name' do - ... - - - # Replace the existing yoga import with the following (adding modular_headers): - pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true - - ... - use_native_modules! - - # For enabling Flipper. - # Note that if you use_framework!, flipper will not work. - # Disable these lines if you are doing use_framework! - flipper_pods() - post_install do |installer| - flipper_post_install(installer) - end -end -``` - - - -Install the dependencies by running `cd ios && pod install`. You can now import and initialize Flipper in your -`ios/your-app-name/AppDelegate.m`. - -For pure Objective-C projects there is an additional setup, please follow these [steps](#for-pure-objective-c-projects) - -The code below enables the following integrations: - -- Layout Inspector -- Network -- Shared Preferences -- Crash Reporter - - - - - -```objective-c -... -#if DEBUG -#ifdef FB_SONARKIT_ENABLED -#import -#import -#import -#import -#import -#import -#import -#endif -#endif - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - [self initializeFlipper:application]; - ... -} - -- (void) initializeFlipper:(UIApplication *)application { - #if DEBUG - #ifdef FB_SONARKIT_ENABLED - FlipperClient *client = [FlipperClient sharedClient]; - SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; - [client addPlugin: [[FlipperKitLayoutPlugin alloc] initWithRootNode: application withDescriptorMapper: layoutDescriptorMapper]]; - [client addPlugin: [[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; - [client addPlugin: [FlipperKitReactPlugin new]]; - [client addPlugin: [[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; - [client start]; - #endif - #endif -} - -@end -``` - - - -```swift -... -#if DEBUG -#if FB_SONARKIT_ENABLED -import FlipperKit -#endif -#endif - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - func application( - _ application: UIApplication, - didFinishLaunchingWithOptions - launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - initializeFlipper(with: application) - ... - } - - private func initializeFlipper(with application: UIApplication) { - #if DEBUG - #if FB_SONARKIT_ENABLED - let client = FlipperClient.shared() - let layoutDescriptorMapper = SKDescriptorMapper(defaults: ()) - FlipperKitLayoutComponentKitSupport.setUpWith(layoutDescriptorMapper) - client?.add(FlipperKitLayoutPlugin(rootNode: application, with: layoutDescriptorMapper!)) - client?.add(FKUserDefaultsPlugin(suiteName: nil)) - client?.add(FlipperKitReactPlugin()) - client?.add(FlipperKitNetworkPlugin(networkAdapter: SKIOSNetworkAdapter())) - client?.add(FlipperReactPerformancePlugin.sharedInstance()) - client?.start() - #endif - #endif - } -} -``` - - - -Lastly, open the Flipper desktop app, and run `yarn ios` in your terminal. - -
- -- If you do not use CocoaPods as a dependency management tool then currently there is no way to integrate FlipperKit other than manually including all the dependencies and building it. -- For Android, Flipper works with both emulators and physical devices connected through USB. However on iOS, we don't yet support physical devices. +For Android, Flipper works with both emulators and physical devices connected through USB. However on iOS, we don't support physical devices yet.
## Having trouble? + See the [troubleshooting page](troubleshooting.html) for help with known problems. diff --git a/docs/tutorial/react-native.md b/docs/tutorial/react-native.md index 7dfccea09..fe823c3e1 100644 --- a/docs/tutorial/react-native.md +++ b/docs/tutorial/react-native.md @@ -12,7 +12,7 @@ This tutorial requires React Native 0.62 or higher. Once you have connected Flipper to a React Native application, writing your own Flipper plugin can be done without reaching into the native world. -To expose Flipper to the JavaScript world, the React Native Native Module `react-native-flipper` needs to be installed in the hosting application by running `yarn add react-native-flipper`. If you are creating develop a plugin that is distributed as NPM package, make sure to add this to the installation instruction of your package as well! +To expose Flipper to the JavaScript world, the React Native Native Module `react-native-flipper` needs to be installed in the hosting application by running `yarn add react-native-flipper` and `cd ios && pod install`. If you are creating develop a plugin that is distributed as NPM package, make sure to add this to the installation instruction of your package as well! Registering a new plugin is done by importing `addPlugin` from `"react-native-flipper"` and providing it an object that at least implements the method `getId` (the plugin id that should be used in the desktop plugin as well to make the connection) and two event handlers for the `onConnect` and `onDisconnect` events.