21

I'm trying to load .html, .js, .css files from device's local file system into React Native WebView component. I was able to get the path to the index.html file but specifying this as the url for the WebView simply throws an error. How would I go about this? Please help!

Manu Gupta
  • 351
  • 1
  • 5
  • 18
Wonil Suh
  • 1,041
  • 2
  • 9
  • 8

5 Answers5

16

In react native it is now possible to require an HTML file and use it as the source for the web view like this (the path is relative to the react-native file you use it in):

const webapp = require('./webapp/index.html');

and the use it in the WebView like this:

<WebView source={webapp} />

Unfortunately this does not load CSS and JavaScript files, that are referenced in the HTML. A solution could be, to write all the CSS and JS inline (e.g. by using a build process).

David Hellsing
  • 106,495
  • 44
  • 176
  • 212
Rias
  • 1,956
  • 22
  • 33
  • 5
    The above snippet works great on iOS. But on Android, it doesn't work on release build but works during development. Any idea why so? – varunvs May 09 '16 at 02:01
  • Actually I don't have an idea. I would expect it to be working on Android as well. – Rias May 09 '16 at 07:58
  • 1
    @varunvs did you find out why its not working on android in release mode? – Martin Mlostek Oct 14 '16 at 10:26
  • 1
    There's a bug logged on Github for this issue but closed - https://github.com/facebook/react-native/issues/505 A workaround is to put HTML files in Android assets directory. You can then import it by using source prop of webview. eg: `source={{ uri: 'file:///android_asset/index.html' }}` You can check the comments in the Github thread to get more details. – varunvs Oct 16 '16 at 09:00
  • @varunvs That solution on github is not working either, on Android. – SoundStage May 05 '17 at 10:56
  • that might help: https://github.com/facebook/react-native/issues/505#issuecomment-244463151 – four-eyes Sep 22 '17 at 07:58
  • in case you decide to use inline js css, this will make your life easy: https://www.npmjs.com/package/html-inline – talsibony Oct 19 '17 at 10:33
9

I was able to include html5/javascript into project by using { html: , baseUrl: } as source. But to be frank, it's more like a lucky shot.

<WebView source={{ html: HTML, baseUrl: 'web/' }} />

I have index.html, which require pano2vr_player.js and pano.xml to make this code work.

const HTML = `
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <title></title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black" />
  <meta name="mobile-web-app-capable" content="yes" />
  <style type="text/css" title="Default">
   body, div, h1, h2, h3, span, p {
    font-family: Verdana,Arial,Helvetica,sans-serif;
   }
    </style>
 </head>
 <body>
  <script type="text/javascript" src="pano2vr_player.js">
  </script>
  <div id="container" style="width:100%;height:100%;">
  <br>Loading...<br><br>
  This content requires HTML5 with CSS3 3D Transforms or WebGL.
    </div>
  <script type="text/javascript">
   // create the panorama player with the container
   pano=new pano2vrPlayer("container");
    window.addEventListener("load", function() {
     pano.readConfigUrlAsync("pano.xml");
    });
  </script>
 </body>
</html>`;

class PanoView extends Component {

  render() {
    return (
      <View>
        <WebView
          style={{ flex: 1, width: 1024, height: 768 }}
          source={{ html: HTML, baseUrl: 'web/' }}
          javaScriptEnabledAndroid={true} />
      </View>
    );
  }
}

And finally add files/folder ('/web' same as baseUrl) to XCode project

enter image description here

And it works! But I'm not sure how...

Doppio
  • 2,018
  • 12
  • 11
5

I stumbled upon the same issue and, after running in circles for hours trying all sorts of solutions, I finally solved it by following this tutorial. Major kudos to the author.

In the article there's some extra info which is a bit outdated, so here's the concise version instead:

  • create a folder in your main project root (e.g. /html);
  • put all of your files in a folder (e.g. Web, with index.html being your WebView entrypoint), give it a .bundle extension (e.g. Web.bundle), and place it into /html;

Now you have to add these files to the project so they are recognized and bundled together in your next build, this process is done differently in iOS and Android:

  • iOS: open your project in Xcode, drag n drop Web.bundle into the project's main folder, and confirm the dialog with the "Copy items if needed" option left unchecked;
  • Android: open /android/app/build.gradle and add:
android {
  ...
  sourceSets { 
    main { assets.srcDirs = ['src/main/assets', '../../html'] } 
  }
}

Now rebuild your project from scratch to have your changes take effect.

In your WebView file, calculate the path to index.html and feed it to the WebView:

const sourceUri = (Platform.OS === 'android' ? 'file:///android_asset/' : '')
    + 'Web.bundle/index.html';

return (
  <WebView
    source={{ uri: sourceUri }}
    originWhitelist={['*']}
    javaScriptEnabled={true}
    allowFileAccess={true}
  />
);

This will load your index.html and all of its js and css files, as long as they're included in the bundle.

apgsn
  • 681
  • 8
  • 17
3

You may have to wrap your own Native Module to do this. React Native's WebView uses UIWebView, for info on loading a local file take a look here: https://gist.github.com/amster/9160860

However it is recommended you use WKWebView, you can wrap one yourself relatively easily. There is currently a repo that is WIP: https://github.com/qrush/react-native-wkwebview

Accomplishing loading local resources using WKWebView can be found in this answer: https://stackoverflow.com/a/28676439/398136

Community
  • 1
  • 1
stan229
  • 2,592
  • 19
  • 23
0

Place this script in any file of ReactNative or your code, recomended to first or top index file. And it will fix problem, tested on RN0.39

import { Platform } from 'react-native';
import { setCustomSourceTransformer } from 'react-native/Libraries/Image/resolveAssetSource';

setCustomSourceTransformer(function (resolver) {

  if (Platform.OS === 'android'
    && !resolver.serverUrl
    && !resolver.bundlePath
    && resolver.asset.type === 'html') {
    resolver.bundlePath = '/android_asset/';
  }

  return resolver.defaultAsset();
});
dryymoon
  • 131
  • 1
  • 4