Move NativeShell to asset file to read as a string

This commit is contained in:
Bill Thornton 2020-12-28 16:28:29 -05:00
parent 505b501706
commit 2e2c671a6b
8 changed files with 213 additions and 166 deletions

View File

@ -12,10 +12,6 @@
"plugin:import/typescript",
"plugin:eslint-comments/recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaFeatures": {
@ -55,5 +51,21 @@
"semi": ["error"],
"space-before-blocks": ["error"],
"space-infix-ops": ["error"]
}
},
"overrides": [
{
"files": [ "./**/*.js" ],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
}
},
{
"files": [ "./assets/**/*.staticjs" ],
"env": {
"node": false,
"browser": true
}
}
]
}

4
App.js
View File

@ -21,6 +21,7 @@ import { useStores } from './hooks/useStores';
import Colors from './constants/Colors';
import AppNavigator from './navigation/AppNavigator';
import Theme from './utils/Theme';
import NativeShellLoader from './utils/NativeShellLoader';
// Import i18n configuration
import './i18n';
@ -87,7 +88,8 @@ const App = observer(({ skipLoadingScreen }) => {
// This is the font that we are using for our tab bar
...Ionicons.font
}),
...loadImagesAsync()
...loadImagesAsync(),
NativeShellLoader.load()
]);
};

View File

@ -0,0 +1,140 @@
/**
* 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/.
*/
function postExpoEvent(event, data) {
window.ReactNativeWebView.postMessage(JSON.stringify({
event: event,
data: data
}));
}
// List of supported features as reported in Safari
const ExpoSupportedFeatures = [
// 'filedownload',
'exitmenu',
'plugins',
'externallinks',
'externalpremium',
'externallinkdisplay',
'fullscreenchange',
'physicalvolumecontrol',
'remotecontrol',
'remotevideo',
'displaylanguage',
'otherapppromotions',
'displaymode',
'subtitleappearancesettings',
'subtitleburnsettings',
'fileinput'
];
window.console = Object.assign(window.console, {
debug: text => postExpoEvent('console.debug', text),
error: text => postExpoEvent('console.error', text),
info: text => postExpoEvent('console.info', text),
log: text => postExpoEvent('console.log', text),
warn: text => postExpoEvent('console.warn', text)
});
window.NativeShell = {
AppHost: {
init: function() {
postExpoEvent('AppHost.init', window.ExpoAppInfo);
return Promise.resolve(window.ExpoAppInfo);
},
appName: function() {
postExpoEvent('AppHost.appName', window.ExpoAppInfo.appName);
return window.ExpoAppInfo.appName;
},
appVersion: function() {
postExpoEvent('AppHost.appVersion', window.ExpoAppInfo.appVersion);
return window.ExpoAppInfo.appVersion;
},
deviceId: function() {
postExpoEvent('AppHost.deviceId', window.ExpoAppInfo.deviceId);
return window.ExpoAppInfo.deviceId;
},
deviceName: function() {
postExpoEvent('AppHost.deviceName', window.ExpoAppInfo.deviceName);
return window.ExpoAppInfo.deviceName;
},
exit: function() {
postExpoEvent('AppHost.exit');
},
getDefaultLayout: function() {
postExpoEvent('AppHost.getDefaultLayout', 'mobile');
return 'mobile';
},
getDeviceProfile: function(profileBuilder, profileBuilderVersion) {
const audioCodecs = ['opus'];
const versionNumber = profileBuilderVersion !== undefined && profileBuilderVersion.split('.').map(num => Number.parseInt(num, 10));
const isAc3Eac3Disabled = profileBuilderVersion === undefined || (versionNumber.length === 3 && versionNumber[0] === 10 && versionNumber[1] < 7);
if (isAc3Eac3Disabled) {
audioCodecs.push('ac3');
audioCodecs.push('eac3');
}
postExpoEvent('AppHost.getDeviceProfile');
return profileBuilder({
enableMkvProgressive: false,
disableHlsVideoAudioCodecs: audioCodecs
});
},
// Keep for support server versions < 10.7
getSyncProfile: function() {
postExpoEvent('AppHost.getSyncProfile');
return Promise.resolve({});
},
supports: function(command) {
const isSupported = command && ExpoSupportedFeatures.indexOf(command.toLowerCase()) != -1;
postExpoEvent('AppHost.supports', {
command: command,
isSupported: isSupported
});
return isSupported;
}
},
downloadFile: function(url) {
postExpoEvent('downloadFile', { url: url });
},
enableFullscreen: function() {
postExpoEvent('enableFullscreen');
},
disableFullscreen: function() {
postExpoEvent('disableFullscreen');
},
getPlugins: function() {
postExpoEvent('getPlugins');
return [];
},
openUrl: function(url, target) {
postExpoEvent('openUrl', {
url: url,
target: target
});
},
updateMediaSession: function(mediaInfo) {
postExpoEvent('updateMediaSession', { mediaInfo: mediaInfo });
},
hideMediaSession: function() {
postExpoEvent('hideMediaSession');
}
};

View File

