【问题标题】:Android M permission issue with Dialog "Don't ask again"对话框“不再询问”的 Android M 权限问题
【发布时间】:2017-03-31 23:24:14
【问题描述】:

这是一种通过 Scoped Directory Access 授予权限的更简单方法,但对话框会显示一个名为“不再询问”的复选框。如果用户选择 Don't ask again 并拒绝该请求,您的应用程序对给定目录的所有未来请求都将被自动拒绝,并且不会向用户显示任何请求 UI。 如果用户后悔或错误地点击了该复选框,应用程序如何补救?应用无法获得权限对话框。

我们该如何处理?

【问题讨论】:

  • 应用程序如何补救它可以。它可以做的是,他可以随时改变主意并转到app -> settings 并在那里授予权限。 (或者至少我会这样做)
  • 未经许可在我的应用程序中无法打开,所以第一次进入时,出现对​​话框。如果用户错误地检查了“不再询问”。然后他下次进入,对话框不显示。 PERMISSION_GRANTED 获得 -1。有什么办法可以改变那个标志吗?
  • 您接受了与scoped directory access 无关的答案。您确定您的问题与 Android 7.0 的作用域目录访问 API 有关吗?
  • 我没有被问到如何访问目录。我询问了如何显示权限对话框,即使单击“不再询问”复选框也是如此。

标签: android android-permissions


【解决方案1】:

我认为您需要做的是使用方法 shouldShowRequestPermissionRationale(String) 如果用户拒绝了权限并选中“不再询问”,它将返回 false。

您应该做的是向用户显示为什么您需要权限或实施回退,例如禁用某些功能。

希望对您有所帮助。

