├── .babelrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── package.json ├── src ├── inject-post-message.js └── react-native-web-view.js ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "@babel/preset-env", "@babel/preset-react" ], 3 | "plugins": [ 4 | "@babel/plugin-proposal-class-properties", 5 | "@babel/plugin-proposal-object-rest-spread" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.git 2 | /node_modules 3 | /index.js 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.git 2 | /node_modules 3 | /src 4 | /.babelrc 5 | /.gitignore 6 | /.npmignore 7 | /.travis.yml 8 | /webpack.config.js 9 | /yarn.lock 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 8.9.1 3 | branches: 4 | only: master 5 | cache: yarn 6 | install: yarn 7 | script: 8 | - yarn build 9 | - yarn test 10 | deploy: 11 | api_key: 12 | secure: lqYgY7yPzK3vc7+sK522cOxIEflfE89ikjzcEA4165iNNXgNG1NSNavSdj/6qnxHoCuiEC1I2zZjln3rPhrN0rJqvJcvjK/B5f90aLEJMXZCglmMW88QnsV6xhhqOrgATa/AV1fh9Q3Bhe/Fg+2kj61BSe5U3qJ3rPNhqxOG1SuJLBuWy3IP41kDsSEIYvG9yTWUq3b+tAN6rs2oqm8GhyTFv6tk5VpcQUo5pMyMfhLlfOOT9IlbnB5rO3n2EFAG+XXzgB3X49ZxuTpWdnqzJigAij3trV6m1jo2jSI7nKAYz8gQJqEBwI7S5b962twJAUcEpgP1/a//dfB0n6JLNz6SOyXrFcRcgjm0E8+RxbhZEYVtceo5bkD1+E+W3tDoM4yeTR49vxsj+6jeuy3JLbzzgAFTMk09x7ksqZUKnqjay91bloNu0N6ly8jUtV+uI4CucwalWjtACtyKGoB6FbJau3Y7rlnGaaHBDdUQjzVTBzQh6kuGaSHQ0/as6pDUrkpzjJ8HNtebMS9SST0aBK9lFn5lCNJwrE5N6DYjvItpuhgD4P8w454f69yygDpQpJjByiIqBvzcLavAnQdlceBJ6mKgurdcA3qb0whCjMlM+bECUjtHrym8ODMVFKMDyM4TJzRzOktoCKUNTky3xUfYb8NLI81qcQA/VvhuvwE= 13 | email: npmjs@charlesstover.com 14 | on: 15 | branch: master 16 | provider: npm 17 | skip_cleanup: true 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Charles Stover 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native WebView [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Trouble%20using%20postMessage%20in%20React%20Native%20on%20iOS?%20The%20rn-webvie%20package%20fixes%20this!&url=https://github.com/CharlesStover/react-native-web-view&via=CharlesStover&hashtags=react,reactjs,iosdev,javascript,mobileapp,mobileappdevelopment,mobiledev,webdev,webdeveloper,webdevelopment) 2 | 3 | An implementation of React Native's WebView that allows for `window.postMessage` on iOS devices. 4 | 5 | [![version](https://img.shields.io/npm/v/rn-webview.svg)](https://www.npmjs.com/package/rn-webview) 6 | [![minified size](https://img.shields.io/bundlephobia/min/rn-webview.svg)](https://www.npmjs.com/package/rn-webview) 7 | [![minzipped size](https://img.shields.io/bundlephobia/minzip/rn-webview.svg)](https://www.npmjs.com/package/rn-webview) 8 | [![downloads](https://img.shields.io/npm/dt/rn-webview.svg)](https://www.npmjs.com/package/rn-webview) 9 | [![build](https://travis-ci.com/CharlesStover/react-native-web-view.svg)](https://travis-ci.com/CharlesStover/react-native-web-view/) 10 | 11 | ## Install 12 | 13 | * `npm install rn-webview --save` or 14 | * `yarn add rn-webview` 15 | 16 | ## Use 17 | 18 | Instead of `import { WebView } from 'react-native'`, simply `import WebView from 'rn-webview'`. 19 | Then continue to use `` just like you would the React Native implementation. 20 | 21 | ## Sponsor 💗 22 | 23 | If you are a fan of this project, you may 24 | [become a sponsor](https://github.com/sponsors/CharlesStover) 25 | via GitHub's Sponsors Program. 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rn-webview", 3 | "version": "0.1.0", 4 | "author": "Charles Stover ", 5 | "bugs": { 6 | "url": "https://github.com/CharlesStover/react-native-web-view/issues" 7 | }, 8 | "description": "An implementation of React Native's WebView that allows for window.postMessage on iOS devices.", 9 | "devDependencies": { 10 | "@babel/core": "^7.0.0-beta.56", 11 | "@babel/plugin-proposal-class-properties": "^7.0.0-beta.56", 12 | "@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.56", 13 | "@babel/preset-env": "^7.0.0-beta.56", 14 | "@babel/preset-react": "^7.0.0-beta.56", 15 | "babel-core": "7.0.0-bridge.0", 16 | "babel-loader": "^8.0.0-beta.4", 17 | "react": "^16.3.1", 18 | "react-native": "https://github.com/expo/react-native/archive/sdk-28.0.0.tar.gz", 19 | "webpack": "^4.16.4", 20 | "webpack-cli": "^3.1.0" 21 | }, 22 | "homepage": "https://github.com/CharlesStover/react-native-web-view#readme", 23 | "keywords": [ 24 | "react", 25 | "reactjs", 26 | "react-native", 27 | "reactnative" 28 | ], 29 | "license": "MIT", 30 | "main": "index.js", 31 | "peerDependencies": { 32 | "react": "^16.3.1", 33 | "react-native": "https://github.com/expo/react-native/archive/sdk-28.0.0.tar.gz" 34 | }, 35 | "repository": { 36 | "type": "git", 37 | "url": "git+https://github.com/CharlesStover/react-native-web-view.git" 38 | }, 39 | "scripts": { 40 | "build": "webpack", 41 | "dev": "set NODE_ENV=development && webpack", 42 | "prepublishOnly": "npm run build", 43 | "test": "echo \"No test.\"" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/inject-post-message.js: -------------------------------------------------------------------------------- 1 | // Custom postMessage handler to inject into the Web View. 2 | export default ` 3 | (function() { 4 | var EMPTY_STATE = Object.create(null); 5 | var escape = function(str) { 6 | return str.replace(/'/g, '\\\\\''); 7 | }; 8 | var postMessage = window.postMessage; 9 | window.postMessage = function() { 10 | if (postMessage) { 11 | postMessage.apply(window, arguments); 12 | } 13 | history.pushState( 14 | EMPTY_STATE, 15 | document.title, 16 | location.href + 17 | '#window.postMessage(\\\'' + 18 | escape(arguments[0]) + 19 | '\\\')' 20 | ); 21 | }; 22 | })(); 23 | `; 24 | -------------------------------------------------------------------------------- /src/react-native-web-view.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { WebView } from 'react-native'; 3 | import injectPostMessage from './inject-post-message'; 4 | 5 | const unescape = str => 6 | str.replace(/\\'/g, '\''); 7 | 8 | class WebViewPostMessage extends React.PureComponent { 9 | 10 | handleNavigationStateChange = e => { 11 | 12 | // If this navigation state contains a message to post, post it. 13 | const postMessage = e.url.match(/\#window\.postMessage\('(.+)'\)$/); 14 | if (postMessage) { 15 | if ( 16 | e.loading && 17 | this.props.onMessage 18 | ) { 19 | this.props.onMessage({ 20 | nativeEvent: { 21 | data: unescape(postMessage[1]) 22 | } 23 | }); 24 | } 25 | return; 26 | } 27 | 28 | // If this navigation state has completed, listen for messages. 29 | if ( 30 | !e.loading && 31 | this.ref 32 | ) { 33 | this.ref.injectJavaScript(injectPostMessage); 34 | } 35 | 36 | // If a navigation state change event handler was passed, call it. 37 | if (this.props.onNavigationStateChange) { 38 | return this.props.onNavigationStateChange(e); 39 | } 40 | return; 41 | }; 42 | 43 | // Grab the WebView ref for injecting JavaScript. 44 | handleRef = ref => { 45 | this.ref = ref; 46 | 47 | // If the caller also wants this ref, pass it along to them as well. 48 | if (this.props.forwardedRef) { 49 | this.props.forwardedRef(ref); 50 | } 51 | }; 52 | 53 | render() { 54 | 55 | // Do not send onMessage to the React Native WebView, since it is not supported on iOS. 56 | const props = {...this.props}; 57 | delete props.forwardedRef; 58 | delete props.onMessage; 59 | 60 | return ( 61 | 66 | ); 67 | } 68 | } 69 | 70 | // Export a component that allows refs to be forwarded, in case the user wants access to the WebView. 71 | export default React.forwardRef((props, ref) => 72 | 76 | ); 77 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const NODE_ENV = 4 | process.env.NODE_ENV ? 5 | process.env.NODE_ENV.trim() : 6 | 'production'; 7 | 8 | module.exports = { 9 | entry: './src/react-native-web-view.js', 10 | externals: [ 11 | { 12 | 'react': { 13 | amd: 'react', 14 | commonjs: 'react', 15 | commonjs2: 'react', 16 | root: 'React' 17 | } 18 | }, 19 | 'react-native' 20 | ], 21 | mode: NODE_ENV, 22 | module: { 23 | rules: [ 24 | 25 | // JavaScript 26 | { 27 | test: /\.js$/, 28 | use: { 29 | loader: 'babel-loader' 30 | } 31 | } 32 | ] 33 | }, 34 | output: { 35 | filename: 'index.js', 36 | library: 'react-native-web-view', 37 | libraryTarget: 'umd', 38 | path: path.resolve(__dirname, '.'), 39 | umdNamedDefine: true 40 | }, 41 | resolve: { 42 | alias: { 43 | 'react': path.resolve(__dirname, './node_modules/react'), 44 | 'react-native': path.resolve(__dirname, './node_modules/react-native') 45 | } 46 | }, 47 | watch: NODE_ENV === 'development' 48 | }; 49 | --------------------------------------------------------------------------------