我正在翻阅关于Android m中的新权限模型的官方文档。它讨论了shouldShowRequestPermissionRationale()函数,如果应用程序之前请求了此权限,并且用户拒绝了请求,该函数将返回true。如果用户在过去拒绝了权限请求并选择Don't ask again选项,则此方法返回false。

但是我们如何区分以下两种情况呢?

案例1:应用程序没有权限,之前也没有向用户请求过权限。在这种情况下,shouldShowRequestPermissionRationale()将返回false,因为这是我们第一次请求用户。

情况2:用户拒绝了权限并选择了“不要再问了”,在这种情况下shouldShowRequestPermissionRationale()将返回false。

我想把用户发送到案例2中的应用设置页面。我怎么微分这两种情况呢?


当前回答

更新

我相信下面CanC的答案是正确的,应该遵循。唯一确定的方法是在onRequestPermissionResult回调中使用shouldShowPermissionRationale来验证这一点。

==

我最初的回答是:

我发现的唯一方法是自己跟踪这是否是第一次(例如使用共享的偏好)。如果不是第一次,则使用shouldShowRequestPermissionRationale()进行区分。

另见:Android M -检查运行时权限-如何确定用户是否勾选了“永不再问”?

其他回答

可能对某人有用:——

我注意到的是,如果我们在onRequestPermissionsResult()回调方法中检查shouldshowrequestpermissionration理()标志,它只显示两种状态。

状态1:-返回true:——任何时候用户单击Deny permissions(包括第一次)。

状态2:-返回false:-如果用户选择“永不再问”。

链接到详细的工作示例。

正确使用shouldShowRequestPermissionRationale是on onRequestPermissionsResult。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
    <androidx.appcompat.widget.LinearLayoutCompat
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity"
        android:gravity="center">
    
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/btn_camera"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Camera"
            android:textAllCaps="false"
            android:background="@color/purple_200"
            android:layout_marginTop="20dp"
            >
        </androidx.appcompat.widget.AppCompatButton>
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/btn_storage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Storage"
            android:textAllCaps="false"
            android:background="@color/purple_200"
            android:layout_marginTop="30dp"
            >
        </androidx.appcompat.widget.AppCompatButton>
    
    </androidx.appcompat.widget.LinearLayoutCompat>
enter code here

MainActivity.kt

package com.example.myapplication
import android.Manifest
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
class MainActivity : AppCompatActivity() {
    private val TAG = "MainActivity"
    lateinit var btnCamera: Button
    private val cameraRequestCode = 100
    lateinit var btnStorage: Button
    private val storageRequestCode = 200
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btnCamera = findViewById(R.id.btn_camera)
        btnStorage = findViewById(R.id.btn_storage)
        btnCamera.setOnClickListener {
            checkPermission(android.Manifest.permission.CAMERA, cameraRequestCode)
        }
        btnStorage.setOnClickListener {
            checkPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, storageRequestCode)
        }
    }

    private fun checkPermission(permissionName: String, requestCode: Int) {
        /**
         * if the permission is given means it will give the  permissionNumber = 0
         * if the permission is not  given means it will give the  permissionNumber =-1
         * It s same as we are checking for PackageManager.PERMISSION_DENIED =-1 & PackageManager.GRANTED=0
         */
        val permissionNumber: Int =
            ContextCompat.checkSelfPermission(this@MainActivity, permissionName)
        if (permissionNumber == PackageManager.PERMISSION_GRANTED) {

        } else if (permissionNumber == PackageManager.PERMISSION_DENIED) {
            askpermission(permissionName, requestCode, permissionNumber)

        }

    }

    private fun askpermission(permissionName: String, permissionCode: Int, permissionNumner: Int) {
        ActivityCompat.requestPermissions(
            this@MainActivity,
            arrayOf(permissionName),
            permissionCode
        )
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == cameraRequestCode) {
            if (permissions.size > 0) {
                if (permissions[0].toString().equals(Manifest.permission.CAMERA, ignoreCase = true)) {
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        Toast.makeText(applicationContext,"Permission Granted",Toast.LENGTH_SHORT).show()

                    }else{
                        if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                           var permissionDeniedStatus= checkDeniedPermissionStatus(permissions[0]);
                            if(permissionDeniedStatus){
                                /**
                                 * Permission Denied
                                 */
                                Toast.makeText(applicationContext,"Permission Denied",Toast.LENGTH_SHORT).show()
                            }else{
                                /**
                                 * Permission Denied and Selected Don t ask again.
                                 */
                                showDialog("Permission Denied","Permission Denied Permanently\nOpen Setting to allow")
                            }
                        }
                    }
                }
            }
        }else  if (requestCode == storageRequestCode) {
            if(permissions[0].toString().equals(Manifest.permission.READ_EXTERNAL_STORAGE, ignoreCase = true)){
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        Toast.makeText(applicationContext,"Permission Granted",Toast.LENGTH_SHORT).show()
                    }
                }else{
                    if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                        var permissionDeniedStatus= checkDeniedPermissionStatus(permissions[0]);
                        if(permissionDeniedStatus){
                            /**
                             * Permission Denied
                             */
                            Toast.makeText(applicationContext,"Permission Denied",Toast.LENGTH_SHORT).show()
                        }else{
                            /**
                             * Permission Denied and Selected Don t ask again.
                             */
                            showDialog("Permission Denied","Permission Denied Permanently\nOpen Setting to allow")
                        }
                    }
                }
            }
        }
    }

    private fun checkDeniedPermissionStatus(permissionName: String) :Boolean{
        val permissionDeniedStatus: Boolean = ActivityCompat.shouldShowRequestPermissionRationale(this@MainActivity, permissionName)
        return permissionDeniedStatus
    }

    private fun showDialog(title: String, message: String) {
        val builder = AlertDialog.Builder(this)
        builder.setTitle(title)
        builder.setMessage(message)
        builder.setPositiveButton(android.R.string.yes) { dialog, which ->

        }

        builder.setNegativeButton(android.R.string.no) { dialog, which ->

        }
        builder.show()
    }
}

