-
-
Notifications
You must be signed in to change notification settings - Fork 437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Access Content uri in android #70
Comments
Any solution? |
URIs returned from Android are DocumentProviders URIs. You need to access them using a ContentResolver. react-native-fs cannot handle DocumentProvider documents, it's only designed to work with files inside the limited areas of the filesystem the app is permitted to access. Right now react-native-fetch-blob might work, though it actually does a lot wrong so it may not. React Native is going to be getting Blob/DocumentProvider support in the future (0.50 or 0.51 hopefully), so it'll soon be possible to do things from within react-native. |
Any alternate solution for file picker and upload to server? |
I am able to get base64 from content uri using below code RNFetchBlob.fs.readFile(this.state.pdf_uri,'base64') I used this https://github.com/wkh237/react-native-fetch-blob package |
Yup, that could work for now, but keep in mind these problems with that library: |
@dantman Do you have solution of this problem? |
@aditya-simplecrm The "solution" I'm using in the app I'm working on is just to wait another month for RN to get native Blob uploading. Alternatively if you feel like writing native code you can just write your own upload code in Java and Objective-C/Swift native code instead of JS. |
There is now a solution for this problem in react-native-fs. Enabling access and copy content:// files -itinance/react-native-fs#395 |
React Native 0.54.0 has finally been released with Blob support, you don't need any RNFS hacks. Now all we have to do is come up with some documentation on how to use it. |
@dantman can you please let me know how can we use it? Any document for same? I am using below version: "react": "16.3.0-rc.0" |
@AgNm Lookup the how to use |
@dantman @Elyx0
Below is getting printed in console.log:
I am not getting how to proceed further. Can you please help. |
@AgNm the Remove |
I'm not sure this is entirely true. Content uris are workable through many built in aspects of react native as(as of 0.53 anyway). For instance: CameraRoll.getPhotos() will return a collection of objects with content:// uris that are accessible and renderable from within React Native's Image component. There is also no need to fetch this file locally and convert it to a blob before uploading. You can upload files at content:// uris using a properly formatted FormData object as a part of a multipart/form-data fetch. Something like: let data = new FormData()
data.append('image', {uri: 'content://path/to/content', type: 'image/png', name: 'name'})
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: data
}) works fine for me. |
@regulus33 this is absolutely correct, using a properly formatted FormData object as shown above will upload the file, without needing to convert the uri to a blob. I can confirm that this is correct as of RN v0.53.0 All React Native needs in the data.append call is the 2nd parameter with a
However, to get it to work for me - I didn't need to specify 'Content-Type' in the header. If I set it to So my fetch call is like this:
As an aside, if you want to do this in TypeScript, I had a past blog post about this. |
@jaeyow Great info! When in doubt, scour the source! |
What I am looking for is not uploading to a server. I want to be able to access the actual or real path that this library provides. Please is it possible to achieve this without first uploading to a remote server? |
@smithaitufe You cannot access the real path, the real path does not belong to your app on either OS. (On iOS you get a local copy, not the real path; On Android you get a content URI to access it through the document provider) If you want to read the the data, you can |
@dantman can you please provide an example for file upload. |
@jkunwar I haven't had a chance to use it in practice yet so I don't have an example. However I have confirmed that fetching a content:// URI from a picker worked. And others have mentioned that you can use content URIs directly with Blob and FormData are standardized browser APIs, examples specific to the picker shouldn't be required. Any tutorial or documentation for that should work: |
//choose file using document picker
//submit form data
//action to upload file
@dantman these are my codes to upload file. would you please look at it and tell me where i am going wrong |
@jkunwar I haven't used the FormData+uri mode yet, other people mentioned it, so I can't really help at the moment. |
@dantman thanks for the response |
@jkunwar what type of errors are you seeing? |
@jkunwar I haven't tried with axios + FormData, but I know this works with fetch + FormData. See this issue with React Native + axios + FormData (axios/axios#1321), and I am not sure if this is still an issue, and might be what you are seeing there.. |
I've used RNFS to read file from content uri, but its returning encoded content. I want to send data to rails as multipart with axios. Suggest me to get file content from content uri without encoding. |
I can get blob #224 and convert dataUrl encoding by base64 and write file using some FS library of RN. Now, I use this method. export const blobToBase64Url = (
blob: Blob
): Promise<Base64FormatObject | null> => {
const fileReader = new FileReader();
return new Promise((resolve, reject) => {
fileReader.readAsDataURL(blob);
fileReader.onloadend = function onloadend() {
const base64Url = fileReader.result as string;
const [definition, dataStr] = base64Url.split(';base64,');
const type = definition.slice(5);
resolve({
type,
dataStr,
encoding: 'base64'
});
};
fileReader.onerror = function onerror(event) {
console.error(event);
fileReader.abort();
reject(event);
};
});
}; |
@tkow Blob data is stored in the native code area (don't remember if it's memory or cached in the filesystem). In order to get a base64 string, the entire contents of the file has to be transmitted over the Native<->JS bridge and converted into base64, which is a format that takes up more memory than the binary it represents. And because that base64 string is a JS string, the entirety of that data has to be in memory. While ArrayBuffers may not have the wasted memory issue of base64, I don't believe there are any version of them that works the Blob way where data isn't handled by JS. So even if you can use them you still don't really want to use them because the real issue is that you do not want to transmit the file data over the Native<->JS bridge unless it's absolutely necessary. That said if you absolutely have to process a large file in JS and transmitting data over the Native<->JS bridge you may want to look into For uploading, As for the issue where you want to take a Blob and save it to your app's filesystem. Unfortunately that is the one case where the RN ecosystem may need some more work. What you want there is for the native code to copy the file data directly from the native side of the Blob to the filesystem without ever sending the data over the Native<->JS bridge. Unfortunately I don't know of anything that did this when I was working with RNDP in the past. Ideally RNFS would have a method that would accept a Blob created by RNFS and copy/write it to a file. Which would then allow you to continue doing other things to it with RNFS. But I'm not sure whether that has ever been done. |
I appreciate to have your time. BTW, The reason why I want to cache files is that stable react-native-firebase supports cached files only. but, this as previously I and you mentioned , inflate bytes and unreasonable processing bytes. |
@dantman |
@sauravjmt I have no clue what API you're even using to open the mail app. |
@dantman i am using 'react-native-mail' which is using Intent in android to send with email. with following basic use Mailer.mail({ } |
@sauravjmt react-native-mail takes filesystem paths and on Android and then uses You will either have to copy the whole file to your app's cache folder and use that path. Or get react-native-mail to optionally accept URIs instead of paths and pass them on directly (assuming that the app on the other end has permissions to read them). |
My solution is create Android custom native module, and in React Native we call them with: |
How can I zip or unzip choosen file from document picker? https://github.com/mockingbot/react-native-zip-archive#api if (res.type === 'application/zip') {
let result = await fetch(res.uri);
const blob = await result.blob(); //this works but how to save it and get file path from blob??
const sourcePath = res.uri; // this not work it is content://..
const targetPath = `${fs.DocumentDirectoryPath}/drivelog.cblite2`;
const charset = 'UTF-8';
unzip(sourcePath, targetPath, charset)
.then((path) => {
console.log(`unzip completed at ${path}`)
})
.catch((error) => {
console.log(error)
})
} |
[UPD]: See #70 (comment) |
I get an invalid synchronous error when using it while debugging. Do you have any idea why? It seems to pull the full path I want though |
Hi @sawndur you can ask questions directly in my package, so we don't bother people here, but the short answer is - I didn't debug any code with this module In it, however if you will write me step by step what are you using - I will try to reproduce it and see if I can do anything. You can also play with the code yourself and make a PR if there are simple solution available. |
I kind of made a workaround to suit my needs. Basically, the RNFetchBlob.fs.stat() wouldn't work because the URI getting received was not matching any of the conditions in the function so it just returned null. So I took your code and tweaked it to work in the stat() method and it worked like a charm. I'm getting full filepaths with file info such as size and name as well. I'm not too sure why it threw "Calling synchronous methods on native modules is not supported in Chrome" but it may have had to do with how I was calling it... |
Can the uri you get from Trying to convert the uri to blob throws an error ( Is there a way to view the file using |
You can simply pass another property
**Note: The android device only reads the path which is like this file:///. with 3 slashes ** |
you can also use this approach numandev1/react-native-compressor#25 (comment) this is same as |
Trying to fetch the fileCopyUri on Android (with Is there anything I'm missing? Using the wrong fetch (no external library; react native v0.66.2)? Lacking some permissions? I tried both The uri also does not look as different from the one emitted by Image picker: Edit: It appears to be somewhat size related |
Yes, larger documents could not be fetched (using the fetch method), no matter if I am using the copyTo parameter or not |
I ended up reading the file manually using https://github.com/RonRadtke/react-native-blob-util#file-stream The following configuration also solved content uri issues on Android and it also works on iOS: const picked = await DocumentPicker.pickSingle({ mode: 'import' });
let path = picked.uri;
if (path.startsWith('file://')) path = path.substring('file://'.length);
const stream = await ReactNativeBlobUtil.fs.readStream(path, 'base64', chunkSize);
stream.open();
stream.onError(...);
stream.onData(...);
stream.onEnd(...); |
i want to upload audio file to firebase its give me error error [Error: failed to stat path |
I have the same issue with accessing media(content uri) files from an external app like music etc. No need to add anything just follow my answer. I have fixed it by adding PermissionsAndroid from react-native here is the code:
I hope this helps you :) |
I believe this thread has gotten so long there's little value in keeping the issue open. If you're looking for a way to work with a file locally, eg. to upload it to a remote server, you'll need to use the thank you |
In case anybody is still facing this issue while using react-native-document-picker, Try adding " copyTo: 'cachesDirectory'" to parameter and use copyFileUri instead of uri. Below is an example of usage const res = await DocumentPicker.pick({ |
I'm getting a content uri in android:
'content://com.android.providers.media.documents/document/image%3A99'
Decoding it does not work, and it seems that it's impossible to access the file.
Does anyone has an idea how to access the file?
10x
The text was updated successfully, but these errors were encountered: