From 448c19380b7e0a5f000d3297cbb3b655a336953c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Str=C3=B6mkvist?= Date: Wed, 28 Aug 2019 22:26:45 +0200 Subject: [PATCH 1/3] Use community WebView fork From https://github.com/react-native-community/react-native-webview As discussed in react-native-community/discussions-and-proposals#6 and react-native-community/discussions-and-proposals#3 --- App.js | 22 +++++++--------------- package-lock.json | 17 ++++++++++++++--- package.json | 3 ++- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/App.js b/App.js index 19cf752..f6492f8 100644 --- a/App.js +++ b/App.js @@ -8,16 +8,8 @@ // External dependencies import React from 'react'; -import { - Alert, - BackHandler, - Linking, - Platform, - StatusBar, - StyleSheet, - View, - WebView, -} from 'react-native'; +import { Alert, BackHandler, Linking, Platform, StatusBar, StyleSheet, View } from 'react-native'; +import { WebView } from 'react-native-webview'; import Constants from 'expo-constants'; import { Notifications } from 'expo'; @@ -276,12 +268,12 @@ export default class App extends React.Component { console.log('handleLoadEnd'); this.webView.injectJavaScript( // This is needed because we want to subscribe notifications only - // if user is authenticated window.postMessage accepts one - // argument, data, which will be available on the event object, - // event.nativeEvent.data. data must be a string. + // if user is authenticated window.ReactNativeWebView.postMessage + // accepts one argument, data, which will be available on the event + // object, event.nativeEvent.data. data must be a string. ` - if (window.user && window.user._id && typeof window.postMessage === 'function') { - window.postMessage('{ "action": "authenticated" }'); + if (window.user && window.user._id && typeof window.ReactNativeWebView.postMessage === 'function') { + window.ReactNativeWebView.postMessage('{ "action": "authenticated" }'); } ${this.appInfoJavaScript} ` diff --git a/package-lock.json b/package-lock.json index 3e7ecd3..40c3fca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3155,6 +3155,17 @@ "unimodules-permissions-interface": "~2.0.1", "unimodules-sensors-interface": "~2.0.1", "uuid-js": "^0.7.5" + }, + "dependencies": { + "react-native-webview": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-5.8.1.tgz", + "integrity": "sha512-b6pSvmjoiWtcz6YspggW02X+BRXJWuquHwkh37BRx1NMW1iwMZA31SnFQvTpPzWYYIb9WF/mRsy2nGtt9C6NIg==", + "requires": { + "escape-string-regexp": "1.0.5", + "invariant": "2.2.4" + } + } } }, "expo-ads-admob": { @@ -6639,9 +6650,9 @@ } }, "react-native-webview": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-5.8.1.tgz", - "integrity": "sha512-b6pSvmjoiWtcz6YspggW02X+BRXJWuquHwkh37BRx1NMW1iwMZA31SnFQvTpPzWYYIb9WF/mRsy2nGtt9C6NIg==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-5.8.2.tgz", + "integrity": "sha512-WvB5vH3xaxwXbk0RFGDIkM+MEeMfrfkhXdgYW1qj/xUuioeH5lduCpR+sID8+OR35zx+pBuamQ9jSlRGuREJrw==", "requires": { "escape-string-regexp": "1.0.5", "invariant": "2.2.4" diff --git a/package.json b/package.json index f67191b..f4289b3 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "react": "16.8.3", "react-dom": "^16.8.6", "react-native": "https://github.com/expo/react-native/archive/sdk-33.0.0.tar.gz", - "react-native-web": "^0.11.4" + "react-native-web": "^0.11.4", + "react-native-webview": "^5.8.2" }, "devDependencies": { "babel-preset-expo": "^5.1.1", From 2bbfdc7c565e8981ecdf2cea323e63641a5ac5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Str=C3=B6mkvist?= Date: Wed, 28 Aug 2019 23:30:20 +0200 Subject: [PATCH 2/3] Refactor injected JavaScript Create injected JavaScript in a single place and then inject it both as a WebView prop and with the `injectJavaScript`-method on `onLoadEnd`. This is preparatory for adding more injected JavaScript. --- App.js | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/App.js b/App.js index f6492f8..81affc4 100644 --- a/App.js +++ b/App.js @@ -70,8 +70,26 @@ export default class App extends React.Component { }); // JS injected to `WebView` - // Embedded website will change its functionality based on this. - appInfoJavaScript = 'window.trMobileApp=' + JSON.stringify(this.appInfo) + ';'; + injectedJavaScript = ` + function postMessage(message) { + if (window.ReactNativeWebView && typeof window.ReactNativeWebView.postMessage == 'function') { + window.ReactNativeWebView.postMessage(JSON.stringify(message)); + } else { + console.error("'window.ReactNativeWebView.postMessage' is not a function"); + } + } + + // This is needed because we want to subscribe notifications only + // if user is authenticated window.ReactNativeWebView.postMessage + // accepts one argument, data, which will be available on the event + // object, event.nativeEvent.data. data must be a string. + if (window.user && window.user._id) { + postMessage({ "action": "authenticated" }); + } + + // Embedded website will change its functionality based on this. + window.trMobileApp = ${JSON.stringify(this.appInfo)}; + `; componentWillMount() { // Subscribe to push notifications @@ -266,18 +284,7 @@ export default class App extends React.Component { // I.e. on each URL change _handleLoadEnd = () => { console.log('handleLoadEnd'); - this.webView.injectJavaScript( - // This is needed because we want to subscribe notifications only - // if user is authenticated window.ReactNativeWebView.postMessage - // accepts one argument, data, which will be available on the event - // object, event.nativeEvent.data. data must be a string. - ` - if (window.user && window.user._id && typeof window.ReactNativeWebView.postMessage === 'function') { - window.ReactNativeWebView.postMessage('{ "action": "authenticated" }'); - } - ${this.appInfoJavaScript} - ` - ); + this.webView.injectJavaScript(this.injectedJavaScript); }; _handleError = error => { @@ -303,7 +310,7 @@ export default class App extends React.Component { Date: Thu, 29 Aug 2019 13:42:47 +0200 Subject: [PATCH 3/3] [WIP] Open external links in external browser Opens external links present onLoadEnd in external browser, but doesn't yet handle the SPA-aspect of the site --- App.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/App.js b/App.js index 81affc4..b29083a 100644 --- a/App.js +++ b/App.js @@ -89,6 +89,22 @@ export default class App extends React.Component { // Embedded website will change its functionality based on this. window.trMobileApp = ${JSON.stringify(this.appInfo)}; + + // Open external websites in browser, not WebView + Array.from(document.querySelectorAll("a[href]")).forEach(link => { + if (link.origin === "${Settings.BASE_URL}") { + // Don't alter links on the Trustroots website + return; + } + + link.addEventListener("click", event => { + // Prevent opening link in current WebView + event.preventDefault(); + + // Message React Native, where we open it externally + postMessage({ action: "openUrl", url: link.href }); + }); + }); `; componentWillMount() {