Reputation: 10226
I've read a tonne of posts about this problem, most of them old so I'm creating a new posting good as of React Native v0.61.5
my problem: I'm retrieving a web page and the files it references, writing them to the app's Documents folder, and attempting to load these into a WebView. These events occur when the user clicks on a button and set the state appropriately
here's how I'm indicating the WebView:
<WebView
source={{html: this.state.html, baseUrl: this.state.baseUrl}}
originWhitelist={['*']}
allowFileAccessFromFileURLs
allowFileAccess={true}
/>
and the content of the file. Please note that the logo resides in the same directory as the file that references it:
<h1>per aspera ad astra</h1>
<img src="logo.jpg"/>
the problem I'm having is that I can't see the image. it appears as a small blue image of a question mark. if I look at the baseUrl
, it's set to:
file:///Users/ekkis/Library/Developer/CoreSimulator/Devices/9F96B01B-3C66-4ABA-96A5-B58049FB9212/data/Containers/Data/Application/735BD192-FC7B-4708-9973-64C3C9953A0D/Documents
...which seems correct. I'm running this on iOS
I have also tried (as suggested elsewhere):
source={require(this.state.uri)}
but this fails (I get the error: "Error: TransformError App.js: App.js:Invalid call at line 62:require(this.state.uri)". it makes little sense as require cannot read HTML files but maybe there's supposed to be some black magic there that just isn't working for me. I've also tried simply setting the uri
but it also doesn't work (and I can't set the baseUrl
in that case)
I'm sure someone out there has done this. it's a base case for this component. I look forward to any guidance
Upvotes: 6
Views: 1905
Reputation: 3813
Below is a working example of using a file within a webview for iOS. It uses the react-native-fs
npm package to download a file locally using the imageUrl
variable to define what image is downloaded. The URL I used for the example points to a nature photo of a creek.
The following example allows for all images within the folder specified by baseFolderPath
as well as within any nested folders.
It may be prudent to keep the same file extension between imageUrl
and imageLocalPath
variables.
import React, { useState, useEffect } from 'react';
import { Text } from 'react-native';
import { WebView } from 'react-native-webview';
import * as RNFS from 'react-native-fs';
const { DocumentDirectoryPath } = RNFS;
const getFolder = filepath => filepath.split('/').slice(0, -1).join('/');
const ensureFolderExists = folderPath => RNFS.mkdir(folderPath + '/', { NSURLIsExcludedFromBackupKey: true });
const writeFile = async (filepath, content, encoding = 'utf8') => {
await ensureFolderExists(getFolder(filepath));
await RNFS.writeFile(filepath, content, encoding);
};
const downloadFile = async (fileUrl, destinationPath) => {
await ensureFolderExists(getFolder(destinationPath));
await RNFS.downloadFile({
fromUrl: fileUrl,
toFile: destinationPath,
headers: {},
}).promise;
return destinationPath;
};
export default () => {
const baseLocalPath = `${RNFS.DocumentDirectoryPath}/myFolder`;
const htmlLocalPath = `${baseLocalPath}/webview.html`;
const imageLocalPath = `${baseLocalPath}/images/myImage.jpg`;
const imageUrl = `https://images.pexels.com/photos/3225517/pexels-photo-3225517.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2`;
const html = `<html><body><img src="${imageLocalPath}" style="width: 100%;height:100%;"></body></html>`;
const [imageDownloaded, setImageDownloaded] = useState(false);
const [htmlFileWritten, setHtmlFileWritten] = useState(false);
useEffect(() => {
writeFile(htmlLocalPath, html).then(() => setHtmlFileWritten(true));
downloadFile(imageUrl, imageLocalPath).then(() => setImageDownloaded(true));
}, []);
return (
(htmlFileWritten && imageDownloaded) ? (
<WebView
originWhitelist={['*']}
allowFileAccessFromFileURLs={true}
allowUniversalAccessFromFileURLs={true}
allowingReadAccessToURL={baseLocalPath}
source={{ uri: htmlLocalPath }}
/>
) : <Text>Loading</Text>
);
};
Upvotes: 1