根据这个:http://developer.android.com/preview/features/runtime-permissions.html#coding一个应用程序可以检查运行时权限和请求权限,如果它还没有被授予。弹出如下对话框:

如果用户拒绝一个重要的权限,在我看来,应用程序应该显示一个解释为什么需要权限和什么影响拒绝。该对话框有两个选项:

重试(再次请求许可) 拒绝(应用程序将工作没有该许可)。

但是,如果用户选中“Never ask again”,则不应该显示带有解释的第二个对话框,特别是如果用户之前已经拒绝了一次。 现在的问题是:我的应用程序如何知道用户是否选中了Never ask again?IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)没有给我这个信息。

第二个问题是:谷歌是否计划在权限对话框中包含一个自定义消息,以解释为什么应用程序需要权限?这样就不会出现第二个对话框,这肯定会带来更好的用户体验。


当前回答

shouldShowRequestPermissionRationale根据之前权限请求中的用户首选项返回true或false。

如果用户只是拒绝权限(不是永远)shouldShowRequestPermissionRationale将返回true。如果永远拒绝许可,则返回false。窍门是即使用户允许了权限shouldShowRequestPermissionRationale也会返回false。

因此,我们可以结合这两个条件来得到永不再问的选择与否。

因此,如果用户不允许权限,并且shouldShowRequestPermissionRationale返回false,那么这意味着用户选择永远不会再次请求权限。

https://stackoverflow.com/a/58114769/5151336

其他回答

我发现这个问题的方法对我来说有点新鲜。我必须保留一个参考,如果用户曾经选择了一个决定。通过这种方式,如果权限没有被授予,我可以告诉用户是第一次在那里,并且应该提示看到权限弹出,或者用户暂时或永久地拒绝它。

psudocode:

if( granted ) {
 // you are set
} else if( requiresRationale() ) {
 // in the ui let the user know he has to tap and launch permission
 button.onSetClickListener { requestPermission() }
} else if( sharedPreferences.getBoolean("permission", false) ) {
  // so user has already decided to deny permission, then it is permanent
  launchAppSettings()
} else {
  // user's first encounter, request permission
  requestPermission()
}

演示文件以GIF格式附在自述文件中。 https://github.com/juanmendez/android-sdk-updates/tree/api/android-permissions/single

如果你想检测所有的“状态”(第一次被拒绝,刚刚被拒绝,刚刚被“Never Ask Again”拒绝或永久拒绝),你可以做以下事情:

创建2个布尔值:

private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;

在请求允许之前设置第一个:

beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

在你的onRequestPermissionsResult方法中设置第二个:

afterClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

使用下面的“真值表”在onRequestPermissionsResult()中做任何你需要的事情(在检查你仍然没有权限之后):

// before after
// FALSE  FALSE  =  Was denied permanently, still denied permanently --> App Settings
// FALSE  TRUE   =  First time deny, not denied permanently yet --> Nothing
// TRUE   FALSE  =  Just been permanently denied --> Changing my caption to "Go to app settings to edit permissions"
// TRUE   TRUE   =  Wasn't denied permanently, still not denied permanently --> Nothing

一个有用的函数来确定任意权限是否被阻止请求(在Kotlin中):

private fun isPermissionBlockedFromAsking(activity: Activity, permission: String): Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        return ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED
            && !activity.shouldShowRequestPermissionRationale(permission)
            && PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false)
    }
    return false
}

当你第一次请求一个权限时,需要设置一个共享首选项布尔值为true,其中包含你想要的权限名称(例如android.Manifest.permission.READ_PHONE_STATE)。


解释:

Build.VERSION。SDK_INT >= Build.VERSION_CODES。因为有些代码只能在API级别23+上运行。

ContextCompat。checkSelfPermission(activity, permission) != PackageManager。permission_granting检查我们还没有权限。

activity.shouldShowRequestPermissionRationale(permission)来检查用户是否再次拒绝了应用程序的请求。由于这个函数的特性,还需要下面这行代码。

PreferenceManager.getDefaultSharedPreferences(活动)。getBoolean(permission, false)用于区分“Never asked”和“Never ask again”状态(以及在第一次权限请求时将值设置为true),因为前一行不会返回此信息。

您可以通过检查权限原理是否显示在onRequestPermissionsResult()回调方法中来确定它。如果您发现任何权限集永远不会再次请求,您可以请求用户从设置中授予权限。

我的完整实现如下所示。它适用于单个或多个权限请求。使用以下或直接使用我的库。

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if(permissions.length == 0){
        return;
    }
    boolean allPermissionsGranted = true;
    if(grantResults.length>0){
        for(int grantResult: grantResults){
            if(grantResult != PackageManager.PERMISSION_GRANTED){
                allPermissionsGranted = false;
                break;
            }
        }
    }
    if(!allPermissionsGranted){
        boolean somePermissionsForeverDenied = false;
        for(String permission: permissions){
            if(ActivityCompat.shouldShowRequestPermissionRationale(this, permission)){
                //denied
                Log.e("denied", permission);
            }else{
                if(ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED){
                    //allowed
                    Log.e("allowed", permission);
                } else{
                    //set to never ask again
                    Log.e("set to never ask again", permission);
                    somePermissionsForeverDenied = true;
                }
            }
        }
        if(somePermissionsForeverDenied){
            final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
            alertDialogBuilder.setTitle("Permissions Required")
                    .setMessage("You have forcefully denied some of the required permissions " +
                            "for this action. Please open settings, go to permissions and allow them.")
                    .setPositiveButton("Settings", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                                    Uri.fromParts("package", getPackageName(), null));
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        }
                    })
                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    })
                    .setCancelable(false)
                    .create()
                    .show();
        }
    } else {
        switch (requestCode) {
            //act according to the request code used while requesting the permission(s).
        }
    }
}

请不要为这个解决办法向我扔石头。

这是可行的,但有点“俗气”。

当调用requestPermissions时,注册当前时间。

        mAskedPermissionTime = System.currentTimeMillis();

然后在onRequestPermissionsResult中

如果结果不允许,请再次检查时间。

 if (System.currentTimeMillis() - mAskedPermissionTime < 100)

由于用户不可能那么快地点击拒绝按钮,我们知道他选择了“永不再问”,因为回调是即时的。

使用风险自负。