Plinio Mayer
Plinio Mayer

Reputation: 99

Convert content:// uri to file:// uri using react native

I'm currently trying to open a file using expo's FileSystem after getting the path from expo's DocumentPicker, but I can't find a way to make the URI from DocumentPicker readable to FileSystem. Everything works fine, I've no problems with permissions or anything else, but every tutorial I could find so far are basically for react native projects with exposed native code or Java.

Here I call DocumentPicker:

import * as DocumentPicker from 'expo-document-picker';

const Hello = ({navigation}) => (
  <HelloView>
    <HelloButton
      style={{
        backgroundColor: WhatsappStyles.colors.lightGreen,
      }}
      activeOpacity={0.5}
      onPress={() => {
        DocumentPicker.getDocumentAsync({
          copyToCacheDirectory: false,
        }).then(({uri}) => {
          navigation.navigate('LoadFile', {path: uri});
        });
      }
    }>
      <HelloButtonText>Go to App</HelloButtonText>
    </HelloButton>
  </HelloView>
);

And here I try (unsuccessfully) read the path:

import * as FileSystem from 'expo-file-system';


const LoadFile = ({navigation, route}) => {
  let [loading, setLoading] = useState(true);

  useEffect(() => {
    FileSystem.readAsStringAsync(route.params.path).then(result => {
    // do something here
    }
    setLoading(false);
  }, []);
...

I'm using react-navigation/stack for stack navigation and styled-components/native to build the components.

Upvotes: 5

Views: 6813

Answers (3)

Carter
Carter

Reputation: 306

Other answers suggest using expo-file-system's downloadAsync method which does not support content:// schemes [1].

In this table, you can see what type of URI can be handled by each method. For example, if you have an URI, which begins with content://, you cannot use FileSystem.readAsStringAsync(), but you can use FileSystem.copyAsync() which supports this scheme.

Here is an example of using the suggested FileSystem.copyAsync to move the file to our app's document directory:

const oldFile = "content://.../file.txt"
const newFile = FileSystem.documentDirectory + `newFile.txt`

await FileSystem.copyAsync({
    from: oldFile,
    to: newFile
});

// Now we can read the file with `readAsStringAsync`

const fileContent = await FileSystem.readAsStringAsync(newFile);

Upvotes: 0

Plinio Mayer
Plinio Mayer

Reputation: 99

So, as far as I could find there's no way to "convert" content:// uri to file:// uri, but you can actually download the file to a cache or to the internal storage using FileSystem's downloadAsync function and use the file:// uri resulting from there.

e.g.

DocumentPicker.getDocumentAsync({
    copyToCacheDirectory: false,
}).then(({contentUri}) => {
    FileSystem.downloadAsync(
         contentUri, 
         FileSystem.documentDirectory + '<file name>')
    .then(({uri}) => {
         FileSystem.readAsStringAsync(uri)
         .then(result => {
              // do what you want here.
         });
    });
});

Upvotes: 1

Vasyl Stokolosa
Vasyl Stokolosa

Reputation: 33

import * as ImagePicker from 'expo-image-picker'

let result = await ImagePicker.launchImageLibraryAsync({
    mediaTypes: ImagePicker.MediaTypeOptions.Images,
    allowsEditing: true,
    base64: true,
    aspect: [4, 3]
})

{ imageURL: result.uri, base64: result.base64 }

So, result.uri an image URL from FileSystem which you can use for displaying in Image and base64 send to yout store :)

Upvotes: 1

Related Questions