open_file icon indicating copy to clipboard operation
open_file copied to clipboard

Uri content://media/external/downloads/<file> doesn't exist for some devices

Open Holofox opened this issue 4 years ago • 6 comments

Hey! Reproduced on real devices and simulators based on Android 11.

  Future<OpenResult> openFileFromPath(String path) {
    try {
      return OpenFile.open(path)
    } catch (e) {
      print(e.toString());
    }
  }
openFileFromPath('content://media/external/downloads/79')
I/flutter (13676): Open file result (ResultType.fileNotFound): the content://media/external/downloads/79 file does not exists
Flutter 2.2.2 • channel unknown • unknown source
Framework • revision d79295af24 (3 weeks ago) • 2021-06-11 08:56:01 -0700
Engine • revision 91c9fc8fe0
Tools • Dart 2.13.3

Holofox avatar Jul 02 '21 11:07 Holofox

Maybe you can try the file path instead of the URI

crazecoder avatar Jul 02 '21 11:07 crazecoder

@crazecoder, it works with the full path, but I have no way to get it on Android 11.

Holofox avatar Jul 02 '21 11:07 Holofox

I'm not sure about your usage scenario, but if you want to select a file, you can use file_picker to get the path

crazecoder avatar Jul 02 '21 12:07 crazecoder

Hi, I have a similar scenario. My app needs to save downloaded files to public download dir (/storage/emulated/0/Download). From API 29 the only way to do this is to use MediaStore API. Below is the example method in Java to copy file to Download dir:

private String saveToDownloadsAndroidQAndHigher(String sourceFilePath, String fileName) throws IOException {
        final ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
        contentValues.put(MediaStore.Downloads.MIME_TYPE, "application/pdf");
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
        contentValues.put(MediaStore.Downloads.IS_PENDING, 1);
        final Uri targetPdfUri =
                getActivity().getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
        final OutputStream outputStream =
                getActivity().getContentResolver().openOutputStream(targetPdfUri);
        copyFile(sourceFilePath, outputStream);

        contentValues.clear();
        contentValues.put(MediaStore.Downloads.IS_PENDING, 0);
        getActivity().getContentResolver().update(targetPdfUri, contentValues, null, null);
        return targetPdfUri.toString();
}

Uri returned from MediaStore is exactly in format: content://media/external/downloads/79

Now I want to open this file in external app. Unfortunately open_file cannot do this, so I need to do this native way:

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.addCategory("android.intent.category.DEFAULT");
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setDataAndType(Uri.parse("content://media/external/downloads/79"), "application/pdf");
        try {
            getActivity().startActivity(intent);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

It would be nice to be able to open such uri using your plugin

krzysztof-swi avatar Jul 05 '21 14:07 krzysztof-swi

Hi, I have a similar scenario. My app needs to save downloaded files to public download dir (/storage/emulated/0/Download). From API 29 the only way to do this is to use MediaStore API. Below is the example method in Java to copy file to Download dir:

private String saveToDownloadsAndroidQAndHigher(String sourceFilePath, String fileName) throws IOException {
        final ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
        contentValues.put(MediaStore.Downloads.MIME_TYPE, "application/pdf");
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
        contentValues.put(MediaStore.Downloads.IS_PENDING, 1);
        final Uri targetPdfUri =
                getActivity().getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
        final OutputStream outputStream =
                getActivity().getContentResolver().openOutputStream(targetPdfUri);
        copyFile(sourceFilePath, outputStream);

        contentValues.clear();
        contentValues.put(MediaStore.Downloads.IS_PENDING, 0);
        getActivity().getContentResolver().update(targetPdfUri, contentValues, null, null);
        return targetPdfUri.toString();
}

Uri returned from MediaStore is exactly in format: content://media/external/downloads/79

Now I want to open this file in external app. Unfortunately open_file cannot do this, so I need to do this native way:

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.addCategory("android.intent.category.DEFAULT");
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setDataAndType(Uri.parse("content://media/external/downloads/79"), "application/pdf");
        try {
            getActivity().startActivity(intent);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

It would be nice to be able to open such uri using your plugin

You can use Cursor to get the path

crazecoder avatar Jul 07 '21 10:07 crazecoder

Thanks for the tip. I managed to get full path using following code:

    try (Cursor cursor = getActivity().getContentResolver().query(targetPdfUri, null, null, null, null)) {
            cursor.moveToFirst();
            final int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
            return cursor.getString(columnIndex);
        }

However MediaStore.MediaColumns.DATA has been deprecated in API 29. When I open above path to pdf using OpenFile, on Android 10 I get an error that Adobe Pdf Reader cannot access file. It works fine on Android 11. So I still believe it would be good to support content uris. Invoking activity in Java for content uri works fine for both Android 10 and 11.

krzysztof-swi avatar Jul 09 '21 08:07 krzysztof-swi