【问题标题】:Writing external storage doesn't work until I restart the application on Android M在我重新启动 Android M 上的应用程序之前,无法写入外部存储
【发布时间】:2015-08-18 21:25:42
【问题描述】:

我对新的权限系统有疑问。我修改了我的代码以请求 WRITE_EXTERNAL_STORAGE 的许可。但是我的应用程序无法写入(或读取)SD卡,直到我重新启动应用程序(当然我在对话框中允许它)。之后它工作正常。

这不是一个新应用,我已经在清单中声明了 WRITE_EXTERNAL_STORAGE,在早期的系统上它运行良好。

我正在使用 checkSelfPermission 和 requestPermissions 方法,当我向 sd 卡发出读取或写入请求时,我遇到了一个我没有权限的异常。

有人知道我错过了什么吗?还是我遇到了错误?

SDK 版本是最新的(几小时前更新),我正在模拟器上测试。

【问题讨论】:

  • 只是为了澄清一下:您是说您添加了代码来请求读取/写入外部存储的权限,当提示您批准该权限但不允许它重新启动应用程序时,您注意到了问题?
  • 是的,我已经添加了请求权限的代码,出现了对话框,我允许了它,但是在我重新启动应用程序之前读/写时仍然出现异常。之后它工作正常,可以读写存储。每次我在设置中撤销权限时都会发生这种情况,在应用程序中重新启用,并且在重新启动之前它不起作用。我不知道是什么导致了这个问题,是设计使然还是 SDK 有问题?
  • 对于这种类型的权限,它应该会自动重新启动您的应用程序。这些权限会导致您的应用程序被放入特殊的(Linux 内核理解)组和 SE Linux 上下文中。为了让您的应用程序的进程实际上具有正确的 GID 和 SE 上下文,必须在必要的配置更改后重新启动它。这是需要重新启动应用程序的情况之一,但框架应该已经为您强制执行此操作。
  • 我现在明白了,谢谢。我在文档中看到,某些权限需要重新启动应用程序,但不知道是这种情况。那样的话,能不能通过代码触发重启?
  • @andrew code.google.com/p/android-developer-preview/issues/…我比这早几个小时创建了我的问题,但这个更详细,所以我想这就是为什么我的问题被标记为重复。

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


【解决方案1】:

当用户允许来自RuntimePermission dialogWRITE_EXTERNAL_STORAGE 权限时,您需要Callback

首先你需要在你的Activity中实现ActivityCompat类的OnRequestPermissionsResultCallbackListener并重写void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)方法来检查用户是允许还是拒绝权限

你可以这样做:

int REQUEST_STORAGE = 1;

private void checkExternalStoragePermissions() {
    if (hasStoragePermissionGranted()) {
        //You can do what whatever you want to do as permission is granted
    } else {
        requestExternalStoragePermission();
    }
}

public boolean hasStoragePermissionGranted(){
        return  ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}

public void requestExternalStoragePermission() {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
        ActivityCompat.requestPermissions(MainActivity.this, {Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_STORAGE);
    }
}

这是onRequestPermissionsResult() 方法将在用户允许或拒绝运行时权限对话框中的权限时调用。

您还可以处理用户已选中从不显示运行时权限对话框的情况。

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

        if (requestCode == REQUEST_STORAGE) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
               //User allow from permission dialog
               //You can do what whatever you want to do as permission is granted
            } else if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivtity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
               //User has deny from permission dialog
               Snackbar.make(mainLayout, getResources().getString("Please enable storage permission"),Snackbar.LENGTH_INDEFINITE)
                      .setAction("OK", new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                ActivityCompat.requestPermissions(MainActivity.this, {Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE);
                            }
                       })
                       .show();
            } else {
                // User has deny permission and checked never show permission dialog so you can redirect to Application settings page
                Snackbar.make(mainLayout, getResources().getString("Please enable permission from settings"),Snackbar.LENGTH_INDEFINITE)
                     .setAction("OK", new View.OnClickListener() {
                           @Override
                           public void onClick(View view) {
                                Intent intent = new Intent();                    intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                Uri uri = Uri.fromParts("package", MainActivity.this.getPackageName(), null);
                                intent.setData(uri);
                                startActivity(intent);
                            }
                       })
                       .show();
            }
        }
}

这里我使用Snackbar 向用户显示有关权限的相关消息,mainLayoutActivity's Main Layout 的ID。

希望对你有帮助。

【讨论】:

  • SDK 有一个 bug,从那以后就被修复了(显然是因为在那之后有大量的更新)。我接受这个答案,因为这是这样做的方法。
猜你喜欢
  • 1970-01-01
  • 2012-08-11
  • 2016-01-08
  • 2016-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-08
  • 1970-01-01
相关资源
最近更新 更多