【讨论】:

    【解决方案2】:

    我们应该使用 shouldShowRequestPermissionRationale。请通过这个:

    private void insertDummyContactWrapper() {
            int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
            if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
                    if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
                        showMessageOKCancel("You need to allow access to Contacts",
                                new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                                                REQUEST_CODE_ASK_PERMISSIONS);
                                    }
                                });
                        return;
                    }
                requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                        REQUEST_CODE_ASK_PERMISSIONS);
                return;
            }
            insertDummyContact();
        }
    

    【讨论】:

    • 谢谢。这 shouldShowRequestPermissionRationale 仅用于检查是否设置了标志。所以我曾经使用这个“手动需要从设置中授予权限”来显示警报
    【解决方案3】:

    有什么方法可以改变那个标志吗?

    开发人员无法更改该标志。否则,复选框将毫无意义,因为开发人员只会通过更改标志来忽略它。

    但是,您的问题指出了范围目录访问中的一个相当大的缺陷:用户 更改该标志的能力有限。设置中似乎没有专门更改此状态的位置,即用户可以手动授予被拒绝的运行时权限的方式。

    在运行 7.1 预览版的 Nexus 5X 上,“清除数据”会重置此标志,尽管这会产生更广泛的影响。在运行 7.1 的 Google Pixel 和运行 Android 7.0 的 Nexus 5X 上,nothing 将重置此标志,甚至完全卸载应用程序。

    我已经为此提交了a bug report。我怀疑这种情况是否会在短期内得到很大改善——充其量,他们可能会修复它,以便“清除数据”可靠地工作。

    【讨论】:

    • 嘿,差不多一年后——Google 是否采取了措施来解决这个问题?
    • @RuchirBaronia:不,因为我能够在 O Developer Previews 上重新创建问题。我提交了a fresh issue,它刚刚被忽略了。
    • 这在装有 Android 8.1 的 Nexus 5X 中仍然是一个问题(例如)。卸载,清除数据,重启手机,都没有用。解决方案是手动授予权限,运行应用程序,然后手动禁用权限。然后对话框再次显示,仍然......在 2019 年。:)
    【解决方案4】:
    public class AccessDenied implements View.OnClickListener{
    
        public Dialog dialog;
        private LinearLayout contentLayout;
        private Activity context;
        private EditText password;
        private String passwordStr;
        private Runnable doOnAccessPermitted;
        private int wrongColor = Color.RED, defColor = Color.parseColor("#80000000");
    
    
        public AccessDenied(Activity con, String pwd) {
            passwordStr = pwd;
            context = con;
            dialog = new Dialog(context, R.style.AnimatedDialog);
            setCancelable(false);
            //init the dialog with content view/animations etc.
            dialog.setContentView(R.layout.access_denied_layout);
            contentLayout = dialog.findViewById(R.id.layoutIconDialogLinearLayout);
            password = dialog.findViewById(R.id.accessdeniedlayoutpassword);
            Button ok = dialog.findViewById(R.id.accessdeniedlayoutok);
            ok.setOnClickListener(this);
            //now the dialog is ready
        }
    
        public void setActionOnAccess(Runnable doOnAccess) {
            doOnAccessPermitted = doOnAccess;
        }
    
        public void setCancelable(boolean set) {
            dialog.setCancelable(set);
        }
    
        public void show() {
            dialog.show();
        }
    
        public void cancel() {
            dialog.cancel();
        }
    
        public void setPassword(String pwrd) {
            passwordStr = pwrd;
        }
    
        public void tryPassword(String tryp) {
            if(passwordStr.equals(tryp)){
                cancel();
                if(doOnAccessPermitted != null)
                    doOnAccessPermitted.run();
            }
        }
    
        @Override
        public void onClick(View view) {
            if(passwordStr.equals(password.getText().toString())) {
                cancel();
                if(doOnAccessPermitted != null)
                    doOnAccessPermitted.run();
            }else{
                password.getText().clear();
                Animation anim = AnimationUtils.loadAnimation(context, R.anim.edittext_shake);
                anim.setDuration(200);
                anim.setRepeatCount(5);
                decView().startAnimation(anim);
                decView().setBackgroundColor(wrongColor);
                new android.os.Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        decView().setBackgroundColor(defColor);
                    }
                }, 1000);
            }
        }
    
        private View decView() {
            return password;
        }
    }
    

    【讨论】:

      【解决方案5】:

      打开应用的权限设置。

      如果用户已勾选“不再询问”,您将无法显示另一个权限对话框。

      但是,您可以帮助用户并打开应用程序的设置,用户可以在其中手动启用所需的权限。

      为此,您需要启动一个意图,类似于:

      public void openAppSettings() {
      
          Uri packageUri = Uri.fromParts( "package", getApplicationContext().getPackageName(), null );
      
          Intent applicationDetailsSettingsIntent = new Intent();
      
          applicationDetailsSettingsIntent.setAction( Settings.ACTION_APPLICATION_DETAILS_SETTINGS );
          applicationDetailsSettingsIntent.setData( packageUri );
          applicationDetailsSettingsIntent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
      
          getApplicationContext().startActivity( applicationDetailsSettingsIntent );
      
      }
      

      现在,为了知道用户何时选中“不再询问”复选框是另一回事,可以使用this StackOverflow answer 完成。

      【讨论】:

      • 是的,很遗憾,“应用信息”用户界面中没有这样的选项。
      【解决方案6】:

      我创建了一个方法来通过使用连接的 if...else if...else 来捕获所有用户操作,它对我来说效果很好。
      首先,确定是否 两个权限都被拒绝并且不再询问也被“勾选”,我结合了权限状态检查和 shouldShowRequestPermissionRationale(Manifest.permission.SEND_SMS)。
      然后确定是否只有权限被拒绝没有“勾选”不再询问,我使用了权限状态检查。在sn-p下面:

      @RequiresApi(api = Build.VERSION_CODES.M) //this is added for API lower than 23
      
      public void myPermissionRationale(){
              //This checks both permission status and the Don't ask again check box
              if (ContextCompat.checkSelfPermission(this,Manifest.permission.SEND_SMS )
                      == PackageManager.PERMISSION_DENIED && !shouldShowRequestPermissionRationale(Manifest.permission.SEND_SMS)) {
                  //open app permission settings here for instance 
      
              }
                 //only checks permission status then shows permission request pop up again
                 else if (ContextCompat.checkSelfPermission(this,Manifest.permission.SEND_SMS )
                          == PackageManager.PERMISSION_DENIED){
                                  // Request the permission
                                  ActivityCompat.requestPermissions(this,
                                          new String[]{Manifest.permission.SEND_SMS},
                                          10);
      
                              }
              }
      

      【讨论】:

        【解决方案7】:

        我为此找到了一个干净且有效的解决方案(但这里没有代码示例, - 阅读并理解它的原因)确保在采取通常要求许可的操作时没有任何场景,不做任何事情。

        标志 shouldShowPermission() - 单独,应用程序第一次请求给定权限和“不再显示被点击”之后没有区别,在这两种情况下都会返回 false。每次都将保持返回 true,直到设置了权限 do Dont Ask Again。这意味着我们第二次开始请求无限的权限,或者直到用户点击不再询问。

        因此,为了区分第一次请求权限和请求权限的时间,在用户已经设置 Dont Ask Again 之后,您可以使用自定义标志。

        这是一个干净而简单的解决方法,它将确定是否设置了不再询问选项。 (在 2 个制作应用程序中测试和工作)

        解决办法:

        添加一个名为“rationaleDisplayed”的标志(或任何你想要的,这将指示向用户显示permissionRationeDialog) - 默认值为false,将其存储在prefs中。在向用户至少展示一次基本原理对话框后,将此标志设置为 true。

        现在你有两个参数,当 shouldShowRationaleDialog = false 和rationalePermissionDisplayed = true 时它们的组合,实际上是设置了“不再显示”的指示。

        为什么会这样? 它之所以有效,是因为 shouldShowRationale, 在第一次请求许可时将返回 false,并且rationalDisplayedFlag 都是 false,因此弹出窗口将正确显示。 (2 个错误)- 这是第一次请求许可的情况。

        然后如果您第一次拒绝,sshouldShowRationale 将为真,rationalDisplayed 将为真-(2 个真),直到使用 dont set again 选项之前都是这种情况。 - 这是在第一次被拒绝后,第二次请求许可的情况。

        最后,如果您设置 Dont Ask Again - 或在 Android api 30 上并拒绝权限 2 次,则标志 shouldShowRationale 将在下次调用时返回 false。

        您有一个 shouldShowRationale = false 的案例,并且您自己的 flagrationeDisplayed = true,它告诉您“不再询问”已设置。 (否则, shouldShowRationale 仍然是错误的)。 - 这是用户两次拒绝权限(api 30)或在拒绝时设置 Dont Show Again 选项的情况。

        有了这个逻辑案例,您现在可以添加一个自定义权限对话框,其中包含有关如何手动启用权限以及使用确定按钮打开应用设置的说明。 (意图在对话正向侦听器中打开设置)。

        标志rationaleDisplayed 基本上是为了确保应用程序第一次请求权限时它会正确显示,但它的值允许确定用户设置为不再询问时的状态。

        像魅力一样工作。

        【讨论】:

          猜你喜欢
          • 2017-02-12
          • 2016-02-10
          • 1970-01-01
          • 1970-01-01
          • 2016-06-30
          • 1970-01-01
          • 2015-10-30
          • 1970-01-01
          • 2012-07-15
          相关资源
          最近更新 更多