Android 11 получает ошибку при загрузке PDF-файла, выбранного из внутреннего хранилища (ошибка открытия: EACCES (отказано в доступе))

При попытке загрузить выбранный PDF-файл будет отображаться ошибка открытия: ошибка EACCES (отказано в доступе) для этого файла. Это происходит только в Android 11 (API 30). Для другой версии работает нормально.

Я использую код ниже, чтобы выбрать pdf с устройства

`val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            type = INTENT_TYPE_PDF
            addCategory(Intent.CATEGORY_OPENABLE)
            putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
            }
 startActivityForResult(intent, REQUEST_CODE_PDF_ATTACH)`

В результате действия извлечение пути к файлу из Uri

public static String getPath(final Context context, final Uri uri) {
        // DocumentProvider
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                String storageDefinition;

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                } else {
                    if (Environment.isExternalStorageRemovable()) {
                        storageDefinition = "EXTERNAL_STORAGE";
                    } else {
                        storageDefinition = "SECONDARY_STORAGE";
                    }
                    return System.getenv(storageDefinition) + "/" + split[1];
                }

            } else if (isDownloadsDocument(uri)) {

                // DownloadsProvider
                
                final String id = DocumentsContract.getDocumentId(uri);

                if (id != null && id.startsWith("raw:")) {
                    return id.substring(4);
                }

                String otherId = null;
                if (id != null && id.startsWith("msf:")) {
                    String[] split = id.split(":");
                    otherId = split[1];
                }

                String[] contentUriPrefixesToTry = new String[]{
                        "content://downloads/public_downloads",
                        "content://downloads/my_downloads",
                        "content://downloads/all_downloads"
                };

                for (String contentUriPrefix : contentUriPrefixesToTry) {
                   
                    Uri contentUri = null;
                    if (otherId == null) {
                        contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
                    } else {
                        contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.parseLong(otherId));
                    }
                    try {
                        String path = getDataColumn(context, contentUri, null, null);
                        if (path != null) {
                            return path;
                        } else {
                            DebugLog.e("Path is null for " + contentUri);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        DebugLog.e(e.getMessage());
                    }
                }

                DebugLog.e("File is not accessible");

                // return destinationPath;
                return null;
            } else if (isMediaDocument(uri)) {
                // MediaProvider
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{
                        split[1]
                };

                return getDataColumn(context, contentUri, selection, selectionArgs);
            }

        } else if ("content".equalsIgnoreCase(uri.getScheme())) {// MediaStore (and general)
            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();

            return getDataColumn(context, uri, null, null);

        } else if ("file".equalsIgnoreCase(uri.getScheme())) {// File
            return uri.getPath();
        }

        return null;
    }

После получения пути к файлу загрузите его, чтобы написать URL-адрес amazon s3, используя

public static Response uploadFileSync(@Nullable String localFilePath, String urlToUploadTo,
                                          String contentTypeString) throws Exception {
        RequestBody requestBody;
        if (localFilePath == null) {
            requestBody = RequestBody.create(null, new byte[0]);
        } else {
            java.io.File file = new java.io.File(localFilePath);
            MediaType contentType = MediaType.parse(contentTypeString);
            requestBody = RequestBody.create(contentType, file);
            DebugLog.i("About to start upload of " + Utils.formatSize(file.length()));
        }

        DebugLog.d("Upload URL: " + urlToUploadTo);
        Request request = new Request.Builder()
                .url(urlToUploadTo)
                .put(requestBody)
                .build();

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(20, TimeUnit.SECONDS)
                .writeTimeout(3, TimeUnit.MINUTES)
                .readTimeout(3, TimeUnit.MINUTES)
                .build();

        // the callback is run on the same background thread.
        // for more information, please read Jake's comment here
        // https://stackoverflow.com/questions/24246783/okhttp-response-callbacks-on-the-main-thread/24248963#24248963
        return okHttpClient.newCall(request).execute();
    }

Получение ошибки при okHttpClient.newCall(request).execute()


person Sumit Ghawate    schedule 24.06.2021    source источник
comment
Опубликуйте свой код onActivityResult с кодом, в котором вы используете полученный uri. Где вы пытаетесь загрузить его или открыть поток. Вы даже не разместили заявление, которое вызывает эту ошибку.   -  person blackapps    schedule 24.06.2021
comment
Избавьтесь от Uri.fromFile(sourceFile). Используйте Uri, который вы получили в onActivityResult().   -  person CommonsWare    schedule 24.06.2021
comment
@blackapps Обновлен вопрос с более подробной информацией.   -  person Sumit Ghawate    schedule 24.06.2021
comment
On Activity result extracting the file path from Uri Не стоит делать такие гадости. Используйте uri напрямую, чтобы загрузить файл.   -  person blackapps    schedule 24.06.2021
comment
@blackapps нам нужен файловый объект для загрузки файла, а для получения файлового объекта нам нужен фактический путь к файлу.   -  person Sumit Ghawate    schedule 24.06.2021
comment
Нет, вам не нужен объект File. Вы спали, так как было добавлено использование потока uri/input.   -  person blackapps    schedule 24.06.2021