Android APIv29 FileNotFoundException EACCES(权限被拒绝)

时间:2019-10-17 10:08:43

标签: android kotlin filenotfoundexception android-external-storage android-api-levels

构建targetSdkVersion v29时无法访问存储。

这是我的gradle配置:

    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    ...
        minSdkVersion 15
        targetSdkVersion 29

请注意,为WRITE_EXTERNAL_STORAGE进行构建时,授予了targetSdkVersion 28权限,并且相同的设置可以正常工作。

这是我的实现方式:

        val outputFolder = File(baseFolder + File.separator + "Output Folder")
        if (!outputFolder.exists()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Files.createDirectory(outputFolder.toPath()) //This allways returns false with targetSdkVersion 29
            } else {
                if (!outputFolder.mkdirs()) {
                    Log.e("SaveRaw", "Unable to create folder for audio recording")
                }
            }
        }

        outputFile = File("$baseFolder/Output Folder/$filename")
        try {
            fileOutputStream = FileOutputStream(outputFile)
        } catch (e: FileNotFoundException) {
            e.printStackTrace() // allways throwing exception here, even if Output Folder exists 
        }

这是一个例外:

W/System.err: java.io.FileNotFoundException: /storage/emulated/0/Chirp Auto Tester/2019_10_17 10:44:43.raw: open failed: EACCES (Permission denied)
W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:496)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:235)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:186)

希望任何人都有答案,我在这里想念什么?

更新:

这里是baseFolder的来源。请注意,getExternalStorageDirectory是不推荐使用的方法。

        val baseFolder: String = if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            Environment.getExternalStorageDirectory().absolutePath
        } else {
            context.filesDir.absolutePath
        }

谢谢

5 个答案:

答案 0 :(得分:9)

Starting with Android 11的存储权限已被撤销,开发人员将需要考虑通过SAFMedia Store访问其所需存储的替代方法。目前,您可以通过在清单中的application标签内添加以下内容来继续使用所用的内容:

android:requestLegacyExternalStorage="true"

您可能要考虑将minSDK更改为19,并使用getExternalFilesDir()来获取不需要任何权限的路径。

答案 1 :(得分:0)

这可能可以帮助您在android级别2​​9中进行更改 https://developer.android.com/about/versions/10/behavior-changes-10

答案 2 :(得分:0)

当您的应用程序定位到Build.VERSION_CODES.Q时,此方法返回的路径将不再可供应用程序直接访问。

    val path = getExternalFilesDir(Environment.DIRECTORY_PICTURES.toString() + 
    File.separator + "Output Folder")
    val file = File(getExternalFilesDir(null), "filename.jpg")

有关更多详细信息,请访问Docs

答案 3 :(得分:0)

在Android版本10(API级别29)中,引入了范围存储的概念。根据Docs的说法:“为了使用户能够更好地控制文件并限制文件混乱,默认情况下,面向Android 10(API级别29)及更高版本的应用会获得对外部存储(或范围存储)的范围内访问权限。此类应用可以访问只能访问外部存储上特定于应用程序的目录以及该应用程序创建的特定媒体类型。”

对于Android版本10,您可以选择通过在应用程序标记内的AndroidManifest.xml中添加android:requestLegacyExternalStorage =“ true”来退出作用域存储

这是一个临时解决方案,仅适用于android版本10及其更高版本。另外,请确保您要求运行时权限来读取/写入外部存储。

答案 4 :(得分:-1)

您需要再次请求权限Manifest.permission.WRITE_EXTERNAL_STORAGE。

在9.0之前,您只请求Manifest.permission.READ_EXTERNAL_STORAGE,您还将获得Manifest.permission.WRITE_EXTERNAL_STORAGE,但从9.0开始,您只能获得一个已重新设置的权限。

原谅我可怜的英语。