仅在Android 6.0中没有此类文件或目录

时间:2016-07-16 12:28:13

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

下面的代码在Marshmallow之前的设备上正常工作,但在Marshmallow中没有。

这些是Manifest中的权限

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

这是代码

public void saveImageToSDCard(Bitmap bitmap) {
    File myDir = new File(
            Environment
                    .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            pref.getGalleryName());

    myDir.mkdirs();
    Random generator = new Random();
    int n = 10000;
    n = generator.nextInt(n);
    String fname = "Wallpaper-" + n + ".jpg";
    File file = new File(myDir, fname);
    if (file.exists())
        file.delete();
    try {
        FileOutputStream out = new FileOutputStream(file);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
        out.flush();
        out.close();
        Uri uri = getImageContentUri(_context,file);

        Log.d(TAG, "Wallpaper saved to: " + file.getAbsolutePath());

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

当我手动允许存储权限时,相同的代码可以正常工作

以下是Nitesh Pareek给出的解决方案。

private boolean hasPermissions(Context context, String[] permissions) {
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
        for (String permission : permissions) {
            if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
    }
    return true;
}
String[] PERMISSIONS = new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE};

    if (!hasPermissions(this, PERMISSIONS)) {
        ActivityCompat.requestPermissions(this, PERMISSIONS, 11);
        return;
    }

4 个答案:

答案 0 :(得分:2)

从Android 6.0(API级别23)开始,用户在应用运行时向应用授予权限,而不是在安装应用时授予权限。

这就是它在pre-lolipop版本中工作的原因,而不是在API 23上。仅在Android Manifest中的权限不足,您还需要在运行时添加它们。请参阅here for more details.

答案 1 :(得分:1)

为marshmallow或更新版本的运行时授予读写权限。 如下所示: -

String[] PERMISSIONS = new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE};

if (!hasPermissions(this, PERMISSIONS)) {
            ActivityCompat.requestPermissions(this, PERMISSIONS, 11);
            return;
        }

private boolean hasPermissions(Context context, String... permissions) {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
            for (String permission : permissions) {
                if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                    return false;
                }
            }
        }
        return true;
    }

答案 2 :(得分:1)

您需要在运行时获取应用程序权限,而不是在安装/更新时采用约定

  

从Android 6.0(API级别23)开始,用户授予权限   应用程序运行时的应用程序,而非安装应用程序时的应用程序。这个   方法简化了应用安装过程,因为用户没有   需要在安装或更新应用时授予权限

获取更多帮助: Requesting Permissions at Run Time

通过关注文档并进行一些谷歌搜索,最后我编译了下面的代码以有效地处理运行时权限

要使其正常工作,您需要按照以下说明操作:

调用此方法检查用户是否授予了存储权限? 如果没有,那么你需要请求它

public static boolean isStoragePermissionGranted(Activity activity) {
    boolean flag = false;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        flag = activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
    }
    return flag;
}

调用此方法以请求存储权限

public static void requestStoragePermission(Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (isStoragePermissionGranted(activity)) {
            return;
        }

        // Fire off an async request to actually get the permission
        // This will show the standard permission request dialog UI
        activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_CODE_STORAGE_PERMISSION);
    }
}

在您的活动中实施此方法以处理权限回调的响应

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode) {
        case REQUEST_CODE_STORAGE_PERMISSION:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (grantResults.length > 0) {
                    if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                        boolean shouldShowRationale = shouldShowRequestPermissionRationale(permissions[0]);
                        if (!shouldShowRationale) {
                            // user denied flagging NEVER ASK AGAIN, you can either enable some fall back,
                            // disable features of your app or open another dialog explaining again the permission and directing to
                            // the app setting
                            dialogReasonStoragePermissionToSettings(this);
                        } else if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permissions[0])) {
                            // user denied WITHOUT never ask again, this is a good place to explain the user
                            // why you need the permission and ask if he want to accept it (the rationale)
                            dialogReasonStoragePermission(this);
                        }
                    } /*else {
                        // Do on permission granted work here
                    }*/
                }
            }

            break;
    }
}

public static void dialogReasonStoragePermission(final Activity activity) {
    AlertDialog.Builder builder = new AlertDialog.Builder(activity);
    builder.setMessage(activity.getString(R.string.reason_storage_permission));
    builder.setCancelable(false);
    builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            requestStoragePermission(activity);
        }
    });
    builder.setNegativeButton("Dismiss", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            dialog.dismiss();
        }
    });

    AlertDialog dialog = builder.create();
    dialog.show();
}

public static void dialogReasonStoragePermissionToSettings(final Activity activity) {
    AlertDialog.Builder builder = new AlertDialog.Builder(activity);
    builder.setMessage(activity.getString(R.string.reason_storage_permission));
    builder.setCancelable(false);
    builder.setPositiveButton("Go to Settings", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            goToAppDetailsForPermissionSettings(activity);
        }
    });
    builder.setNegativeButton("Dismiss", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            dialog.dismiss();
        }
    });

    AlertDialog dialog = builder.create();
    dialog.show();
}

private static final int REQUEST_CODE_APP_DETAILS_PERMISSION_SETTING = 3995;
private static void goToAppDetailsForPermissionSettings(Activity activity) {
    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
    intent.setData(uri);
    activity.startActivityForResult(intent, REQUEST_CODE_APP_DETAILS_PERMISSION_SETTING);
}

答案 3 :(得分:0)

我没有为您提供直接代码,但是这里有一个原因API级别23引入了一个新的Permission结构以获得更高的安全性,这是一个简短但很糟糕的描述,在文档中here

从Android 6.0(API级别23)开始,用户在应用程序运行时向应用程序授予权限,而不是在安装应用程序时。此方法简化了应用安装过程,因为用户在安装或更新应用时无需授予权限。它还使用户可以更好地控制应用程序的功能;例如,用户可以选择让相机应用程序访问相机,但不能访问设备位置。用户可以随时撤消权限,方法是转到应用程序的“设置”屏幕。

代码很好,只需要添加一些额外的东西,然后运行时权限进行存储。

阅读this blog以深入了解有关运行时权限的所有内容,让我对此有了清晰的了解,希望对您也有帮助。

由于