react-native-share: [Android] Unable to share files - "Request contained no data"

Steps to reproduce

  1. Create file using react-native-fs (.csv)
  2. Use the path from react-native-fs as the url (file:// + $path)
  3. Share.open({url: pathWithFilePrefix, title: "MyData.csv"})
  4. Share to Google Disk

Expected behaviour

File to be exported/uploaded

Actual behaviour

image

Environment

  • React Native version: 0.59.9
  • React Native platform + platform version: Android 9? (Api 28)

react-native-share

Version: 1.2.1

Full code:

exportCsv = async () => {
    let data = this.getCsvData();
    var path = RNFS.DocumentDirectoryPath + "/MyData.csv"; 

    // path = "/data/user/0/com.myApp/files/MyData.csv"

    try {
      RNFS.writeFile(path, data, "utf8");
    } catch (err) {
      Alert.alert("Export failed", "Failed to write file to disk");
      return;
    }

    try {
      let editedPath = "file://" + path;
      await Share.open({
        url: editedPath,
        type: "text/csv",
        title: "MyData.csv"
      });
    } catch (err) {
      // Fall trough
    }

    try {
      await RNFS.unlink(path);
    } catch (err) {
      console.log("Unable to delete locally stored file", err);
    }
  };

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 28 (4 by maintainers)

Most upvoted comments

I finally made it work, I was simply missing a FileProvider implementation. The documentation could be more explicit about that.

@MateusAndrade - Yes, got it working using the following code, which seems to be doing the same thing as @bojanmitevski (This is what triggered #521 , which has been resolved) But the issue still exists (not beeing able to use file:// or a common API), even tho there is a workaround for it. I believe if there should be a workaround, it should be in the library (automatically loading file based on base64 when using file://) - or the library should mention this in the documentation.

      try {
        const content = await RNFS.readFile(path, "base64");
        Share.open({
          url: "data:text/comma-separated-values;base64," + content
        });
      } catch (err) {
        console.log("Failed to get base64");
      }

this is work for me。but,How to set the XLS file type?text/xls ??

I finally solved the problem of android sharing excel files.Here is the full code。

import XLSX from 'xlsx'
import {
    writeFile,
    readFile,
    unlink,
    DocumentDirectoryPath,
    ExternalDirectoryPath,
} from 'react-native-fs'
import { Platform } from 'react-native'
import { Toast } from '@ant-design/react-native'
import Share from 'react-native-share';


/**
 * excel
 * @param data
 * @param fileName
 */
const exportExcel = (data: Array, fileName: string) => {
    let ipt = new Promise(function(resolve, reject) {
        try {
            const output = str => str
            const path = Platform.select({
                ios: `${DocumentDirectoryPath}/`,
                android: `${ExternalDirectoryPath}/`
            })
            const fileType = 'xls'
            if (data && data.length > 0) {
                let ws = XLSX.utils.aoa_to_sheet(data)
                let wb = XLSX.utils.book_new()
                XLSX.utils.book_append_sheet(wb, ws, fileName)
                const wbout = XLSX.write(wb, {
                    type: 'base64',
                    bookType: fileType
                })
                const file = `${path}${fileName}.${fileType}`
                writeFile(file, output(wbout), 'base64')
                    .then(res => {
                        console.log(file)
                        wxShareFile(fileName, file, resolve, reject)
                        // resolve(file)
                    })
                    .catch(err => {
                        Toast.fail(err)
                        console.log(err)
                        reject(err)
                    })
            } else {
                alert('没有可分享的数据')
            }
        } catch (e) {
            console.log(e)
            reject(e)
        }
    })

    return ipt
}

const wxShareFile = async (fileName, filePath, resolve, reject) => {
    readFile(filePath,"base64").then((res)=>{
       console.log(res)
//You can search for MIME Types using Google to find the corresponding Types of files
// something like it : .xls->application/vnd.ms-excel .Xml-> text/ xml .zip-> application/ x-zip .mp3-> audio/x-mpeg-3.
        const dataUri = `data:application/vnd.ms-excel;base64,${res}`;
         Share.open({
            url: dataUri,
        });
         // unlink(path);

    })

}



export { exportExcel }

I managed to solve this issue by passing the pdf file path to the url param from sharing options. sharePDf = async (pdfPath) => { //Be sure that PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE is already granted const shareOptions = {

    url: 'file://'+pdfPath,
    mimeType: 'application/pdf',
    title: 'Pdf test'
    };

Platform.OS === ‘ios’ ?
Share.open(shareOptions) : this.sharePDFWithAndroid(pdfPath, ‘application/pdf’); }

My share function for android is :

sharePDFWithAndroid(pdfPath, type) { const { fs, fetch, wrap } = RNFetchBlob; RNFetchBlob.fs.readFile(pdfPath, ‘base64’).then( base64Data => { base64Data = data:${type};base64, + base64Data; Share.open({ url: base64Data }); }); }

After a lot of research, I found out that only base64 data for pdf file can be shared using react-native-share. Is not possible to share using url with “file://…pdfPath…”.

I hope that someone will find this helpfull.

@MateusAndrade - Yes, got it working using the following code, which seems to be doing the same thing as @bojanmitevski (This is what triggered #521 , which has been resolved)

But the issue still exists (not beeing able to use file:// or a common API), even tho there is a workaround for it. I believe if there should be a workaround, it should be in the library (automatically loading file based on base64 when using file://) - or the library should mention this in the documentation.

      try {
        const content = await RNFS.readFile(path, "base64");
        Share.open({
          url: "data:text/comma-separated-values;base64," + content
        });
      } catch (err) {
        console.log("Failed to get base64");
      }

I don’t think it’s possible to share base64 using file:// approach.

True, this is the workaround 😃

I created a repository that showcases this error in its simplest form.

https://github.com/Cnordbo/RNShare-reproduction-of-extension-error

Im unfamiliar with how to debug this in android studio / java, but I’m looking into it, will try to help out the best I can, but this is currently beyond my knowledge.

This also includes the suggested fix by @MateusAndrade without success.

I will try giving a look at the repo this week. Thanks for sharing your example. 😄

I created a repository that showcases this error in its simplest form.

https://github.com/Cnordbo/RNShare-reproduction-of-extension-error

Im unfamiliar with how to debug this in android studio / java, but I’m looking into it, will try to help out the best I can, but this is currently beyond my knowledge.

This also includes the suggested fix by @MateusAndrade without success.

I am starting to think that the example app needs a specific example for each provider and each type of share (image, text, with title etc). Not to complicate things (though it would at first), but so the community could share - in a functional way - how each one works since they seem to have so many differences (like you can do this for whatsapp on android, but not ios)…

Maybe a dropdown of providers and then a bunch of tick-boxes / text entries for how to share it (tick box for title, and enter it here, tick box for content and enter it here, or tick this box to include this sample image) etc.

Could still be just a single App.js but would expose all these differences.

Because my hunch is that google drive just has a quirk.

@mikehardy this looks related to #517 .

@Cnordbo you can try removing title and/or type?