Skip to content
This repository has been archived by the owner on Mar 16, 2019. It is now read-only.

Read file from Camera roll (content:// path on android) #287

Open
nordved opened this issue Mar 14, 2017 · 51 comments
Open

Read file from Camera roll (content:// path on android) #287

nordved opened this issue Mar 14, 2017 · 51 comments

Comments

@nordved
Copy link

nordved commented Mar 14, 2017

I am trying to get the base64 code for an image in the camera roll. The path for the image is something like

content://com.app.provider/app_images/Android/data/com.app/files/Pictures/image-a00a13f4-a24f-40ce-bb16-e56979b75692.jpg

And I am trying to read this file with

RNFetchBlob.fs.readFile(localPath, 'utf8')

and

RNFetchBlob.fs.readFile(localPath, 'base64')

The app simply crashes and in the logcat I can find the error

Column '_data' does not exist

I have also tried

RNFetchBlob.fs.readFile(RNFetchBlob.wrap(localPath), 'base64')

Which gives the error:

Error: Attempt to invoke virtual method 'boolean java.lang.String.startsWith(java.lang.String)' on a null object reference

In the FileSystem API you write that it is possible to read the files from content://, so I'd like to know if there is another way that I'm not seeing.

EDIT: I'm using RN 0.41 and RNFB 0.10.2

@tlvince
Copy link

tlvince commented Mar 15, 2017

I'm seeing the same thing for readFile calls to paths within DocumentDir.

Error: Attempt to invoke virtual method 'boolean java.lang.String.startsWith(java.lang.String)' on a null object reference
    at createErrorFromErrorData (NativeModules.js:116)
    at NativeModules.js:79
    at MessageQueue.__invokeCallback (MessageQueue.js:288)
    at MessageQueue.js:127
    at guard (MessageQueue.js:46)
    at MessageQueue.invokeCallbackAndReturnFlushedQueue (MessageQueue.js:126)
    at debuggerWorker.js:71

Android, RN 0.42.

@chris-pikul
Copy link

chris-pikul commented Mar 20, 2017

I just found this today. So that's a +1 from me.
Specifically, it's when sharing from Google Drive which give's a URI looking like...
content://com.google.android.apps.docs.storage.legacy/enc%3D2cnEPvlNW2uZUjq8h_w7hhNWmkRhsPqHum9gJTxeOrsaGiV3%0A

Same error pops up, and get's caught in the promise.
Error processing message Error: Attempt to invoke virtual method 'boolean java.lang.String.startsWith(java.lang.String)' on a null object reference

Should mention I'm using the readFile(uri, 'base64') version.
Also:
RN: 0.35.0
RNFetchBlob: 0.10.0

@wkh237
Copy link
Owner

wkh237 commented Mar 21, 2017

Thanks for providing the information, will look into this issue ASAP 👍

@wkh237
Copy link
Owner

wkh237 commented Mar 22, 2017

After some investigation, the problem is that our Android URI resolver couldn't get the absolute file path from the given URI. I will try to figure out if there's a better implementation.

@tlvince
Copy link

tlvince commented Mar 22, 2017

I'm experiencing this in Android 7.1 if that makes any difference. Lmk if you'd like me to test anything.

@wkh237
Copy link
Owner

wkh237 commented Mar 23, 2017

@ChrisPikul510 @tlvince , is there any way to make a content provider URI like content://com.app.provider/app_images/Android/data/com.app/files/Pictures/image-a00a13f4-a24f-40ce-bb16-e56979b75692.jpg and content://com.google.android.apps.docs.storage.legacy/enc%3D2cnEPvlNW2uZUjq8h_w7hhNWmkRhsPqHum9gJTxeOrsaGiV3%0A ?

In my case, the URIs from camera roll look like this content://media/external/images/media/694, and there's no problem to resolve this kind of URI.

@tlvince
Copy link

tlvince commented Mar 23, 2017

Apologies. In my case I'd missed adding a content type prefix altogether; adding file:// to e.g. file://${RNFetchBlob.fs.dirs.DocumentDir}/${filename} works for me.

@nordved
Copy link
Author

nordved commented Mar 23, 2017

@wkh237 I was using https://github.com/marcshilling/react-native-image-picker to take a picture. It saves to the gallery of the phone or selects from the gallery. I can understand if you feel like 3rd party support is not on the top of your list though.

I solved it by storing the base64 directly from the callback instead of getting it from the filesystem.

@wkh237
Copy link
Owner

wkh237 commented Mar 24, 2017

@nordved , thanks for the information. It'd be great to make this kind of URI supported since it's very common use case IMO 👍

@chris-pikul
Copy link

chris-pikul commented Mar 25, 2017

@wkh237 The uri I was attempting came directly from Google Drive app through a share intent. In which case from my end I'm not entirely sure exists as that looks like a hash/temp URI. Are you suggesting I modify the URI?

BTW, is there a way you can implement a function for grabbing N bytes from a file? I ask because I'm only reading this file to grab the first 16 bytes to cross-reference with my list. Which also if you want to integrate here would be cool too. It's just header signature negotiation...
https://github.com/ChrisPikul510/content-type-negotiation

@wkh237
Copy link
Owner

wkh237 commented Mar 26, 2017

@ChrisPikul510 , thanks for the information, though the function is not supported yet but it's on our roadmap (see #124).

However, as a workaround, you can use an undocumented API fs.slice this API will not be removed as it's used by Blob.slice polyfill.

fs.slice(src:string, dest:string, start:number, end:number):Promise 

which will create a file at path dest you can then read its content via fs.readFile.

@chris-pikul
Copy link

@wkh237 So if I have this right, a way for me to get the header is to do something like....

RNFetchBlob.fs.slice('file://some/file', CACHE_DIR_FILE, 0, 16)
   .then(() => RNFetchBlob.fs.readFile(CACHE_DIR_FILE, 'base64'))
   .then((data) => {
      //Do something with data
   })
   .catch(console.warn)

And that should give me only the first 16 bytes correct? But if I have a temp file, then I'll need to unlink it, which seems a bit too complicated computationally for something so simple.

Anyways, any word on the content:// URI's causing this crash?

@wkh237
Copy link
Owner

wkh237 commented Mar 27, 2017

About the content:// URI's problem, after some investigations I got some clues. In short, we have to handle this kind of URI in a different way, will update the status once it's complete.

@wkh237
Copy link
Owner

wkh237 commented Mar 28, 2017

I've added additional URI handling to fs.readFile and fs.readStream, please try to install the package from branch `issue-287.'

$ npm install --save git://github.com/wkh237/react-native-fetch-blob.git#issue-287

@etiennewaldron
Copy link

@tlvince I am having the same issue, with the same image picker. How did you do it in the end? Is this the line you updated? fs.readFile(uri, 'base64') Thanks

@etiennewaldron
Copy link

@wkh237 Just tried it, it doesn't seem to fix my issue. Below is the URI I am using in fs.readFile: content://com.app.provider/app_images/Android/data/com.app/files/Pictures/image-2cf9181c-ab81-4fca-8241-fad4ed060156.jpg. Any ideas?

@wkh237
Copy link
Owner

wkh237 commented Apr 5, 2017

@etiennewaldron , thanks for the feedback. Will look into the issue and find another possible solution.

@etiennewaldron
Copy link

Hi, do you have any news on this issue? Is there a quick fix I can use in the meantime? Thanks

@wkh237
Copy link
Owner

wkh237 commented Apr 16, 2017

@etiennewaldron , I've just updated branch issue-287, I can read a picture from react-native-image-picker which has URI like this

content://com.rnfetchblobtest.provider/app_images/Pictures/image-c6f94579-a189-44da-9060-3fc9c613f354.jpg

Please try if that works, thanks 👍

@zkrige
Copy link

zkrige commented Jun 29, 2017

not working on 0.10.6, and issue-287 gives me stat error: failed to list path " + path + " for it is not exist or it is not a folder

path == content://com.app.provider/app_images/Android/data/com.app/files/Pictures/image-7402dd55-4003-4094-a53c-69c852d27876.jpg

@wkh237
Copy link
Owner

wkh237 commented Jul 2, 2017

Just updated branch issue-287, it's working on my end now. Please update your package from the branch, thanks 👍

@kashav
Copy link

kashav commented Jul 3, 2017

@wkh237 Not working on 0.10.6 for me either, the issue-287 branch seems to be working well, thanks! 👍

@ShoaibKhazer
Copy link

@wkh237 I have updated my package to branch 287
I am getting this error while uploading form react-native-image-picker
RNFetchBlob failed to create request multipart body :Attempt to invoke virtual method 'char[] java.lang.String.toCharArray()' on a null object reference
here is my image uri:
content://com.servup.provider/external_files/Android/data/com.servup/files/Pictures/image-6c20d60e-eb03-442b-a023-b816c68b8d1a.jpg

kindly help me in solving this issue

@wkh237
Copy link
Owner

wkh237 commented Jul 10, 2017

@ShoaibKhazer , is there steps to reproduce the error? Including the app you use to select the image.

@ShoaibKhazer
Copy link

I am simply using react-native image picker to capture the image
then getting the image uri and uploading using

    RNFetchBlob.fetch('PUT', 'http://52.72.219.6:44303/Api/v1/ConsumerProfile', {
          "Accept": "application/json",
          "Authorization" : 'Bearer ' + this.state.token,
          }, [
              {
                name : 'avatar',
                filename : 'avatar.png',
                data: RNFetchBlob.wrap(imgUri)
              },])
          .uploadProgress((written, total) => {
              console.log('uploaded', written / total)
          })

@ShoaibKhazer
Copy link

@wkh237 your response is highly valuable as my product is about to launch :)

@wkh237
Copy link
Owner

wkh237 commented Jul 12, 2017

@ShoaibKhazer , I'd like to help but I will need to find a way to get the problematic URI.

I've tested the URIs I can have, and could not reproduce the error. Have you tried android.getContent for getting images/files ?

@maiordom
Copy link

fix problem with settings cameraRoll: true for react-native-image-picker

ImagePicker.launchCamera({
      noData: true,
      storageOptions: {
        cameraRoll: true,
        waitUntilSaved: true,
      },
    }
})

