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

2

There are 2 best solutions below

0
On BEST ANSWER

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
On
  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()
        }