简体   繁体   English

Android 11 打开失败:EACCES(权限被拒绝)

[英]Android 11 open failed: EACCES (Permission denied)

I am developing an app.我正在开发一个应用程序。 In which I am uploading different file types (eg docx, pdf, zip) to a WAMP Server.我在其中将不同的文件类型(例如 docx、pdf、zip)上传到 WAMP 服务器。 Below is path of file to my internal Storage.下面是文件到我的内部存储的路径。

/storage/emulated/0/WhatsApp/Media/WhatsApp Documents/api.txt /storage/emulated/0/WhatsApp/Media/WhatsApp Documents/api.txt

I have added and allowed storage permission in Manifest file and also on runtime for reading a file.我已经在 Manifest 文件中添加并允许存储权限,并在运行时读取文件。 However there is no Internal Storage Permission request available.但是,没有可用的内部存储权限请求。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

and also for Android 10 I was using this attribute also还有 Android 10 我也在使用这个属性

android:requestLegacyExternalStorage="true"

But i am getting this error on Android 11 OS aka Android R onboard Samsung Galaxy when I am reading file from Internal Storage for uploading.但是当我从内部存储读取文件进行上传时,我在 Android 11 OS aka Android R onboard Samsung Galaxy 上收到此错误。

java.io.FileNotFoundException: /storage/emulated/0/WhatsApp/Media/WhatsApp Documents/api.txt: open failed: EACCES (Permission denied) java.io.FileNotFoundException:/storage/emulated/0/WhatsApp/Media/WhatsApp Documents/api.txt:打开失败:EACCES(权限被拒绝)

On An Android 11 device your app only has access to its own files.在 Android 11 设备上,您的应用只能访问自己的文件。

And to general mediafies in public directories.以及公共目录中的一般媒体。

Try to list the files in that whatsapp directory and you will see that they are not listed.尝试列出该 whatsapp 目录中的文件,您将看到它们未列出。

You have two options to read the file.您有两个选项来读取文件。

  1. Let the user pick the file with ACTION_OPEN_DOCUMENT.让用户选择带有 ACTION_OPEN_DOCUMENT 的文件。
  2. Request MANAGE_EXTERNAL_STORAGE in manifest and let the user confirm.在 manifest 中请求 MANAGE_EXTERNAL_STORAGE 并让用户确认。

You can try to use the android:preserveLegacyExternalStorage="true" tag in the manifest file in the application tag.您可以尝试在应用程序标记中的清单文件中使用android:preserveLegacyExternalStorage="true"标记。 This tag is used to access the storage in the android 11 devices.该标签用于访问 android 11 器件中的存储。 And for more detail follow this link it will explain you more as per your requirement.有关更多详细信息,请点击此链接,它将根据您的要求向您解释更多。

I search a lot of time and get the solution that adds <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> in the manifest file and try to get the file access permission in the android 11 phones.我搜索了很多时间,得到了在清单文件中添加<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>的解决方案,并尝试在 android 11 手机中获取文件访问权限。 Then you will open and read the file from the storage.然后您将打开并从存储中读取文件。

But the thing is that the play store does not allow you to use of the MANAGE_EXTERNAL_STORAGE permission in your app.但问题是 Play 商店不允许您在应用程序中使用MANAGE_EXTERNAL_STORAGE权限。 it will take time to give access to the developer to use it to access all the files.授予开发人员访问权限以使用它访问所有文件需要时间。 Here the link is这里的链接是

On An Android 11 device your app only has access to its own files.在 Android 11 设备上,您的应用只能访问自己的文件。

And to general mediafies in public directories.以及公共目录中的一般媒体。

Try to list the files in that whatsapp directory and you will see that they are not listed.尝试列出该 whatsapp 目录中的文件,您将看到它们未列出。

You have two options to read the file.您有两个选项来读取文件。

Let the user pick the file with ACTION_OPEN_DOCUMENT.让用户选择带有 ACTION_OPEN_DOCUMENT 的文件。 Request MANAGE_EXTERNAL_STORAGE in manifest and let the user confirm.在 manifest 中请求 MANAGE_EXTERNAL_STORAGE 并让用户确认。

Ordinary request is not working for the MANAGE_EXTERNAL_STORAGE permission.普通请求不适用于 MANAGE_EXTERNAL_STORAGE 权限。 user must be accepted this permission in Android setting用户必须在 Android 设置中接受此权限在此处输入图像描述

Try to get path with this method.....尝试用这种方法获取路径......

public static String getDriveFile(Context context, Uri uri) { Uri returnUri = uri;公共 static 字符串 getDriveFile(上下文上下文,Uri uri){ Uri returnUri = uri; Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null); Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, Z309A6259686489DFF0DFF

    int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
    int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
    returnCursor.moveToFirst();
    String name = (returnCursor.getString(nameIndex));
    String size = (Long.toString(returnCursor.getLong(sizeIndex)));
    File file = new File(context.getCacheDir(), name);
    try {
        InputStream inputStream = context.getContentResolver().openInputStream(uri);
        FileOutputStream outputStream = new FileOutputStream(file);
        int read = 0;
        int maxBufferSize = 1 * 1024 * 1024;
        int bytesAvailable = inputStream.available();

        //int bufferSize = 1024;
        int bufferSize = Math.min(bytesAvailable, maxBufferSize);

        final byte[] buffers = new byte[bufferSize];
        while ((read = inputStream.read(buffers)) != -1) {
            outputStream.write(buffers, 0, read);
        }
        Log.e("File Size", "Size " + file.length());
        inputStream.close();
        outputStream.close();
        Log.e("File Path", "Path " + file.getPath());
        Log.e("File Size", "Size " + file.length());
    } catch (Exception e) {
        Log.e("Exception", e.getMessage());
    }
    return file.getPath();

}

