Reputation: 3387
I try to load the local .html
file into WebView
in React Native:
// load local .html file
const PolicyHTML = require('./Policy.html');
// PolicyHTML is just a number of `1`
console.log('PolicyHTML:', PolicyHTML);
// will cause an error: JSON value '1' of type NSNumber cannot be converted to NSString
<WebView html={PolicyHTML} />
The .html
file should be read as a string, not as a resource representative.
How can I load the .html
file into WebView
in React Native?
By the way, what is the type of those resource representatives from require()
? Is it number
?
Upvotes: 50
Views: 88343
Reputation: 129
If you're working with assets, project directories is different on the device's directory once the project is build and you can't simply reference them via string url.
If using expo, you have to require
every asset then use useAssets
on the require to cache them to the local storage of the device.
useAssets
will return an object that contains a localUri
(this is the uri of the image that has been cached)
you can then use the localUri
and put it as the src
of the image
import { useAssets } from 'expo-asset';
/* . . . */
const IndexHTML = require('./assets/index.html');
const myImage = require('./assets/splash.png');
// url link after image is cached to the device
const [imgSrc, setImgSrc] = useState('');
const [image, imerr] = useAssets(myImage);
const [html, error] = useAssets(IndexHTML);
const webViewProps = {
javaScriptEnabled: true,
androidLayerType: 'hardware',
originWhitelist: ['*'],
allowFileAccess: true,
domStorageEnabled: true,
mixedContentMode: 'always',
allowUniversalAccessFromFileURLs: true,
onLoad: () => {
console.log(image[0].localUri);
setImgSrc(image[0].localUri);
},
source: {
html: '<img src="' + imgSrc + '"/>',
},
};
return <WebView {...webViewProps} />
const webViewProps = {
...
source: IndexHTML,
};
Note: for the expo apporach, files referenced in IndexHTML will not be found
The trick is to turn your html into a string literal
to utilize template strings.
Then you have to manually require each of those assets to concatenate localUrl
require()
has limited types supported and you need to add a metro.config.js
in your root folder.
it will give errors if you require()
a .js
file since it reads it as a module rather, the workaround approach would be to bundle your assets
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
config.resolver.assetExts.push(
// Adds support for asset file types
'css', 'ppt', 'obj'
);
module.exports = config;
If you have the android
folder in your directory, navigate to
android > app > build.gradle
then add
android {
/* link assets to the local storage of device */
sourceSets {
main { assets.srcDirs = ['src/main/assets', '../../source/assets/'] }
// [do not touch, 'relative to your asset'] }
}
. . .
finally, the relative folder you linked in gradle can be accessed through
file:///android_asset/
for ex. file:///android_asset/index.html
-> /asset/index.html
return <WebView source={{uri: `file:///android_asset/index.html`}} />
For IOS, here's how
On the other hand, you have to rebuild vanilla react to see the changes in the assets.. which takes about 20 minutes or so
A quick solution would be to integrate a static server, but this is a recent fork of the react-native-static-server
that only works in vanilla react native.
Upvotes: 4
Reputation: 138
With Expo tools and generally using Expo:
import { WebView } from "react-native-webview";
import { readAsStringAsync } from "expo-file-system";
import { useAssets } from "expo-asset";
export const MusicSheet = () => {
const [index, indexLoadingError] = useAssets(
require("../assets/musicsheetview/index.html")
);
const [html, setHtml] = useState("");
if (index) {
readAsStringAsync(index[0].localUri).then((data) => {
setHtml(data);
});
}
return (
<View style={styles.container}>
<WebView
onLoad={() => {}}
source={{ html }}
onMessage={(event) => {}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
height: 100,
display: "flex",
},
});
Upvotes: 4
Reputation: 6352
If you need to serve local assets as well, then:
put all assets together with index.html
into android/app/src/main/assets/www
(You can copy them there with gradle task)
Then:
var uri = Platform.OS == "android" ?
"file:///android_asset/www/index.html" :
"./web/www/index.html"
return <WebView source={{ uri }} />
** For iOS didn't tested, please add instruction, how assets should be stored
Upvotes: 2
Reputation: 21520
I come across this post searching for loading static html.
If your html code is retrieved using, for example, an API, you can render WebView in this way:
<WebView
originWhitelist={['*']}
source={{ html: html, baseUrl: '' }}
/>
Notice that originWhitelist
is required as explained in the documentation:
Note that static html will require setting of originWhitelist for example to ["*"].
Upvotes: 17
Reputation: 101
<View style={{flex: 1}}>
<WebView
style={{flex: 1}}
source={require("./resources/index.html")}
/>
</View>
To make WebView, the parent has to has a dimension or flex:1. We could set the WebView to flex: 1 too so that it fills up the parent.
Upvotes: 8
Reputation: 27
Try this :
Write such lines of code in the file where you want to use WebView Component
const OurStoryHTML = require ('./OurStory.html')
<WebView
source={OurStoryHTML}
style={{flex: 1, marginTop : 44}}
/>
It may help you.
Upvotes: 0
Reputation: 532
try it:
const PolicyHTML = require('./Policy.html');
<WebView
source={PolicyHTML}
style={{flex: 1}}
/>
Upvotes: 50