我正在翻阅关于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;
}
}
}
这段代码要求用户在运行时请求权限,
如果用户允许,执行结果方法,
如果用户拒绝,它会用描述和用户拒绝再次询问(它会用说明再次询问),
但如果用户选择永远不会再问。
它处理永不再问,显示打开设置选项与说明。
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);
}
我理解它的方式,shouldShowRequestPermissionRationale()在底层运行许多用例,并通知应用程序是否显示正在请求的权限的解释。
运行时权限背后的思想是,大多数情况下,用户将对权限请求说Yes。这样用户就只需要点击一次。当然,这个请求应该在正确的上下文中使用——即在按下“摄像”按钮时请求摄像许可。
If the user denies the request, but after some time comes around and presses the "Camera" button again, shouldShowRequestPermissionRationale() will return true, so the app can show some meaningful explanation why the permission is requested, and why the app won't work properly without it. Normally you would show in that dialog window a button to deny again/decide later, and a button to grant the permissions. The grant permissions button in the rationale dialog, should start the permission request again. This time the user will also have a "Never show again" checkbox. Should he decide to select it, and deny the permission again, it would notify the Android system that the user and the app are not on the same page. That action would have two consequences - shouldShowRequestPermissionRationale() will always return false, and the requestPermissions() method will not show any dialog, but will directly return denied to the onRequestPermissionsResult callback.
但是还有另一种可能的场景,可以使用onRequestPermissionsResult。例如,一些设备可能有禁用摄像头的设备策略(为CIA、DARPA等工作)。在这些设备上,onRequestPermissionsResult将总是返回false,并且requestPermissions()方法将无声地拒绝请求。
这是我从Ben Poiesz (Android框架的产品经理)的播客中了解到的。
http://androidbackstage.blogspot.jp/2015/08/episode-33-permission-mission.html