3

I've been hitting my head on the screen for some time and just can't get it to work despite all the information I've found on git or stackoverflow.

What I'm trying to achieve:

Persistence of the images selected (from library or camera). Persistence also when I rebuild my app, which means when I run react-native run-ios for iOS, or react-native run-android for Android.

What I've implemented

Here is my function that is called when I add an image.

ImagePicker.showImagePicker({
   storageOptions: {
      path: 'myCustomPath',
      waitUntilSaved: true,
      cameraRoll: true,
      skipBackup : true
   },
   noData: true
}, res => {
   if (res.didCancel) {
      console.log("User cancelled");
   } else if (res.error) {
      console.log("Error", res.error);
   } else {
      console.log("Picker Response:", res);
      // Getting the fileName as for iOS the fileName is incorrect even with waitUntilSaved to true.
      const path = res.uri.split("/");
      const fileName = path[path.length-1]; 
      let uri = "file://" + Platform.select({
         android: RNFS.ExternalStorageDirectoryPath + "/Pictures/",
         ios: RNFS.DocumentDirectoryPath+"/"
         })
         + "myCustomPath/" + fileName

      this.setState({
         pickedImage: {
            uri: uri,
         }
      });
      this.props.onImagePicked({ uri: res.uri }); 
   }
});

And in my home page, I display the image in <Thumbnail square style={{width:50, height:50}} source={info.item.image} />

---- EDIT START ----- ---- SOLUTION ----

The solution was to reconstruct the path where I want to display the image using the fileName: <Thumbnail square style={{width:50, height:50}} source={{uri : RNFS.DocumentDirectoryPath+"/"+info.item.image.fileName}} />

---- EDIT ENDS -----

The Result

So here are the results, you'll see works well on Android, but not on iOS. I selected an image on the library using the react-native-image-picker.

Android

"Picker Response":

fileName: "image-d53839d1-fa89-4a61-b648-f74dace53f83.jpg"
fileSize: 235728
height: 1440
isVertical: true
originalRotation: 0
path: "/storage/emulated/0/Pictures/myCustomPath/image-d53839d1-fa89-4a61-b648-f74dace53f83.jpg"
type: "image/jpeg"
uri: "file:///storage/emulated/0/Pictures/myCustomPath/image-d53839d1-fa89-4a61-b648-f74dace53f83.jpg"
width: 1080

the save "uri" for my image is : file:///storage/emulated/0/Pictures/myCustomPath/image-d53839d1-fa89-4a61-b648-f74dace53f83.jpg

Behavior is as below :

  • left screenshot is after saving my image,
  • right screenshot is after a rebuild, opening the app, I still see my image!

--> Happy!

enter image description here enter image description here

Now on iOS

"Picker Response" :

fileName: "IMG_0004.JPG"
fileSize: 470300
height: 1618
isVertical: true
latitude: 64.752895
longitude: -14.538611666666666
origURL: "assets-library://asset/asset.JPG?id=99D53A1F-FEEF-40E1-8BB3-7DD55A43C8B7&ext=JPG"
timestamp: "2012-08-08T21:29:49Z"
type: "image/jpeg"
uri: "file:///Users/[name]/Library/Developer/CoreSimulator/Devices/33076AD2-C989-47E9-A803-3E56CC4B09D6/data/Containers/Data/Application/4756F0A2-9CCC-4F9A-9315-D55434328FD9/Documents/myCustomPath/6A5C27E3-89F7-465F-A855-66749C92D086.jpg"
width: 1080

the save "uri" for my image is : file:///Users/[name]/Library/Developer/CoreSimulator/Devices/33076AD2-C989-47E9-A803-3E56CC4B09D6/data/Containers/Data/Application/4756F0A2-9CCC-4F9A-9315-D55434328FD9/Documents/myCustomPath/6A5C27E3-89F7-465F-A855-66749C92D086.jpg

Behavior is as below :

  • left screenshot is after saving my image,
  • right screenshot is after a rebuild, opening the app, I still see my image!

--> NOT HAPPY!

enter image description here enter image description here

My issue

I've read all about the temporary aspect of the returned uri and see what react-native-image-picker says about it:

On iOS, don't assume that the absolute uri returned will persist.

I've found also this thread which had a similar issue, but none worked:

  • RNFS.DocumentDirectoryPath after a rebuild had a different UUID in the path, so the file was not found as it was saved with the previous UUID
  • I tried saving for iOS the uri as '~/Documents/myCustomPath/myfilename.jpg' had the same behavior. Displayed when added, blank after rebuild.

I had before the rebuild:

Document directory path being : file:///Users/[user]/Library/Developer/CoreSimulator/Devices/33076AD2-C989-47E9-A803-3E56CC4B09D6/data/Containers/Data/Application/466CAF1A-AF8D-423C-9BF6-F0A242AF8038/Documents/

and my saved picture uri :

file:///Users/[user]/Library/Developer/CoreSimulator/Devices/33076AD2-C989-47E9-A803-3E56CC4B09D6/data/Containers/Data/Application/466CAF1A-AF8D-423C-9BF6-F0A242AF8038/Documents/myCustomPath/20969988-633B-46BD-8558-E39C3ADD6D12.jpg