@ShoaibKhazer
Copy link

thanks a lot @wkh237 and @maiordom for your support @maiordom solution is working for me . :)

@wkh237
Copy link
Owner

wkh237 commented Jul 12, 2017

@ShoaibKhazer , great to know it's working ! Also thanks @maiordom for the help 😗

@fabriziomoscon
Copy link

fabriziomoscon commented Aug 3, 2017

@wkh237 I am using
"react-native": "0.45.1"
"react-native-fetch-blob": "^0.10.8"
"react-native-image-picker": "^0.26.3"
on Android emulator version 7.0.0

If I specify cameraRoll: false in the option object for launchCamera()

{
  storageOptions: {
    cameraRoll: false
  }
}

normalizePath will return null and throw an Exception

static String normalizePath(String path) {
if(path == null)
return null;
if(!path.matches("\\w+\\:.*"))
return path;
if(path.startsWith("file://")) {
return path.replace("file://", "");
}
Uri uri = Uri.parse(path);
if(path.startsWith(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET)) {
return path;
}
else
return PathResolver.getRealPathFromURI(RNFetchBlob.RCTContext, uri);
}

Also I noticed that the constant FILE_PREFIX_CONTENT is not even used

public static final String FILE_PREFIX_CONTENT = "content://";

@brianinator
Copy link

