Merge pull request #204 from thornbill/android-back

Fix support for hardware back buttons
This commit is contained in:
Bill Thornton 2021-01-07 09:05:16 -05:00 committed by GitHub
commit 2039e77a2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 94 additions and 32 deletions

View File

@ -4,11 +4,11 @@ root = true
insert_final_newline = true insert_final_newline = true
end_of_line = lf end_of_line = lf
[{*.js, *.json}] [{*.js, *.json, *.staticjs}]
charset = utf-8 charset = utf-8
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.js] [{*.js, .staticjs}]
indent_style = tab indent_style = tab
[*.json] [*.json]

4
App.js
View File

@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
import { useStores } from './hooks/useStores'; import { useStores } from './hooks/useStores';
import AppNavigator from './navigation/AppNavigator'; import AppNavigator from './navigation/AppNavigator';
import DarkTheme from './themes/dark'; import DarkTheme from './themes/dark';
import NativeShellLoader from './utils/NativeShellLoader'; import StaticScriptLoader from './utils/StaticScriptlLoader';
// Import i18n configuration // Import i18n configuration
import './i18n'; import './i18n';
@ -89,7 +89,7 @@ const App = observer(({ skipLoadingScreen }) => {
...Ionicons.font ...Ionicons.font
}), }),
...loadImagesAsync(), ...loadImagesAsync(),
NativeShellLoader.load() StaticScriptLoader.load()
]); ]);
}; };

View File

@ -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();
}
}
};

View File

@ -3,6 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
function postExpoEvent(event, data) { function postExpoEvent(event, data) {
window.ReactNativeWebView.postMessage(JSON.stringify({ window.ReactNativeWebView.postMessage(JSON.stringify({
event: event, event: event,
@ -13,6 +14,7 @@ function postExpoEvent(event, data) {
// List of supported features as reported in Safari // List of supported features as reported in Safari
const ExpoSupportedFeatures = [ const ExpoSupportedFeatures = [
// 'filedownload', // 'filedownload',
'exit',
'exitmenu', 'exitmenu',
'plugins', 'plugins',
'externallinks', 'externallinks',

View File

@ -11,10 +11,10 @@ import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
import { useStores } from '../hooks/useStores'; import { useStores } from '../hooks/useStores';
import { getAppName, getSafeDeviceName } from '../utils/Device'; import { getAppName, getSafeDeviceName } from '../utils/Device';
import NativeShellLoader from '../utils/NativeShellLoader'; import StaticScriptLoader from '../utils/StaticScriptlLoader';
import { openBrowser } from '../utils/WebBrowser'; import { openBrowser } from '../utils/WebBrowser';
import RefreshWebView from './RefreshWebView'; import RefreshWebView from './RefreshWebView';
import { Platform } from 'react-native'; import { BackHandler, Platform } from 'react-native';
const NativeShellWebView = observer(React.forwardRef( const NativeShellWebView = observer(React.forwardRef(
function NativeShellWebView(props, ref) { function NativeShellWebView(props, ref) {
@ -31,7 +31,9 @@ window.ExpoAppInfo = {
deviceName: '${getSafeDeviceName().replace(/'/g, '\\\'')}' deviceName: '${getSafeDeviceName().replace(/'/g, '\\\'')}'
}; };
${NativeShellLoader.NativeShell} ${StaticScriptLoader.scripts.NativeShell}
${StaticScriptLoader.scripts.ExpoRouterShim}
true; true;
`; `;
@ -48,6 +50,9 @@ true;
try { try {
const { event, data } = JSON.parse(state.data); const { event, data } = JSON.parse(state.data);
switch (event) { switch (event) {
case 'AppHost.exit':
BackHandler.exitApp();
break;
case 'enableFullscreen': case 'enableFullscreen':
rootStore.isFullscreen = true; rootStore.isFullscreen = true;
break; break;

View File

@ -3,12 +3,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. * 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 { 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 { ThemeContext } from 'react-native-elements';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; 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 { observer } from 'mobx-react';
import { useStores } from '../hooks/useStores'; import { useStores } from '../hooks/useStores';
@ -35,11 +35,24 @@ const HomeScreen = observer(() => {
// Prevent default behavior // Prevent default behavior
e.preventDefault(); e.preventDefault();
// Call the web router to navigate home // 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(() => {
const 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 // Clear the error state when the active server changes
useEffect(() => { useEffect(() => {
setIsLoading(true); setIsLoading(true);

View File

@ -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;

View File

@ -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;