0

Here is my code:

    const saveImg = async (base64Img: string, success: Function, fail:Function) => {
        const isAndroid = Platform.OS === "android"
        const isIos = Platform.OS === 'ios'

        const dirs = isIos? RNFS.LibraryDirectoryPath : RNFS.ExternalDirectoryPath;
        const certificateTitle = 'certificate-'+((Math.random() * 10000000) | 0)
        const downloadDest = `${dirs}/${certificateTitle}.png`;
        const imageDatas = base64Img.split('data:image/png;base64,');
        const imageData = imageDatas[1];

        try{
            await RNFetchBlob.config({
                addAndroidDownloads:{
                    notification:true,
                    description:'certificate',
                    mime:'image/png',
                    title:certificateTitle +'.png',
                    path:downloadDest
                }
            }).fs.writeFile(downloadDest, imageData, 'base64')
            if (isAndroid) {
              } else {
                RNFetchBlob.ios.previewDocument(downloadDest);
              }
            success()
        }catch(error:any){
            console.log(error)
            fail()
        }
    }

I get this error:

undefined is not an object (near '...}).fs.writeFile(downloadD...')
at node_modules/react-native-webview/lib/WebView.android.js:207:16 in _this.onMessage

When I hit the download button and this runs I get the mentioned Error. I use to get the download done with the below code modification, but I really need to show the download feedback from both android and IOS.

This works (but without notification)

await RNFetchBlob.fs.writeFile(downloadDest, imageData, 'base64')

I am using expo

  • `I get the mentioned Error` ,? You did not mention any error in your post. Please do. – blackapps Nov 29 '22 at 15:08
  • Why using RNFetchBlob when retrieving base64 ? You didn't call fetch you just define a request object. ```javascript RNFetchBlob.config({}).fetch("GET", "test.com", { }) ``` – Michael Bahl Nov 29 '22 at 15:44
  • @MichaelBahl I just need to convert the base64 string to image, download it and get the download manager notification, what's the best alternative ? – Robert Vitoriano Nov 29 '22 at 15:52
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Nov 30 '22 at 06:22

2 Answers2

1

I discovered that the react-fetch-blob does not work with expo, to solve it, I used the following libraries:

expo-file-system, expo-media-library, expo-image-picker,expo-notifications

This was the code to convert, download and show the notification of the image in the "expo way":

import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
import * as ImagePicker from 'expo-image-picker';
import * as Notifications from 'expo-notifications';

const saveImg = async (base64Img: string, success: Function, fail:Function) => {

    const imageDatas = base64Img.split('data:image/png;base64,');
    const imageData = imageDatas[1];

      try {
        const certificateName = 'certificate-'+((Math.random() * 10000000) | 0) + ".png"
        const certificatePathInFileSystem = FileSystem.documentDirectory +certificateName ;
        await FileSystem.writeAsStringAsync(certificatePathInFileSystem, imageData, {
          encoding: FileSystem.EncodingType.Base64,
        });
        await MediaLibrary.saveToLibraryAsync(certificatePathInFileSystem);

        Notifications.setNotificationHandler({
            handleNotification: async () => ({
              shouldShowAlert: true,
              shouldPlaySound: false,
              shouldSetBadge: true,

            }),
          });

        await Notifications.scheduleNotificationAsync({
            content: {
                title: certificateName +' saved !',
                body: "Click to show the certificate",
            },
            trigger: null,
          });
          setCertificatePath(certificatePathInFileSystem)
      success()
      } catch (e) {
        console.error(e);
      fail()
      }
}

In order to open the images gallery on click I used this code:

useEffect(()=>{
    if(certificatePath){
        Notifications.addNotificationResponseReceivedListener( async (event )=> {
            await ImagePicker.launchImageLibraryAsync({
                mediaTypes: ImagePicker.MediaTypeOptions.All,
                allowsEditing: true,
              })
        })
    }
},[certificatePath])
0
  1. Try to call fetch after create RNFetchBlob.config
  2. If you just wanna display an Image and not store you can show image as fallows (https://reactnative.dev/docs/next/images#uri-data-images)
<Image
  style={{
    width: 51,
    height: 51,
    resizeMode: 'contain'
  }}
  source={{
    uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg=='
  }}
/>

Call fetch on config object:

        try{
            const fetchConfig = await RNFetchBlob.config({
                addAndroidDownloads:{
                    notification:true,
                    description:'certificate',
                    mime:'image/png',
                    title:certificateTitle +'.png',
                    path:downloadDest
                }
            })
    fetchConfig.fetch('your.domain.com').fs.writeFile(downloadDest, imageData, 'base64')
            if (isAndroid) {
              } else {
                RNFetchBlob.ios.previewDocument(downloadDest);
              }
            success()
        }catch(error:any){
            console.log(error)
            fail()
        }
Michael Bahl
  • 2,941
  • 1
  • 13
  • 16