我正在翻阅关于Android m中的新权限模型的官方文档。它讨论了shouldShowRequestPermissionRationale()函数,如果应用程序之前请求了此权限,并且用户拒绝了请求,该函数将返回true。如果用户在过去拒绝了权限请求并选择Don't ask again选项,则此方法返回false。
但是我们如何区分以下两种情况呢?
案例1:应用程序没有权限,之前也没有向用户请求过权限。在这种情况下,shouldShowRequestPermissionRationale()将返回false,因为这是我们第一次请求用户。
情况2:用户拒绝了权限并选择了“不要再问了”,在这种情况下shouldShowRequestPermissionRationale()将返回false。
我想把用户发送到案例2中的应用设置页面。我怎么微分这两种情况呢?
这段代码要求用户在运行时请求权限,
如果用户允许,执行结果方法,
如果用户拒绝,它会用描述和用户拒绝再次询问(它会用说明再次询问),
但如果用户选择永远不会再问。
它处理永不再问,显示打开设置选项与说明。
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;
}
}
}
检查这个实现。对我来说还不错。基本上你在checkPermissions()方法中检查权限,传递一个权限列表。在onRequestPermissionsResult()上检查权限请求的结果。实现让你解决两种情况下,当用户选择“永不再问”或不。在这个实现中,如果se选择“never ask again”,对话框有一个选项将他带到应用程序设置活动。
所有这些代码都在我的片段中。我认为最好创建一个专门的类来做这件事,比如PermissionManager,但我不确定。
/**
* responsible for checking if permissions are granted. In case permissions are not granted, the user will be requested and the method returns false. In case we have all permissions, the method return true.
* The response of the request for the permissions is going to be handled in the onRequestPermissionsResult() method
* @param permissions list of permissions to be checked if are granted onRequestPermissionsResult().
* @param requestCode request code to identify this request in
* @return true case we already have all permissions. false in case we had to prompt the user for it.
*/
private boolean checkPermissions(List<String> permissions, int requestCode) {
List<String> permissionsNotGranted = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED)
permissionsNotGranted.add(permission);
}
//If there is any permission we don't have (it's going to be in permissionsNotGranted List) , we need to request.
if (!permissionsNotGranted.isEmpty()) {
requestPermissions(permissionsNotGranted.toArray(new String[permissionsNotGranted.size()]), requestCode);
return false;
}
return true;
}
/**
* called after permissions are requested to the user. This is called always, either
* has granted or not the permissions.
* @param requestCode int code used to identify the request made. Was passed as parameter in the
* requestPermissions() call.
* @param permissions Array containing the permissions asked to the user.
* @param grantResults Array containing the results of the permissions requested to the user.
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case YOUR_REQUEST_CODE: {
boolean anyPermissionDenied = false;
boolean neverAskAgainSelected = false;
// Check if any permission asked has been denied
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
anyPermissionDenied = true;
//check if user select "never ask again" when denying any permission
if (!shouldShowRequestPermissionRationale(permissions[i])) {
neverAskAgainSelected = true;
}
}
}
if (!anyPermissionDenied) {
// All Permissions asked were granted! Yey!
// DO YOUR STUFF
} else {
// the user has just denied one or all of the permissions
// use this message to explain why he needs to grant these permissions in order to proceed
String message = "";
DialogInterface.OnClickListener listener = null;
if (neverAskAgainSelected) {
//This message is displayed after the user has checked never ask again checkbox.
message = getString(R.string.permission_denied_never_ask_again_dialog_message);
listener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//this will be executed if User clicks OK button. This is gonna take the user to the App Settings
startAppSettingsConfigActivity();
}
};
} else {
//This message is displayed while the user hasn't checked never ask again checkbox.
message = getString(R.string.permission_denied_dialog_message);
}
new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme)
.setMessage(message)
.setPositiveButton(getString(R.string.label_Ok), listener)
.setNegativeButton(getString(R.string.label_cancel), null)
.create()
.show();
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
/**
* start the App Settings Activity so that the user can change
* settings related to the application such as permissions.
*/
private void startAppSettingsConfigActivity() {
final Intent i = new Intent();
i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:" + getActivity().getPackageName()));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
getActivity().startActivity(i);
}
这段代码要求用户在运行时请求权限,
如果用户允许,执行结果方法,
如果用户拒绝,它会用描述和用户拒绝再次询问(它会用说明再次询问),
但如果用户选择永远不会再问。
它处理永不再问,显示打开设置选项与说明。
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;
}
}
}
public void requestPermission(View view){
if(ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
if(ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)){
//The Alert Dialog before asking for the second time to help the user understand why he needs to give permission.
AlertDialog alert = new AlertDialog.Builder(this).setMessage("Without the permissions you cannot run the application")
.setCancelable(false)
.setPositiveButton("Okay, I understand", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
}
}).setNegativeButton("No, Exit the App", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
System.exit(2);
}
}).create();
alert.setTitle("ALERTY");
alert.show();
//End of the alert Dialog
}
else{
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
}
}
else {
textView.setText("Permission Is Already Granted");
}
}
/*
The shouldShowRequestPermissionRationale() function returns true if the app has requested this permission
previously and the user denied the request.If the user turned down the permission request in the past and chose
the Don't ask again option, this method returns false.
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if(requestCode == REQUEST_FINE_LOCATION) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
textView.setText("Hooray! on Request Permissions Granted");
}
else{
//Since the user has chosen the don't ask again option,
if(!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)){
//Alert Dialog that will take user to settings where he can manually give the permissions
AlertDialog alert = new AlertDialog.Builder(this).setMessage("You have permanently disabled the permission ")
.setPositiveButton("Go to Settings", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
openSettings();
}
}).setNegativeButton("Don't Go",null).setCancelable(false).create();
alert.setTitle("Give permission manually");
alert.show();
// End of the Alert Dialog
}
else{
textView.setText("Permission has been denied the 1st time");
}
}
}
}
这是openSettings方法。
public void openSettings(){
Intent intent = new Intent();
Uri uri = Uri.fromParts("package",this.getPackageName(),null);
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(uri);
startActivity(intent);
}
“M Preview 1”后,如果第一次弹出对话框,则没有“Never ask again”复选框。
如果用户拒绝权限请求,第二次请求权限时,权限对话框中会出现“Never ask again”复选框。
所以逻辑应该是这样的:
Request permission:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
} else {
//Do the stuff that requires permission...
}
Check if the permission was denied or granted in onRequestPermissionsResult.
If the permission was denied previously, this time there will be a Never ask again checkbox in the permission dialog.
Call shouldShowRequestPermissionRationale to see if the user checked Never ask again. shouldShowRequestPermissionRationale method returns false only if the user selected Never ask again or device policy prohibits the app from having that permission:
if (grantResults.length > 0){
if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Do the stuff that requires permission...
}else if (grantResults[0] == PackageManager.PERMISSION_DENIED){
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
//Show permission explanation dialog...
}else{
//Never ask again selected, or device policy prohibits the app from having that permission.
//So, disable that feature, or fall back to another situation...
}
}
}
因此,如果用户勾选了“永不再问”,您将不必跟踪。