From 0363485069a0079ab7f85e2f08f77fa802ba465e Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 24 Nov 2023 11:37:37 -0800 Subject: [PATCH] RNTester: add the ability to open a specific example from incoming URL (#41642) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/41642 This allows opening an example within RNTester without tapping the module card. If the app receives an openURL request with the format `rntester://example/`, open that example (if exists) directly. Such URL request may come from various sources (e.g. custom test run, etc). Changelog: [Internal] Reviewed By: christophpurrer Differential Revision: D51543385 fbshipit-source-id: f9a01963cefb4602b629da0b01be6e334c28a912 --- packages/rn-tester/js/RNTesterAppShared.js | 47 ++++++++++++++++++- .../js/utils/RNTesterNavigationReducer.js | 9 ++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/rn-tester/js/RNTesterAppShared.js b/packages/rn-tester/js/RNTesterAppShared.js index 3f93d9aa480..27260cc901a 100644 --- a/packages/rn-tester/js/RNTesterAppShared.js +++ b/packages/rn-tester/js/RNTesterAppShared.js @@ -26,7 +26,13 @@ import { initialNavigationState, } from './utils/testerStateUtils'; import * as React from 'react'; -import {BackHandler, StyleSheet, View, useColorScheme} from 'react-native'; +import { + BackHandler, + Linking, + StyleSheet, + View, + useColorScheme, +} from 'react-native'; // RNTester App currently uses in memory storage for storing navigation state @@ -113,6 +119,45 @@ const RNTesterApp = ({ [dispatch], ); + // Setup Linking event subscription + const handleOpenUrlRequest = React.useCallback( + ({url}: {url: string, ...}) => { + // Supported URL pattern(s): + // * rntester://example/ + const match = /^rntester:\/\/example\/(.+)$/.exec(url); + if (!match) { + console.warn( + `handleOpenUrlRequest: Received unsupported URL: '${url}'`, + ); + return; + } + + const key = match[1]; + const exampleModule = RNTesterList.Modules[key]; + if (exampleModule == null) { + console.warn( + `handleOpenUrlRequest: Unable to find requested module with key: '${key}'`, + ); + return; + } + + console.log(`handleOpenUrlRequest: Opening example '${key}'`); + + dispatch({ + type: RNTesterNavigationActionsType.EXAMPLE_OPEN_URL_REQUEST, + data: { + key, + title: exampleModule.title || key, + }, + }); + }, + [dispatch], + ); + React.useEffect(() => { + const subscription = Linking.addEventListener('url', handleOpenUrlRequest); + return () => subscription.remove(); + }, [handleOpenUrlRequest]); + const theme = colorScheme === 'dark' ? themes.dark : themes.light; if (examplesList === null) { diff --git a/packages/rn-tester/js/utils/RNTesterNavigationReducer.js b/packages/rn-tester/js/utils/RNTesterNavigationReducer.js index 9c2097d668c..db59ba5a7a7 100644 --- a/packages/rn-tester/js/utils/RNTesterNavigationReducer.js +++ b/packages/rn-tester/js/utils/RNTesterNavigationReducer.js @@ -18,6 +18,7 @@ export const RNTesterNavigationActionsType = { BACK_BUTTON_PRESS: 'BACK_BUTTON_PRESS', MODULE_CARD_PRESS: 'MODULE_CARD_PRESS', EXAMPLE_CARD_PRESS: 'EXAMPLE_CARD_PRESS', + EXAMPLE_OPEN_URL_REQUEST: 'EXAMPLE_OPEN_URL_REQUEST', }; const getUpdatedRecentlyUsed = ({ @@ -100,6 +101,14 @@ export const RNTesterNavigationReducer = ( state.activeModuleExampleKey != null ? state.activeModuleTitle : null, }; + case RNTesterNavigationActionsType.EXAMPLE_OPEN_URL_REQUEST: + return { + ...state, + activeModuleKey: key, + activeModuleTitle: title, + activeModuleExampleKey: null, + }; + default: throw new Error(`Invalid action type ${action.type}`); }