I worked on Android application based on Cordova and I had to change the version the application was focused on to save files in the device.我在基于 Cordova 的 Android 应用程序上工作,我不得不更改应用程序所关注的版本以将文件保存在设备中。

I change the API Level version to 28 and works correctly.我将 API 级别版本更改为 28 并正常工作。 This change is used to avoid the scoped storage feature added on Android 10.此更改用于避免在 Android 10 上添加范围存储功能。

This information is extracted from this page: https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage此信息摘自此页面: https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage

I hope this information is helpful.我希望这些信息对你有用。

First, check whether you have implemented scoped storage logic in-app.首先,检查您是否在应用内实现了范围存储逻辑。 You can also use android:requestLegacyExternalStorage="true" But this legacyStoragePermission is limited to version 10. You need to implement scoped logic.您也可以使用android:requestLegacyExternalStorage="true"但是这个 legacyStoragePermission 仅限于版本 10。您需要实现范围逻辑。

Also, check whether your targetSDKVersion value is 30 or greater or not, this is needed if you are using the app in Device android version 30 or more.另外,请检查您的 targetSDKVersion 值是否为 30 或更大,如果您在 Device android 版本 30 或更高版本中使用该应用程序,则需要这样做。

You can change allowBackup from true to false in Manifest's application part.您可以在 Manifest 的应用程序部分将 allowBackup 从 true 更改为 false。 It worked for me.它对我有用。

android:allowBackup="false"

I spent a week getting the info on how to read files from External storage on Android 11 API 29 and Later.我花了一周时间获取有关如何从 Android 11 API 29 及更高版本上的外部存储读取文件的信息。


You still need Manifest permission READ_EXTERNAL_STORAGE.您仍然需要清单权限 READ_EXTERNAL_STORAGE。

        try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            // Open a specific media item using ParcelFileDescriptor.
            ContentResolver resolver = getApplicationContext()
                    .getContentResolver();

            // "rw" for read-and-write;
            // "rwt" for truncating or overwriting existing file contents.
            String readOnlyMode = "r";
            // uri - I have got from onActivityResult
            //uri = data.getData();
            ParcelFileDescriptor parcelFile = resolver.openFileDescriptor(uri, readOnlyMode);

            FileReader fileReader = new FileReader(parcelFile.getFileDescriptor());
            BufferedReader reader = new BufferedReader(fileReader);

            String line;
            while ((line = reader.readLine()) != null) {
                //Your action here!!!
            }
            reader.close();
            fileReader.close();

        }
    } catch (IOException e) {
        e.printStackTrace();
    }

Read this: Open a media file.阅读:打开一个媒体文件。

For Android 11 or above use the code below on the onCreate() of the activity.对于 Android 11 或更高版本,请在活动的 onCreate() 上使用以下代码。 It will run once and ask for permission.它将运行一次并请求许可。

        if (Build.VERSION.SDK_INT >= 30){
        if (!Environment.isExternalStorageManager()){
            Intent getpermission = new Intent();
            getpermission.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
            startActivity(getpermission);
        }
    }
    

Next declare the MANAGE_EXTERNAL_STORAGE permission in the manifest.接下来在清单中声明 MANAGE_EXTERNAL_STORAGE 权限。

However, the problem with this method is that you cannot upload it to play store if you don't have a good reason on why you need access to all files.但是,这种方法的问题是,如果您没有充分的理由说明为什么需要访问所有文件,则无法将其上传到 Play 商店。

from android 10, it is not possible to access all the files through your app, so while saving data for example image, use following code and then you can read it normally.从 Android 10 开始,无法通过您的应用访问所有文件,因此在保存数据(例如图像)时,使用以下代码即可正常读取。 getExternalFilesDir is important getExternalFilesDir 很重要

File file=new File(getActivity().getApplicationContext().getExternalFilesDir(null),"/scantempo"+"/Image_" + System.currentTimeMillis() + ".jpg");
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
            out.flush();
            out.close();
            Uri uri=Uri.fromFile(file);
            return uri;

After you update your app to target Android 11, the system ignores the requestLegacyExternalStorage flag.将应用更新为目标 Android 11 后,系统会忽略 requestLegacyExternalStorage 标志。

For read files from external storage following codes:对于从外部存储读取文件的代码如下:

fun startFilePicker(activity: Activity, requestCode: Int) {

        val pickIntent: Intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
            putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
            type = "*/*"
        }
        activity.startActivityForResult(pickIntent, requestCode)
    }
  override fun onActivityResult(requestCode : Int , resultCode : Int , data : Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        val fileUri=data.data

       val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
                Intent.FLAG_GRANT_WRITE_URI_PERMISSION

        context.contentResolver.takePersistableUriPermission(
           fileUri,
            takeFlags
        )
}

Create temp file创建临时文件

fun createTempFileForUpload(context:Context,fileUri:Uri){
 val docFile = DocumentFile.fromSingleUri(context, fileUri)
                    val fileName: String = if (docFile == null || docFile.name.isNullOrBlank()) {
                        FilenameUtils.getName(fileUri.path)
                    } else {
                        docFile.name!!
                    }

                        val tempFile = File.createTempFile("tempFile", "tmp")
                        val ins: InputStream = context.contentResolver.openInputStream(fileUri)!!
                        val out: OutputStream = FileOutputStream(tempFile)
                        val buf = ByteArray(1024)
                        var len: Int = ins.read(buf)
                        while (len > 0) {
                            out.write(buf, 0, len)
                            len = ins.read(buf)
                        }
                        out.close()
                        ins.close()
                        tempFile.mkdirs()
}

Then you can upload temp file.然后你可以上传临时文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM