From ec1bd0dd856c9d77e8c5064fe63f6f2c82904131 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 6 Jan 2021 14:27:10 -0500 Subject: [PATCH 1/2] Fix support for hardware back buttons --- .editorconfig | 4 ++-- App.js | 4 ++-- assets/js/ExpoRouterShim.staticjs | 31 ++++++++++++++++++++++++++++++ assets/js/NativeShell.staticjs | 2 ++ components/NativeShellWebView.js | 11 ++++++++--- screens/HomeScreen.js | 23 ++++++++++++++++++---- utils/NativeShellLoader.js | 21 -------------------- utils/StaticScriptlLoader.js | 32 +++++++++++++++++++++++++++++++ 8 files changed, 96 insertions(+), 32 deletions(-) create mode 100644 assets/js/ExpoRouterShim.staticjs delete mode 100644 utils/NativeShellLoader.js create mode 100644 utils/StaticScriptlLoader.js diff --git a/.editorconfig b/.editorconfig index 5b52116..d178b51 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,11 +4,11 @@ root = true insert_final_newline = true end_of_line = lf -[{*.js, *.json}] +[{*.js, *.json, *.staticjs}] charset = utf-8 trim_trailing_whitespace = true -[*.js] +[{*.js, .staticjs}] indent_style = tab [*.json] diff --git a/App.js b/App.js index aea36b8..4fecf29 100644 --- a/App.js +++ b/App.js @@ -20,7 +20,7 @@ import PropTypes from 'prop-types'; import { useStores } from './hooks/useStores'; import AppNavigator from './navigation/AppNavigator'; import DarkTheme from './themes/dark'; -import NativeShellLoader from './utils/NativeShellLoader'; +import StaticScriptLoader from './utils/StaticScriptlLoader'; // Import i18n configuration import './i18n'; @@ -89,7 +89,7 @@ const App = observer(({ skipLoadingScreen }) => { ...Ionicons.font }), ...loadImagesAsync(), - NativeShellLoader.load() + StaticScriptLoader.load() ]); }; diff --git a/assets/js/ExpoRouterShim.staticjs b/assets/js/ExpoRouterShim.staticjs new file mode 100644 index 0000000..07e84f3 --- /dev/null +++ b/assets/js/ExpoRouterShim.staticjs @@ -0,0 +1,31 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +const getWebRouter = function() { + return window.Emby && window.Emby.Page; +}; + +window.ExpoRouterShim = { + back: function() { + const router = getWebRouter(); + if (router) { + try { + if (router.canGoBack()) { + router.back(); + } else { + window.NativeShell.AppHost.exit(); + } + } catch (ex) { + console.error('[ExpoRouterShim] call to back() failed', ex); + } + } + }, + home: function() { + const router = getWebRouter(); + if (router && typeof router.goHome === 'function') { + router.goHome(); + } + } +}; diff --git a/assets/js/NativeShell.staticjs b/assets/js/NativeShell.staticjs index 65992d5..5a161de 100644 --- a/assets/js/NativeShell.staticjs +++ b/assets/js/NativeShell.staticjs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + function postExpoEvent(event, data) { window.ReactNativeWebView.postMessage(JSON.stringify({ event: event, @@ -13,6 +14,7 @@ function postExpoEvent(event, data) { // List of supported features as reported in Safari const ExpoSupportedFeatures = [ // 'filedownload', + 'exit', 'exitmenu', 'plugins', 'externallinks', diff --git a/components/NativeShellWebView.js b/components/NativeShellWebView.js index 7902c32..a063f8a 100644 --- a/components/NativeShellWebView.js +++ b/components/NativeShellWebView.js @@ -11,10 +11,10 @@ import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake'; import { useStores } from '../hooks/useStores'; import { getAppName, getSafeDeviceName } from '../utils/Device'; -import NativeShellLoader from '../utils/NativeShellLoader'; +import StaticScriptLoader from '../utils/StaticScriptlLoader'; import { openBrowser } from '../utils/WebBrowser'; import RefreshWebView from './RefreshWebView'; -import { Platform } from 'react-native'; +import { BackHandler, Platform } from 'react-native'; const NativeShellWebView = observer(React.forwardRef( function NativeShellWebView(props, ref) { @@ -31,7 +31,9 @@ window.ExpoAppInfo = { deviceName: '${getSafeDeviceName().replace(/'/g, '\\\'')}' }; -${NativeShellLoader.NativeShell} +${StaticScriptLoader.scripts.NativeShell} + +${StaticScriptLoader.scripts.ExpoRouterShim} true; `; @@ -48,6 +50,9 @@ true; try { const { event, data } = JSON.parse(state.data); switch (event) { + case 'AppHost.exit': + BackHandler.exitApp(); + break; case 'enableFullscreen': rootStore.isFullscreen = true; break; diff --git a/screens/HomeScreen.js b/screens/HomeScreen.js index b145df9..239071d 100644 --- a/screens/HomeScreen.js +++ b/screens/HomeScreen.js @@ -3,12 +3,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import React, { useContext, useEffect, useState, useRef } from 'react'; +import React, { useCallback, useContext, useEffect, useState, useRef } from 'react'; import { useTranslation } from 'react-i18next'; -import { Platform, StyleSheet, View } from 'react-native'; +import { BackHandler, Platform, StyleSheet, View } from 'react-native'; import { ThemeContext } from 'react-native-elements'; import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; -import { useNavigation } from '@react-navigation/native'; +import { useFocusEffect, useNavigation } from '@react-navigation/native'; import { observer } from 'mobx-react'; import { useStores } from '../hooks/useStores'; @@ -35,11 +35,26 @@ const HomeScreen = observer(() => { // Prevent default behavior e.preventDefault(); // Call the web router to navigate home - webview.current?.injectJavaScript('window.Emby && window.Emby.Page && typeof window.Emby.Page.goHome === "function" && window.Emby.Page.goHome();'); + webview.current?.injectJavaScript('window.ExpoRouterShim && window.ExpoRouterShim.home();'); } }); }, []); + useFocusEffect( + useCallback(() => { + console.log('useCallback'); + const onBackPress = () => { + console.log('onBackPress()'); + webview.current?.injectJavaScript('window.ExpoRouterShim && window.ExpoRouterShim.back();'); + return true; + }; + + BackHandler.addEventListener('hardwareBackPress', onBackPress); + + return () => BackHandler.removeEventListener('hardwareBackPress', onBackPress); + }, [webview]) + ); + // Clear the error state when the active server changes useEffect(() => { setIsLoading(true); diff --git a/utils/NativeShellLoader.js b/utils/NativeShellLoader.js deleted file mode 100644 index e7cad4a..0000000 --- a/utils/NativeShellLoader.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -import { Asset } from 'expo-asset'; -import { readAsStringAsync } from 'expo-file-system'; - -class Loader { - NativeShell = '' - - async load() { - const [{ localUri }] = await Asset.loadAsync(require('../assets/js/NativeShell.staticjs')); - this.NativeShell = await readAsStringAsync(localUri); - return this.NativeShell; - } -} - -const NativeShellLoader = new Loader(); - -export default NativeShellLoader; diff --git a/utils/StaticScriptlLoader.js b/utils/StaticScriptlLoader.js new file mode 100644 index 0000000..b091ee7 --- /dev/null +++ b/utils/StaticScriptlLoader.js @@ -0,0 +1,32 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +import { Asset } from 'expo-asset'; +import { readAsStringAsync } from 'expo-file-system'; + +const loadStaticFile = async (asset) => { + const [{ localUri }] = await Asset.loadAsync(asset); + return await readAsStringAsync(localUri); +}; + +class Loader { + scripts = { + NativeShell: '', + ExpoRouterShim: '' + } + + async load() { + // Load the NativeShell + this.scripts.NativeShell = await loadStaticFile(require('../assets/js/NativeShell.staticjs')); + // Load the RouterShim + this.scripts.ExpoRouterShim = await loadStaticFile(require('../assets/js/ExpoRouterShim.staticjs')); + + return this.scripts; + } +} + +const StaticScriptLoader = new Loader(); + +export default StaticScriptLoader; From 25d89a0711e059435b156395f8f90837543d582b Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 6 Jan 2021 14:36:56 -0500 Subject: [PATCH 2/2] Remove debug logging --- screens/HomeScreen.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/screens/HomeScreen.js b/screens/HomeScreen.js index 239071d..e157cc2 100644 --- a/screens/HomeScreen.js +++ b/screens/HomeScreen.js @@ -42,9 +42,7 @@ const HomeScreen = observer(() => { useFocusEffect( useCallback(() => { - console.log('useCallback'); const onBackPress = () => { - console.log('onBackPress()'); webview.current?.injectJavaScript('window.ExpoRouterShim && window.ExpoRouterShim.back();'); return true; };