Hi @wkh237 I have the same issue that @ShoaibKhazer reported. I tried as you suggested by using android.getContentIntent but no luck resolving it. I even tried writing the file and then reading it but I get the same exception as I do using the upload. Any tips?

@CptMaumau
Copy link

I've made it work with RNFetchBlob.fs.readFile(localPath, 'base64') but if the file is too big, the app crashes so I really need to use file storage with RNFetchBlob.wrap (works well on iOS) but I still get Attempt to invoke virtual method 'char[] java.lang.String.toCharArray()' on a null object reference

@lll000111
Copy link
Contributor

@CptMaumau It would help if you could produce a test case, especially if it is one that fits right into the already existing tests: https://github.com/wkh237/react-native-fetch-blob-dev/tree/master/test (all files starting with "test-" are tests for RNFB).

lll000111 added a commit to lll000111/react-native-fetch-blob that referenced this issue Sep 7, 2017
- in readFile: Replace code introduced for issue wkh237#287 - The use of available() (InputStream) method is not recommended if one wants to get the definite size of the input. I replaced it with a dynamic method that reads the input stream until it ends, using ByteArrayOutputStream to assemble the result

- in getSystemFolders: handle the possibility that getExternalFilesDir() returns null

- suppress two IDE warnings about 1) an unused null assignment as signal to the GC (which probably really is not needed in tihs context), and 2) an unused parameter
@tombailey
Copy link

If anyone is still having issues with this on Android, try #546

@song50119
Copy link

song50119 commented Nov 5, 2017

+1

@EyalSi
Copy link

EyalSi commented Jan 11, 2018

There is now a solution for this problem in react-native-fs. Enabling access and copy content:// files -itinance/react-native-fs#395

@dnaploszek
Copy link

Is this going to be merged anytime soon? Or could i use @tombailey fork? I know that the maintainer is missing, but this is a huge drawback. Is there anything left to do on issue-287 branch?

@cmwendwa
Copy link

Using react native image picker wrapped RNFetchBlob.wrap(response.path) rather than RNFetchBlob.wrap(response.uri) and it worked. Note: the response's from the picker.

@rochapablo
Copy link

joltup#59

@rahul-mutyalkar
Copy link

Thanks @maiordom for the help

@ev3nst
Copy link

ev3nst commented Mar 15, 2019

in my case, it was only happening on android and with additional data.

my additional data had ID in it, which is an integer.. so simply adding this ->

ID.toString()

fixed it..

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests