How can I download through WebView using react-native?

Viewed 13475

I'm using a WebView and I want to let the person download through the WebView. It's a simple WebView that have a link to download a zip file.

Can I do using the webview? (Like Chrome)

at least I want to get the listener when the user try to download the file though the WebView.

2 Answers

I did on this way, to download a file we need two steps, fetch the bits and create a file on device, in this example I'm downloading any .zip file when the url have a .zip:

I'm using :

import RNFetchBlob from 'rn-fetch-blob';
var RNFS = require('react-native-fs');

and using the WebView like this:

<WebView
    source={{ uri: "http://myinitialurl.com.br/arquivos/" }}
    style={{}}
    startInLoadingState={true}
    allowUniversalAccessFromFileURLs={true}
    javaScriptEnabled={true}
    mixedContentMode={'always'}
    onNavigationStateChange={(result) => this.handleUrlWithZip(result)}
/>

and:

handleUrlWithZip(input) {

    //check if have another download
    if (this.state.downloadStart == true || input.url.toLowerCase().includes('.zip') == false) {
      return;
    } else {
      this.setState({ downloadStart: true, showModalLoading: true })
    }

    const directoryFile = RNFS.ExternalStorageDirectoryPath + '/DownloadFile/';

    //Creating folder
    if (RNFS.exists(directoryFile)) {

      RNFS.unlink(directoryFile)
        .then(() => {
          console.log('FOLDER/FILE DELETED');
        })
        // `unlink` will throw an error, if the item to unlink does not exist
        .catch((err) => {
          console.log('CANT DELETE', err.message);
          this.setState({ showError: true })
        });

      RNFS.mkdir(directoryFile)
    }

    //If folder is created
    if (input) {
      //Verifing if the url have a .zip file
      if (input.url.toLowerCase().includes('.zip')) {
        const urlDownload = input.url;

        let fileName;
        try {
          fileName = urlDownload.substr(urlDownload.lastIndexOf('/')).replace('.zip', '') + '.zip';
        } catch (e) {
          console.log(e);
          fileName = 'example.zip'
        }

        console.log('URL = ' + urlDownload)

        //Downloading the file on a folder
        let dirs = directoryFile + '/' + fileName;
        RNFetchBlob
          .config({
            // response data will be saved to this path if it has access right.
            path: dirs
          })
          .fetch('GET', urlDownload, {
            //some headers ..
          })
          .progress((received, total) => {
            console.log('progress', received / total)
          })
          .then((res) => {
            // the path should be dirs.DocumentDir + 'path-to-file.anything'
            console.log('The file saved to ', res.path())

            //Acabou o download do arquivo
            this.setState({
              downloadStart: false, showModalLoading: false,
              showFileExplorer: true, startFolder: directoryFile
            })
          })
      }
    }
  }

There is aa drop-in replacement component for the original WebView https://github.com/react-native-community/react-native-webview which supports file downloads (and uploads) since December 2018.

All you need is to add the permissions to iOS by adding the following to ios/[project]/Info.plist:

<key>NSPhotoLibraryAddUsageDescription</key>
<string>Save pictures for certain activities.</string>

or for Android by adding this to the AndroidManifest.xml

<!-- this is required to save files on Android  -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Related