but after the rebuild the Application UUID changed to BEE128C8-5FCF-483C-A829-8F7A0BB4E966 making now my document directory to be

file:///Users/[user]/Library/Developer/CoreSimulator/Devices/33076AD2-C989-47E9-A803-3E56CC4B09D6/data/Containers/Bundle/Application/BEE128C8-5FCF-483C-A829-8F7A0BB4E966/Documents

but still looking the picture in the uri :

file:///Users/[user]/Library/Developer/CoreSimulator/Devices/33076AD2-C989-47E9-A803-3E56CC4B09D6/data/Containers/Data/Application/466CAF1A-AF8D-423C-9BF6-F0A242AF8038/Documents/myCustomPath/20969988-633B-46BD-8558-E39C3ADD6D12.jpg

When the image is actually now located under:

file:///Users/[user]/Library/Developer/CoreSimulator/Devices/33076AD2-C989-47E9-A803-3E56CC4B09D6/data/Containers/Data/Application/BEE128C8-5FCF-483C-A829-8F7A0BB4E966/Documents/myCustomPath/20969988-633B-46BD-8558-E39C3ADD6D12.jpg

So how can I cope for that App UUID change after a rebuild as paths are dynamic on iOS.

Versions I use:

  • "react-native": "0.57.8",
  • "react-native-fs": "^2.13.2",
  • "react-native-image-picker": "^0.28.0"
Jojo
  • 133
  • 3
  • 9
  • What do you mean by a rebuild? Do you mean a reload `CMD+R`? Or do you mean deleting the app from the simulator and rebuilding it and reinstalling it? Have you tried going to the documents directory on the simulator and seeing if the image is there? Have you tried using `RNFS.readDir` to check that the images are there? – Andrew Jan 16 '19 at 17:42
  • I mean by rebuild running: ```react-native run-ios```. Reloads (```CMD+R```) do work. Desinstall of course looses persistence. But I need to keep persistence when rebuilding (kind of when you get a new build version) – Jojo Jan 16 '19 at 17:58
  • ok, for ```RNFS.readDir``` in my ```myCustomPath``` I do get the image from my previous example, with the path: ```/Users/johanmontmartin/Library/Developer/CoreSimulator/Devices/33076AD2-C989-47E9-A803-3E56CC4B09D6/data/Containers/Data/Application/A4CE9AE7-D766-4949-B380-9642138D7C58/Documents/myCustomPath/6A5C27E3-89F7-465F-A855-66749C92D086.jpg``` but as we can see the ```Application``` GUID in the path is not the same, because is regenerated with new builds. – Jojo Jan 16 '19 at 18:16
  • So the file exists but it has a different url? – Andrew Jan 16 '19 at 18:25
  • Correct. Which is the issue many people have usually after a rebuild because everytime with a rebuild, the app internal id changes (see [https://stackoverflow.com/questions/39286211/react-native-ios-read-image-from-apps-documents-folder] (this stackoverflow thread), but this didn't help me) – Jojo Jan 16 '19 at 22:00
  • also same issue as in [https://github.com/react-native-community/react-native-image-picker/issues/107] – Jojo Jan 16 '19 at 22:09
  • Why doesn’t the solution https://stackoverflow.com/questions/39286211/react-native-ios-read-image-from-apps-documents-folder%5D work for you? You may need to share more code or explain what is happening in more detail in your code after you select the image. – Andrew Jan 17 '19 at 08:21
  • the solution doesn't work because RNFS.DocumentDirectoryPath after a rebuild returns the new application UUID, so the path to the original image was lost. For the tilda solution (~), that did not work as the image was not even showing. – Jojo Jan 17 '19 at 08:54
  • ok... I think I got my issue, I was not regenerating the path when I wanted to display the image... will try and update – Jojo Jan 17 '19 at 09:55

2 Answers2

3

As react-native-image-picker states

On iOS, don't assume that the absolute uri returned will persist.

This means that if you store the absolute uri to the file and then do react-native run-ios the application GUID will change and that absolute uri will no longer exist or work. However, and this is important the image will be in the folder that you saved it in, as it is copied across.

The only solution to fixing this is to save the directory and the filename of the file and reconstruct the uri when you want to use it.

So that means that you would save in state

this.setState({ image: '/myCustomPath/image.jpg' });

Then when you come to use it you would rebuild the path like this

let pathToFile = `${RNFS.DocumentDirectoryPath}${this.state.image}`
Andrew
  • 26,706
  • 9
  • 85
  • 101
  • 1
    Correct, that is what I've figured out and just tested. My issue is I was not reconstructing the path when I display the image: What worked was ```source={{uri : RNFS.DocumentDirectoryPath+"/"+info.item.image.fileName}}``` – Jojo Jan 17 '19 at 10:11
2

You could simply solve this (without rely on react-native-fs) by replacing the path before "/Documents/..." with a tilde "~".

let pathToFile = "file:///var/mobile/Containers/Data/Application/9793A9C3-C666-4A0E-B630-C94F02E32BE4/Documents/images/72706B9A-12DF-4196-A3BE-6F17C61CAD06.jpg"
if (Platform.OS === 'ios') {
    pathToFile = '~' + pathToFile.substring(pathToFile.indexOf('/Documents'));
}

This is supported by React Native as you can see in their source code.