react native webview load from device local file system
Asked Answered
R

5

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!

Reactance answered 3/11, 2015 at 18:54 Comment(0)
P
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).

Pithos answered 5/3, 2016 at 15:57 Comment(7)
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?Rooke
Actually I don't have an idea. I would expect it to be working on Android as well.Pithos
@Rooke did you find out why its not working on android in release mode?Luciusluck
There's a bug logged on Github for this issue but closed - 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.Rooke
@Rooke That solution on github is not working either, on Android.Imprison
that might help: github.com/facebook/react-native/issues/…Godden
in case you decide to use inline js css, this will make your life easy: npmjs.com/package/html-inlineClarinda
W
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...

Went answered 16/10, 2016 at 4:14 Comment(0)
H
7

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.

Hypnoanalysis answered 29/6, 2020 at 17:15 Comment(0)
K
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://mcmap.net/q/173706/-wkwebview-not-loading-local-files-under-ios-8

Keel answered 4/11, 2015 at 22:54 Comment(0)
T
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();
});
Talmudist answered 18/1, 2017 at 13:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.