From ce996ba8af28f4b6dfc904f03cf92ec0ea26a952 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Wed, 17 Oct 2018 06:17:55 -0700 Subject: [PATCH] Add listener in the renderer process for deeplink Summary: - Set userPrefferedPlugin for external deeplink - Listen for deeplink in renderer process and navigate accordingly Reviewed By: passy Differential Revision: D10339035 fbshipit-source-id: 4de6249a0672f9ce02b0dfb78a4563302c308578 --- src/App.js | 2 +- .../__tests__/deeplinkURLParsing.node.js | 32 +++++++++++++++ src/dispatcher/application.js | 40 ++++++++++++++++++- src/reducers/connections.js | 13 +++++- static/index.js | 11 +++-- 5 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 src/dispatcher/__tests__/deeplinkURLParsing.node.js diff --git a/src/App.js b/src/App.js index 2aafaff87..688e478e2 100644 --- a/src/App.js +++ b/src/App.js @@ -45,8 +45,8 @@ export class App extends React.Component { ); }); ipcRenderer.send('getLaunchTime'); + ipcRenderer.send('componentDidMount'); } - render() { return ( diff --git a/src/dispatcher/__tests__/deeplinkURLParsing.node.js b/src/dispatcher/__tests__/deeplinkURLParsing.node.js new file mode 100644 index 000000000..a6b28881d --- /dev/null +++ b/src/dispatcher/__tests__/deeplinkURLParsing.node.js @@ -0,0 +1,32 @@ +/** + * Copyright 2018-present Facebook. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * @format + */ + +import {uriComponents} from '../application.js'; + +test('test parsing of deeplink URL', () => { + const url = 'flipper://app/plugin/meta/data'; + let components = uriComponents(url); + expect(components).toEqual(['app', 'plugin', 'meta/data']); +}); + +test('test parsing of deeplink URL when arguments are less', () => { + const url = 'flipper://app/'; + let components = uriComponents(url); + expect(components).toEqual(['app']); +}); + +test('test parsing of deeplink URL when url is null', () => { + // $FlowFixMe + let components = uriComponents(null); + expect(components).toEqual([]); +}); + +test('test parsing of deeplink URL when pattern does not match', () => { + const url = 'Some random string'; + let components = uriComponents(url); + expect(components).toEqual([]); +}); diff --git a/src/dispatcher/application.js b/src/dispatcher/application.js index 603a33758..5b8f4cd24 100644 --- a/src/dispatcher/application.js +++ b/src/dispatcher/application.js @@ -5,10 +5,27 @@ * @format */ -import {remote} from 'electron'; +import {remote, ipcRenderer} from 'electron'; import type {Store} from '../reducers/index.js'; import type Logger from '../fb-stubs/Logger.js'; +import {selectPlugin, userPreferredPlugin} from '../reducers/connections'; +export const uriComponents = (url: string) => { + if (!url) { + return []; + } + const match: ?Array = url.match( + /^flipper:\/\/([^\/]*)\/([^\/]*)\/?(.*)$/, + ); + if (match) { + return (match + .map(decodeURIComponent) + .slice(1) + .filter(Boolean): Array); + } + return []; +}; + export default (store: Store, logger: Logger) => { const currentWindow = remote.getCurrentWindow(); currentWindow.on('focus', () => { @@ -23,4 +40,25 @@ export default (store: Store, logger: Logger) => { payload: false, }); }); + + ipcRenderer.on('flipper-deeplink', (event, url) => { + // flipper://// + const match = uriComponents(url); + if (match.length > 1) { + store.dispatch( + selectPlugin({ + selectedApp: match[0], + selectedPlugin: match[1], + deepLinkPayload: match[2], + }), + ); + } + }); + ipcRenderer.on('flipper-deeplink-preferred-plugin', (event, url) => { + // flipper://// + const match = uriComponents(url); + if (match.length > 1) { + store.dispatch(userPreferredPlugin(match[1])); + } + }); }; diff --git a/src/reducers/connections.js b/src/reducers/connections.js index 779b71327..0276ef683 100644 --- a/src/reducers/connections.js +++ b/src/reducers/connections.js @@ -45,6 +45,10 @@ export type Action = selectedApp: ?string, }, } + | { + type: 'SELECT_USER_PREFERRED_PLUGIN', + payload: string, + } | { type: 'SERVER_ERROR', payload: ?string, @@ -178,7 +182,10 @@ export default function reducer( userPreferredPlugin: selectedPlugin, }; } - + case 'SELECT_USER_PREFERRED_PLUGIN': { + const {payload} = action; + return {...state, userPreferredPlugin: payload}; + } case 'NEW_CLIENT': { const {payload} = action; const {userPreferredApp, userPreferredPlugin} = state; @@ -249,3 +256,7 @@ export const selectPlugin = (payload: { type: 'SELECT_PLUGIN', payload, }); +export const userPreferredPlugin = (payload: string): Action => ({ + type: 'SELECT_USER_PREFERRED_PLUGIN', + payload, +}); diff --git a/static/index.js b/static/index.js index f7d59f286..8153aa462 100644 --- a/static/index.js +++ b/static/index.js @@ -153,6 +153,13 @@ app.on('ready', function() { } }); +ipcMain.on('componentDidMount', event => { + if (deeplinkURL) { + win.webContents.send('flipper-deeplink-preferred-plugin', deeplinkURL); + deeplinkURL = null; + } +}); + ipcMain.on('getLaunchTime', event => { if (launchStartTime) { event.sender.send('getLaunchTime', launchStartTime); @@ -161,7 +168,6 @@ ipcMain.on('getLaunchTime', event => { launchStartTime = null; } }); - // Define custom protocol handler. Deep linking works on packaged versions of the application! app.setAsDefaultProtocolClient('flipper'); @@ -219,8 +225,5 @@ function tryCreateWindow() { slashes: true, }); win.loadURL(entryUrl); - if (deeplinkURL) { - win.webContents.send('flipper-deeplink', deeplinkURL); - } } }