Android 6.0+ java.io.FileNotFoundException :(权限被拒绝)

时间:2017-11-09 09:21:08

标签: android permissions android-manifest android-6.0-marshmallow

最近,我遇到了关于许可问题的一个非常奇怪的问题,它让我困惑了几天,我希望有人能帮我弄清楚发生了什么。谢谢!

问题在于: 出于某种原因,我需要应用存储权限来保存一些照片,并且我已将权限添加到AndroidManifestival.xml:

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

当然,我知道我必须在 Android 6.0 后的代码中申请存储权限,这是我申请许可的代码:

public static boolean isGrantExternalRW(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && (context.checkSelfPermission(
            Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {

        ((Activity)context).requestPermissions(new String[]{
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        }, Constants.PERMISSION_REQUEST_CODE);

        return false;
    }

    return true;
}

我在保存照片之前使用过这种方法,并且出现了权限对话框,我已经检查了它。我在应用程序设置中检查了应用程序权限,没关系。

这是我用来将位图保存到文件的方法:

public static String savePhotoToSDCard(Bitmap bitmap, String photoName) {
    String absolutePath = "";

    String state = Environment.getExternalStorageState();
    Log.e("file", "---------------------" + state);
    File newsDir =  new File(Environment.getExternalStorageDirectory().toString()
            + File.separator + "photo");


    if (!newsDir.exists()) {
        newsDir.mkdirs();
    }

    File picFile = new File(newsDir, photoName + ".png");
    absolutePath = picFile.getAbsolutePath();

    if (picFile.exists()) {
        picFile.delete();
    }

    if (photoName.equals("avatar")) {          
        int ratio = 2;        
        Bitmap result = Bitmap.createBitmap(bitmap.getWidth() / ratio, bitmap.getHeight() / ratio, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        Rect rect = new Rect(0, 0, bitmap.getWidth() / ratio, bitmap.getHeight() / ratio);
        canvas.drawBitmap(bitmap, null, rect, null);
    }

    try {
        FileOutputStream fileOutputStream = new FileOutputStream(picFile);
        if (bitmap != null) {

            if (bitmap.compress(Bitmap.CompressFormat.PNG, 30, fileOutputStream)) {
                fileOutputStream.flush();
                Log.d("Photo", "---------------------------fileOutputStream.flush");
                fileOutputStream.close();
            }
        }
    } catch (FileNotFoundException e) {
        Log.e("File", "----------------------------" + e.toString());
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return absolutePath;
}

当我运行应用程序时,它出错了,这是日志:

  

java.io.FileNotFoundException:/storage/emulated/photo/avatar.png(permission denied)

但最奇怪的是,当我向AndroidManifestival.xml添加两次存储权限时,它有效!

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

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

那么,问题是什么?请帮忙。

4 个答案:

答案 0 :(得分:2)

幸运的是,我终于解决了我的问题。原因如下: 存储权限与以下依赖项冲突:

compile 'com.github.vungle:vungle-android-sdk:5.3.0'

当我添加依赖项时,系统无法识别我申请的存储权限(虽然我在AndroidManifest.xml中添加了两次,但它有效),但当我删除它时,一切正常!这种依赖用于将广告添加到应用中,但现在我不得不放弃它。

答案 1 :(得分:0)

我认为解决方案类似于Requesting Permissions at Run Time

你有handled the permissions request response吗?

与这些链接相关,您必须在代码中正确实现这些步骤:

首先: 尝试使用它来请求权限:

 boolean permissionGranted = ActivityCompat.checkSelfPermission(this, Manifest.permission......) == PackageManager.PERMISSION_GRANTED;
    if(permissionGranted) {
        // {Some Code}
    } else {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission....}, 200);
    }

第二: OnRequestPermissionsResultCallback的实施

...implements  ActivityCompat.OnRequestPermissionsResultCallback {

第三: 覆盖onRequestPermissionsResult方法

 @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 200: {
                if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // {Some Code}
                }
            }
        }
    }

答案 2 :(得分:0)

在启动画面或打开相机的地方调用此方法。

 public static boolean checkAndRequestPermissions(Context context) {
                int cameraPermission = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA);
                int readfilePermission = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE);
                int writefilePermission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
                if (cameraPermission != PackageManager.PERMISSION_GRANTED) {
                    listPermissionsNeeded.add(Manifest.permission.CAMERA);
                }
                        if (readfilePermission != PackageManager.PERMISSION_GRANTED) {
                    listPermissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
                }
                if (writefilePermission != PackageManager.PERMISSION_GRANTED) {
                    listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
                }
                if (!listPermissionsNeeded.isEmpty()) {
                    ActivityCompat.requestPermissions((Activity) context, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
                    return false;
                }
                return true;
            }

在AndroidManifestival.xml中,您需要添加

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

答案 3 :(得分:0)

你能尝试这样吗,我想你一旦创建它就会删除它。

if (new File(newsDir, photoName + ".png").exists()) {
       new File(newsDir, photoName + ".png").delete();
}
File picFile = new File(newsDir, photoName + ".png");
absolutePath = picFile.getAbsolutePath();

并代替

Environment.getexternalstoragedirectory().toString()
use this 
Environment.getexternalstoragedirectory().getabsolutepath()