更新

我相信下面CanC的答案是正确的,应该遵循。唯一确定的方法是在onRequestPermissionResult回调中使用shouldShowPermissionRationale来验证这一点。

==

我最初的回答是:

我发现的唯一方法是自己跟踪这是否是第一次(例如使用共享的偏好)。如果不是第一次,则使用shouldShowRequestPermissionRationale()进行区分。

另见:Android M -检查运行时权限-如何确定用户是否勾选了“永不再问”?

这段代码要求用户在运行时请求权限, 如果用户允许,执行结果方法, 如果用户拒绝,它会用描述和用户拒绝再次询问(它会用说明再次询问), 但如果用户选择永远不会再问。 它处理永不再问,显示打开设置选项与说明。

public String storagePermissions = Manifest.permission.READ_EXTERNAL_STORAGE;   
private static final int REQUEST_ACCESS =101;  

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      if(checkSelfPermission(storagePermissions)== PackageManager.PERMISSION_GRANTED){
          result();    // result  is your block of code 
      }else {
          requestPermissions(new String[]{storagePermissions},REQUEST_ACCESS);
      }

    }
    else{
        result();    //so if user is lower than api verison M, no permission is requested
    } 

}

 private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
    new AlertDialog.Builder(MainActivity.this)
            .setMessage(message)
            .setTitle("Hi User..")
            .setPositiveButton("Ok", okListener)
            .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {        //idea calling showMessage funtion again
                    Snackbar mySnackbar = Snackbar.make( findViewById(R.id.coordinatorlayout),"You Press Cancel.. ", Snackbar.LENGTH_INDEFINITE);
                    mySnackbar.setAction("Exit", new cancelButton());
                    mySnackbar.show();

                }
            })
            .create()
            .show();
}


private void result(){
          //your code
}

    @RequiresApi(api = Build.VERSION_CODES.M)
public class NeverAskAgain implements View.OnClickListener{
    @Override
    public void onClick(View view)
    {
        goToSettings();
    }
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void goToSettings() {
    Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
    finish();
    myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
    myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivityForResult(myAppSettings, REQUEST_APP_SETTINGS);
}
public class cancelButton implements View.OnClickListener{
    @Override
    public void onClick(View view){
        Toast.makeText(MainActivity.this,"To use this app , you must grant storage permission",Toast.LENGTH_SHORT);
        finish();
    }
    }


 @Override
@RequiresApi(api = Build.VERSION_CODES.M)
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode,permissions,grantResults);

    switch(requestCode) {
        case REQUEST_ACCESS:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission is granted
                    result();
                    break;
                }
                else if (!shouldShowRequestPermissionRationale(permissions[0])){
                    showMessageOKCancel("You choose Never Ask Again,option",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Snackbar mySnackbar = Snackbar.make(findViewById(R.id.coordinatorlayout), "Permission=>Storage=>On", Snackbar.LENGTH_INDEFINITE);
                        mySnackbar.setAction("Settings", new NeverAskAgain());
                        mySnackbar.show();
                    }
                     });
                    break;
                }
                else {
                    showMessageOKCancel("You Denid permission Request..",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            requestPermissions(new String[]{storagePermissions}, REQUEST_ACCESS);
                        }
                    });
                    break;
                }
        }
}

如果有人喜欢,就发布另一种选择。你可以使用EasyPermissions,这是由谷歌本身提供的,如前所述,“简化Android M系统权限”。

然后你不必直接处理shouldShowRequestPermissionRationale。