@ -11,24 +11,11 @@ import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
import { useStores } from '../hooks/useStores';
import { getAppName, getSafeDeviceName } from '../utils/Device';
import NativeShell from '../utils/NativeShell';
import NativeShellLoader from '../utils/NativeShellLoader';
import { openBrowser } from '../utils/WebBrowser';
import RefreshWebView from './RefreshWebView';
import { Platform } from 'react-native';
const injectedJavaScript = `
window.ExpoAppInfo = {
appName: '${getAppName()}',
appVersion: '${Constants.nativeAppVersion}',
deviceId: '${Constants.deviceId}',
deviceName: '${getSafeDeviceName().replace(/'/g, '\\\'')}'
};
${NativeShell}
true;
`;
const NativeShellWebView = observer(React.forwardRef(
function NativeShellWebView(props, ref) {
const { rootStore } = useStores();
@ -36,6 +23,19 @@ const NativeShellWebView = observer(React.forwardRef(
const server = rootStore.serverStore.servers[rootStore.settingStore.activeServer];
const injectedJavaScript = `
window.ExpoAppInfo = {
appName: '${getAppName()}',
appVersion: '${Constants.nativeAppVersion}',
deviceId: '${Constants.deviceId}',
deviceName: '${getSafeDeviceName().replace(/'/g, '\\\'')}'
};
${NativeShellLoader.NativeShell}
true;
`;
const onRefresh = () => {
// Disable pull to refresh when in fullscreen
if (rootStore.isFullscreen) return;

17
metro.config.js Normal file
View File

@ -0,0 +1,17 @@
/**
* 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 { getDefaultConfig } = require('@expo/metro-config');
const defaultConfig = getDefaultConfig(__dirname);
module.exports = {
resolver: {
assetExts: [
...defaultConfig.resolver.assetExts,
'staticjs'
]
}
};

View File

@ -20,6 +20,7 @@
"expo-asset": "~8.2.0",
"expo-constants": "~9.2.0",
"expo-device": "~2.3.0",
"expo-file-system": "~9.2.0",
"expo-font": "~8.3.0",
"expo-keep-awake": "~8.3.0",
"expo-localization": "~9.0.0",

View File

@ -1,146 +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/.
*/
/* eslint-env browser */
const NativeShell = `
function postExpoEvent(event, data) {
window.ReactNativeWebView.postMessage(JSON.stringify({
event: event,
data: data
}));
}
// List of supported features as reported in Safari
const ExpoSupportedFeatures = [
// 'filedownload',
'exitmenu',
'plugins',
'externallinks',
'externalpremium',
'externallinkdisplay',
'fullscreenchange',
'physicalvolumecontrol',
'remotecontrol',
'remotevideo',
'displaylanguage',
'otherapppromotions',
'displaymode',
'subtitleappearancesettings',
'subtitleburnsettings',
'fileinput',
];
window.console = Object.assign(window.console, {
debug: text => postExpoEvent('console.debug', text),
error: text => postExpoEvent('console.error', text),
info: text => postExpoEvent('console.info', text),
log: text => postExpoEvent('console.log', text),
warn: text => postExpoEvent('console.warn', text)
});
window.NativeShell = {
AppHost: {
init: function() {
postExpoEvent('AppHost.init', window.ExpoAppInfo);
return Promise.resolve(window.ExpoAppInfo);
},
appName: function() {
postExpoEvent('AppHost.appName', window.ExpoAppInfo.appName);
return window.ExpoAppInfo.appName;
},
appVersion: function() {
postExpoEvent('AppHost.appVersion', window.ExpoAppInfo.appVersion);
return window.ExpoAppInfo.appVersion;
},
deviceId: function() {
postExpoEvent('AppHost.deviceId', window.ExpoAppInfo.deviceId);
return window.ExpoAppInfo.deviceId;
},
deviceName: function() {
postExpoEvent('AppHost.deviceName', window.ExpoAppInfo.deviceName);
return window.ExpoAppInfo.deviceName;
},
exit: function() {
postExpoEvent('AppHost.exit');
},
getDefaultLayout: function() {
postExpoEvent('AppHost.getDefaultLayout', 'mobile');
return 'mobile';
},
getDeviceProfile: function(profileBuilder, profileBuilderVersion) {
const audioCodecs = ['opus'];
const versionNumber = profileBuilderVersion !== undefined && profileBuilderVersion.split('.').map(num => Number.parseInt(num, 10));
const isAc3Eac3Disabled = profileBuilderVersion === undefined || (versionNumber.length === 3 && versionNumber[0] === 10 && versionNumber[1] < 7);
if (isAc3Eac3Disabled) {
audioCodecs.push('ac3');
audioCodecs.push('eac3');
}
postExpoEvent('AppHost.getDeviceProfile');
return profileBuilder({
enableMkvProgressive: false,
disableHlsVideoAudioCodecs: audioCodecs
});
},
// Keep for support server versions < 10.7
getSyncProfile: function() {
postExpoEvent('AppHost.getSyncProfile');
return Promise.resolve({});
},
supports: function(command) {
const isSupported = command && ExpoSupportedFeatures.indexOf(command.toLowerCase()) != -1;
postExpoEvent('AppHost.supports', {
command: command,
isSupported: isSupported
});
return isSupported;
}
},
downloadFile: function(url) {
postExpoEvent('downloadFile', { url: url });
},
enableFullscreen: function() {
postExpoEvent('enableFullscreen');
},
disableFullscreen: function() {
postExpoEvent('disableFullscreen');
},
getPlugins: function() {
postExpoEvent('getPlugins');
return [];
},
openUrl: function(url, target) {
postExpoEvent('openUrl', {
url: url,
target: target
});
},
updateMediaSession: function(mediaInfo) {
postExpoEvent('updateMediaSession', { mediaInfo: mediaInfo });
},
hideMediaSession: function() {
postExpoEvent('hideMediaSession');
}
};
`;
export default NativeShell;

View File

@ -0,0 +1,21 @@
/**
* 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;