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

Java Android 6.0打开失败:EACCES(权限被拒绝),java,android,android-6.0-marshmallow,Java,Android,Android 6.0 Marshmallow,我已将使用权限包括写入外部存储,装载卸载文件系统,读取外部存储添加到AndroidManifest.xml 当我尝试在Nexus5(Android 6.0)中运行我的应用程序时,它抛出了一个异常,如下所示: java.io.IOException:open失败:EACCES(权限被拒绝) 我尝试了另一款Android手机(Android 5.1),一切正常。代码如下: private File createImageFile() throws IOException { String t

我已将
使用权限
包括
写入外部存储
装载卸载文件系统
读取外部存储
添加到
AndroidManifest.xml

当我尝试在Nexus5(Android 6.0)中运行我的应用程序时,它抛出了一个异常,如下所示:

java.io.IOException:open失败:EACCES(权限被拒绝)

我尝试了另一款Android手机(Android 5.1),一切正常。代码如下:

private File createImageFile() throws IOException {
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(imageFileName, ".jpg", storageDir);
    currentPhotoPath = image.getAbsolutePath();
    return image;
}

安卓6.0在权限方面有差异吗

Android为Android 6.0(棉花糖)添加了新的权限模型

因此,您必须检查运行时权限:

什么是运行时权限?

通过Android 6.0棉花糖,谷歌引入了一种新的权限模型,使用户能够更好地理解应用程序为什么会请求特定权限。与用户在安装时盲目接受所有权限不同,现在系统会提示用户在应用程序使用过程中接受必要的权限

何时实施新模式?

在您选择在应用程序中以版本23为目标之前,它不需要完全支持。如果您的目标是版本22或更低,您的应用程序将在安装时请求所有权限,就像它在运行棉花糖以下操作系统的任何设备上一样

此信息取自此处:

请检查如何从此链接实施:

Android 6(棉花糖)中,即使用户在安装时接受了您的所有权限,他们也可以在以后决定从您手中拿走一些权限

快速解决方案,但不推荐:如果您将渐变中的
targetSdkVersion
更改为
22
,问题可能会得到解决

如何实施?(最佳实践)

  • 首先确定用户的设备是否为棉花糖设备:

    private boolean shouldAskPermission(){
    
    return(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP_MR1);
    
    }
    
  • 如果
    shouldAskPermission()
    返回
    true
    ,请请求您需要的权限:

    String[] perms = {"android.permission.WRITE_EXTERNAL_STORAGE"};
    
    int permsRequestCode = 200;
    
    requestPermissions(perms, permsRequestCode);
    
  • 方法
    requestPermissions(字符串[]权限,int requestCode)
    是在Android活动类中找到的公共方法

  • 您将在方法onRequestPermissionResult中收到请求的结果,如下所示:

    @Override
    public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults){
    
    switch(permsRequestCode){
    
        case 200:
    
            boolean writeAccepted = grantResults[0]==PackageManager.PERMISSION_GRANTED;
    
            break;
    
    }
    
    }
    
  • 在收到结果后,您需要适当地处理它们

    建议的权限流:

    更多信息:

    使用棉花糖设备的用户现在可以通过应用程序设置撤销危险权限

    Android将一些权限定义为“危险的”和一些权限定义为“正常的”,这两种权限在应用程序的清单中都是必需的,但只有危险的权限需要运行时请求

    如果您选择不实现新的权限模型(运行时请求),则撤销权限可能会导致不必要的用户体验,在某些情况下还会导致应用程序崩溃

    下表列出了所有当前危险权限及其各自的组:

    如果用户接受一个组/类别中的一个权限,他们将接受整个组

    来源:

    使用Dexter库:

    你可以用。简化运行时请求权限过程的Android库。

    您也可以使用向后兼容

    例如:

    private static final int REQUEST_CODE = 0x11;
    
    String[] permissions = {"android.permission.WRITE_EXTERNAL_STORAGE"};
    ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE); // without sdk version check
    
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
        if (requestCode == REQUEST_CODE) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // save file
            } else {
                Toast.makeText(getApplicationContext(), "PERMISSION_DENIED", Toast.LENGTH_SHORT).show();
            }
        }
    }
    

    从API-23开始,您需要在活动中声明权限,即使您已经在清单中声明了权限

    // Storage Permissions variables
    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };
    
    //persmission method.
     public static void verifyStoragePermissions(Activity activity) {
        // Check if we have read or write permission
        int writePermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        int readPermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);
    
        if (writePermission != PackageManager.PERMISSION_GRANTED || readPermission != PackageManager.PERMISSION_GRANTED) {
            // We don't have permission so prompt the user
            ActivityCompat.requestPermissions(
                    activity,
                    PERMISSIONS_STORAGE,
                    REQUEST_EXTERNAL_STORAGE
            );
        }
    }
    
    只需使用call
    verifyStoragePermissions(此选项)在onCreate中。
    
    希望如此。

    如果你很懒,只需将targetSdkVersion降级到22(在棒棒糖之前)

    这对我很有效


    转到设置->应用程序->应用程序->提供存储、联系人等权限。

    我遇到了同样的问题


    可能是你的手机安全机制造成的。您可以转到“设置”以授权写入/读取权限。

    对于我来说,即使在完成此处所述的所有操作后,我的手机仍以USB作为MTP连接。把它改成“只收费”对我来说很有效。

    谷歌在Android上有一个新功能Q:外部存储的过滤视图。快速修复方法是在AndroidManifest.xml文件中添加以下代码:

    <manifest ... >
        <!-- This attribute is "false" by default on apps targeting Android Q. -->
        <application android:requestLegacyExternalStorage="true" ... >
         ...
        </application>
    </manifest>
    
    
    

    我认为您应该检查安卓6.0上新增的权限功能,并根据这些功能更改代码。。!!我看了这一页,没发现什么特别的。@samuel40:我想你不知道新型号。这是一个旧的,所以请检查此->检查下面的答案,并参考链接,以实现新的模式。。!!对我来说,在搜索谷歌后,我尝试了很多方法,但都没有成功。我打开设置,发现Android 6.0在
    Settings>Privacy and safety>App permissions>Storage
    部分阻止了我的应用程序权限。在存储权限部分启用后,它就可以工作了。希望对其他人有所帮助people@samuel40:如果这对你有用,请检查->非常感谢,我会检查的。我理解他们为什么这么做,但是。。。当你有十几个权限,必须找到每个权限的使用位置并添加所有代码时,这有点痛苦…@Michael:是的,你是对的!但对我们来说,用户的安全性要比投资信息的安全性重要得多!!我有这项检查,权限已授予,但我无法归档.createTempFile(前缀,sufix,目录);没有发现任何有用的东西是的,这对我使用安卓6或更高版本很有效。至少本地可以在回购中使用版本2。您仍然可以推送版本23。非常好的答案,谢谢!有一件事:perms字符串应该是“android.permission.WRITE\u EXTERNAL\u STORAGE”,而不是“android.permission.WRITE\u EXTER”