From 426d17b08deebeea9a979ef015986238e8af767f Mon Sep 17 00:00:00 2001 From: Michel Weststrate Date: Thu, 23 Jan 2020 07:09:51 -0800 Subject: [PATCH] Update docs for JS only plugins Summary: Added docs on how to write React-Native JavaScript based plugins Reviewed By: passy Differential Revision: D19344803 fbshipit-source-id: ad1ea66f1031760729fdaea8a7e6c1ef5dcd5439 --- .gitignore | 3 ++ docs/extending/create-plugin.md | 71 ++++++++++++++++++++++++++++++++- docs/extending/js-plugin-api.md | 6 +++ docs/tutorial/react-native.md | 52 ++++++++++++++++++++++++ website/i18n/en.json | 3 ++ website/sidebars.json | 1 + 6 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 docs/tutorial/react-native.md diff --git a/.gitignore b/.gitignore index 0d083e7bc..d6a2bf980 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ libs/*/bin/**/*.class # Mac OS X *.DS_Store + +# Automatically generated +docs/extending/ui-components.md diff --git a/docs/extending/create-plugin.md b/docs/extending/create-plugin.md index f08bf3131..48dc09cc3 100644 --- a/docs/extending/create-plugin.md +++ b/docs/extending/create-plugin.md @@ -4,7 +4,8 @@ title: Client Plugin API --- ## FlipperPlugin -To build a client plugin, just implement the `FlipperPlugin` interface. + +To build a client plugin, implement the `FlipperPlugin` interface. The ID that is returned from your implementation needs to match the `name` defined in your JavaScript counterpart's `package.json`. @@ -60,6 +61,32 @@ public: bool runInBackground() override; }; ``` + + +
+ +Please note that using Flipper from JavaScript in React Native requires the package [`react-native-flipper`](https://www.npmjs.com/package/react-native-flipper) to be installed in the hosting application. + +
+ +```javascript +import {addPlugin} from 'react-native-flipper'; + +addPlugin({ + getId() { + return 'MyFlipperPlugin'; + }, + onConnect(connection) { + console.log("connected"); + }, + onDisconnect() { + console.log("disconnected"); + }, + runInBackground() { + return false; + } +}) +``` @@ -112,6 +139,25 @@ void MyFlipperPlugin::didConnect(std::shared_ptr conn) { }); } ``` + +```javascript +addPlugin({ + getId() { + return 'MyFlipperPlugin'; + }, + onConnect(connection) { + console.log("connected"); + connection.receive("getData", (data, responder) => { + console.log("incoming data", data); + // respond with some data + responder.success({ + ack: true + }); + }); + }, + // ...as-is +}) +``` ## Push data to the desktop @@ -137,12 +183,33 @@ void MyFlipperPlugin::didConnect(std::shared_ptr conn) { conn->send("getData", message); } ``` + +```javascript +addPlugin({ + getId() { + return 'MyFlipperPlugin'; + }, + onConnect(connection) { + console.log("connected"); + connection.send("newRow", { message: "Hello" }); + }, + // ...as-is +}) +``` ## Background Plugins -In some cases you may want to provide data to flipper even when your plugin is not currently active. Returning true in `runInBackground()` will result in `onConnect` being called as soon as Flipper connects, and allow you to use the connection at any time. +In some cases you may want to provide data to Flipper even when your plugin is not currently active. Returning true in `runInBackground()` will result in `onConnect` being called as soon as Flipper connects, and allow you to use the connection at any time. This should be used in combination with a `persistedStateReducer` on the desktop side. See the [JS Plugin API](js-plugin-api#background-plugins) for details. The benefit is that the desktop plugin can process this data in the background and fire notifications. It also reduces the number of renders and time taken to display the data when the plugin becomes active. + +
+ +Please note that a background plugin could keep some data in memory until a Flipper connection is available, for example to keep statistics about the app startup process. +However, a plugin shouldn't assume it will eventually get a connection, since this depends on whether the user has enabled the plugin on the Desktop side. +So make sure to not store unbounded amounts of data! + +
diff --git a/docs/extending/js-plugin-api.md b/docs/extending/js-plugin-api.md index b991fc615..22b58538f 100644 --- a/docs/extending/js-plugin-api.md +++ b/docs/extending/js-plugin-api.md @@ -3,6 +3,12 @@ id: js-plugin-api title: JavaScript Plugin API --- +
+ +This page describes the JavaScript API that is used to implement plugins inside the Flipper Desktop application. For the JavaScript API that can be used inside React Native to communicate with the Flipper Desktop, see [Client Plugin API](create-plugin). + +
+ Provided a plugin is setup as defined in [JS Plugin Definiton](js-setup), the basic requirement of a Flipper plugin is that `index.tsx` exports a default class that extends `FlipperPlugin`. `FlipperPlugin` is an extension of `React.Component` with extra Flipper-related functionality. This means to define the UI of your plugin, you just need to implement this React component. diff --git a/docs/tutorial/react-native.md b/docs/tutorial/react-native.md new file mode 100644 index 000000000..11eafe2a9 --- /dev/null +++ b/docs/tutorial/react-native.md @@ -0,0 +1,52 @@ +--- +id: react-native +title: Building a React Native Plugin +--- + +
+ +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! + +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. + +These `onConnect` and `onDisconnect` events are triggered every time the plugin becomes (in)active in the Flipper desktop application. +If the plugin is a [background plugin](../extending/create-plugin.md#background-plugins), these events are triggered typically only once (they might be triggered never, if the Desktop user didn't enable the plugin, or multiple times if they enabled or disabled the plugin a few times). + +The `onConnect` callback receive a `connection` which can be used to communicate with the backend: + +```javascript +import {addPlugin} from "react-native-flipper" + +addPlugin({ + getId() { + return 'ReactNativeExamplePlugin'; + }, + onConnect(connection) { + mammmals.forEach(({ title, pictureUrl }, index) => { + connection.send('newRow', { + id: index, + title, + url: pictureUrl + }) + }) + }, + onDisconnect() { + } +}) +``` + +You might want to store the connection somewhere to be able to send more events as long as `onDisconnect` event hasn't been fired. + +The `connection` object can also be used to listen to messages coming from the Desktop plugin. See [Client Plugin API](create-plugin) for details. + +An example plugin to play a little Tic-Tac-Toe between the Flipper Desktop and a React Native app can be found inside this repository as well (run `yarn && yarn android` in `react-native/ReactNativeFlipperExample` to start the test project): + + * The React Native JavaScript based plugin implementation: [FlipperTicTacToe.js](https://github.com/facebook/flipper/tree/master/react-native/ReactNativeFlipperExample/FlipperTicTacToe.js) + * The Flipper Desktop plugin implementation: [rn-tic-tac-toe/index.tsx](https://github.com/facebook/flipper/blob/master/src/plugins/rn-tic-tac-toe/index.tsx) diff --git a/website/i18n/en.json b/website/i18n/en.json index c4b73d3a8..b90894ad0 100644 --- a/website/i18n/en.json +++ b/website/i18n/en.json @@ -166,6 +166,9 @@ }, "tutorial/js-table": { "title": "Showing a table" + }, + "tutorial/react-native": { + "title": "Building a React Native Plugin" } }, "links": { diff --git a/website/sidebars.json b/website/sidebars.json index fc46e4e08..6e25c5c5e 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -36,6 +36,7 @@ "tutorial/intro", "tutorial/ios", "tutorial/android", + "tutorial/react-native", "tutorial/js-setup", "tutorial/js-table", "tutorial/js-custom",