相关文章推荐

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

Minimal reproducible example

Not sure i can show a reproducible example as this problem only seems to happen when creating an APK through expos build process.

Summary

This is my first time making an issue, please let me know if you need anymore information.

This is happening on Android, i have not tested other platforms.

I get "location isn't readable" when i try to use FileSystem.readAsStringAsync on an image uri, to encode it with base64. But only in a built apk, in dev it works fine.

I am trying to show an image, from the projects assets folder, in html with the code shown below, using FileSystem.readAsStringAsync to encode it with base64.

const androidDrawableResPath = `file:///android_res/drawable`;
const getAndroidReleaseImageURI = (sourceURI: string) =>
  `${androidDrawableResPath}/${sourceURI}`;
const getLogoUri = async () => {
  const image = Image.resolveAssetSource(require('../../../assets/logo.png'));
  const data = await FileSystem.readAsStringAsync(
  getAndroidReleaseImageURI(image.uri),
    encoding: FileSystem.EncodingType.Base64,
  return 'data:image/png;base64,' + data
const logoUri = getLogoUri()
<img src="${logoUri}" />

Now that works just fine when running dev, but not in a built apk. In the built apk, i get the "location isn't readable" error on FileSystem.readAsStringAsync.
I use the workaround found here: facebook/react-native#18216 because i would get an "unsupposeted scheme" error when trying to use Asset.loadAsync to get the image uri.

Environment

expo-env-info 1.0.5 environment info:
System:
OS: Windows 10 10.0.19044
Binaries:
Node: 16.13.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.18 - ~\AppData\Roaming\npm\yarn.CMD
npm: 8.1.0 - C:\Program Files\nodejs\npm.CMD
IDEs:
Android Studio: AI-221.6008.13.2211.9619390
npmPackages:
@expo/webpack-config: ^18.0.1 => 18.1.0
expo: ^48.0.19 => 48.0.19
react: 18.2.0 => 18.2.0
react-dom: 18.2.0 => 18.2.0
react-native: 0.71.8 => 0.71.8
react-native-web: ~0.18.10 => 0.18.12
Expo Workflow: managed

I have the same issue but only using Expo go on Android. On standalone builds is working as expected.

Could you share your code that runs in standalone builds? I'm curious to see if yours differ from mine in some significant fashion

I have the same issue but only using Expo go on Android. On standalone builds is working as expected.

Could you share your code that runs in standalone builds? I'm curious to see if yours differ from mine in some significant fashion

I have something like this this:

const result = await DocumentPicker.getDocumentAsync({
      type: ["image/png" "image/jpg", "image/jpeg", "application/pdf"]
if (result.type === "success") {
    const uri = result.uri
    const encodedFile = await FileSystem.readAsStringAsync(uri, { encoding: EncodingType.Base64 })
    setFile(encodedFile)

I have the same issue but only using Expo go on Android. On standalone builds is working as expected.

Could you share your code that runs in standalone builds? I'm curious to see if yours differ from mine in some significant fashion

I have something like this this:

const result = await DocumentPicker.getDocumentAsync({
      type: ["image/png" "image/jpg", "image/jpeg", "application/pdf"]
if (result.type === "success") {
    const uri = result.uri
    const encodedFile = await FileSystem.readAsStringAsync(uri, { encoding: EncodingType.Base64 })
    setFile(encodedFile)

Thanks. Its just so strange, i use FileSystem.readAsStringAsync in the exact same way, but with an image. And it doesn't work in a built apk. It just give me "assets_logo.png"

can someone in the thread please share a minimal reproducible example? you should be able to reproduce it in a built apk by running npx expo run:android --configuration release. remove any unrelated code that isn't needed to reproduce, it should be just the blank template + minimal code

Thank you.

I created a reproducible example, but i had problems creating a apk with the exact method you described, so i created one through the expo build process, like i'm doing in my original project.

Snack: https://snack.expo.dev/@kasperandersen/no-img-apk-example
Project that you can install by opening on your device: https://expo.dev/accounts/kasperandersen/projects/no-img-apk-example/builds/f2444070-bf36-44c7-8474-d641e0d49ff0

The code in the snack isn't the exact same as my original post (sorry), but the root of the problem is the same. If i try to use any expo api to get an uri from an image, be it Asset.loadAsync, Image.resolveAssetSource (this one is RN, not expo) or whatever else, to dispaly in a pdf, it will work just fine in dev, but as soon as i create a built apk, the uri changes to something like "assets_nameOfImage".
Note that i alert the uri in the createPdf.js file, and it clearly shows the proper uri in dev, but just a weird string in the apk

In my original link: facebook/react-native#18216 someone talks about it being a problem with the metro bundler (comment is minimized).

Pictures of local dev and apk:

I was having a similar issue as well. Mine was failing in dev running in Expo Go on Android, but I haven't tried running a production build.

In my use case I am trying to load a PDF document form and programmatically fill it out and write it back into a user selected directory. To do that I select a pdf using DocumentPicker and the directory with StorageAccessFramework as follows.

const handleSelectPDF = async () => {
  try {
    const { uri: selectedCharacterSheet, name } =
      await DocumentPicker.getDocumentAsync({
        type: 'application/pdf'
      });
    setPdfFile({ uri: selectedCharacterSheet, name });
  } catch (error) {
    alert(error);
const handleSelectOutputFolder = async () => {
  try {
    const { directoryUri: selectedDirectory } =
      await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
    if (selectedDirectory) {
      setOutputPathUri(selectedDirectory);
      return;
    alert('Permissions for storage are required to use the export feature!');
  } catch (error) {
    console.error(error);
    alert(error);

App is contanerised in Docker.

Host Machine

System:
OS: Ubuntu 22.04.2 (Jammy Jellyfish)
Shell: 5.0.3 - /bin/bash

Container in Docker

expo-env-info 1.0.5 environment info:
System:
OS: Linux 6.2 Debian GNU/Linux 10 (buster) 10 (buster)
Shell: GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
Binaries:
Node: 16.20.1 - /usr/local/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 8.19.4 - /usr/local/bin/npm
npmPackages:
babel-preset-expo: ^9.3.0 => 9.5.0
expo: ^48.0.0 => 48.0.20
react: 18.2.0 => 18.2.0
react-native: 0.71.8 => 0.71.8
Expo Workflow: managed

The only thing that got it working for me was by using the copyToCacheDirectory: false option on the getDocumentAsync. This however, is documented as not ideal if the user will be picking larger files which I assume would be a common issue when dealing with images.

I can try to get a standalone build of this app running and report back. If I face the same issue in a build then I can try to create a simple example project to replicate the issue.

hi all! Same problem at expo 48.

I had to set the copyToCacheDirectory flag to false in the DocumentPicker
and do this

     if (Platform.OS === 'android' && uri.startsWith('content://')) {
       // Create a temporary path to copy the file
       const tmpFileURI = FileSystem.cacheDirectory! + new Date().getTime() + '.jpg';
       // Copy the file from the content:// URI to a local directory
       await FileSystem.copyAsync({
         from: uri,
         to: tmpFileURI,
       uri = tmpFileURI;
     const content = await FileSystem.readAsStringAsync(uri, { encoding: EncodingType.Base64 });

this is strange(

can someone in the thread please share a minimal reproducible example? you should be able to reproduce it in a built apk by running npx expo run:android --configuration release. remove any unrelated code that isn't needed to reproduce, it should be just the blank template + minimal code

Thank you.

I created a reproducible example, but i had problems creating a apk with the exact method you described, so i created one through the expo build process, like i'm doing in my original project.

Snack: https://snack.expo.dev/@kasperandersen/no-img-apk-example Project that you can install by opening on your device: https://expo.dev/accounts/kasperandersen/projects/no-img-apk-example/builds/f2444070-bf36-44c7-8474-d641e0d49ff0

The code in the snack isn't the exact same as my original post (sorry), but the root of the problem is the same. If i try to use any expo api to get an uri from an image, be it Asset.loadAsync, Image.resolveAssetSource (this one is RN, not expo) or whatever else, to dispaly in a pdf, it will work just fine in dev, but as soon as i create a built apk, the uri changes to something like "assets_nameOfImage". Note that i alert the uri in the createPdf.js file, and it clearly shows the proper uri in dev, but just a weird string in the apk

@viking11

I had this issue where the code will work on ios and android locally, but when building android I get asset_name as local uri, going thro the code here ( https://github.com/expo/expo/blob/main/packages/expo-asset/src/PlatformUtils.ts#L93 ) I was able to transform it back to URI for readAsStringAsync and it works 🚀

export async function readAssetFile({ file }: { file: any}) {
  const [{ localUri, name, hash, type }] = await Asset.loadAsync(file);
  let uri = localUri ?? '';
  if (!uri?.startsWith('file://')) {
    if (Platform.OS === 'android') {
      uri = `${cacheDirectory}ExponentAsset-${hash}.${type}`;
  return readAsStringAsync(uri, { encoding: 'base64' });
const imgRequire = require('./assets/test-image.png');
const imgBase64 = await readAssetFile({file: imgRequire});

Hope this solve your issue.

[SDK 51] [IOS] expo-file-system readAsStringAsync() is throwing 'File is not readable' error #29058
 
推荐文章