根据这个:http://developer.android.com/preview/features/runtime-permissions.html#coding一个应用程序可以检查运行时权限和请求权限,如果它还没有被授予。弹出如下对话框:
如果用户拒绝一个重要的权限,在我看来,应用程序应该显示一个解释为什么需要权限和什么影响拒绝。该对话框有两个选项:
重试(再次请求许可)
拒绝(应用程序将工作没有该许可)。
但是,如果用户选中“Never ask again”,则不应该显示带有解释的第二个对话框,特别是如果用户之前已经拒绝了一次。
现在的问题是:我的应用程序如何知道用户是否选中了Never ask again?IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)没有给我这个信息。
第二个问题是:谷歌是否计划在权限对话框中包含一个自定义消息,以解释为什么应用程序需要权限?这样就不会出现第二个对话框,这肯定会带来更好的用户体验。
如果你想检测所有的“状态”(第一次被拒绝,刚刚被拒绝,刚刚被“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
我在Android m中写了一个权限请求的简写,这段代码还处理了对旧Android版本的向后兼容性。
所有丑陋的代码都被提取到一个片段中,该片段将自己附加到请求权限的活动上。PermissionRequestManager的使用方法如下:
new PermissionRequestManager()
// We need a AppCompatActivity here, if you are not using support libraries you will have to slightly change
// the PermissionReuqestManager class
.withActivity(this)
// List all permissions you need
.withPermissions(android.Manifest.permission.CALL_PHONE, android.Manifest.permission.READ_CALENDAR)
// This Runnable is called whenever the request was successfull
.withSuccessHandler(new Runnable() {
@Override
public void run() {
// Do something with your permissions!
// This is called after the user has granted all
// permissions, we are one a older platform where
// the user does not need to grant permissions
// manually, or all permissions are already granted
}
})
// Optional, called when the user did not grant all permissions
.withFailureHandler(new Runnable() {
@Override
public void run() {
// This is called if the user has rejected one or all of the requested permissions
L.e(this.getClass().getSimpleName(), "Unable to request permission");
}
})
// After calling this, the user is prompted to grant the rights
.request();
来看看:https://gist.github.com/crysxd/385b57d74045a8bd67c4110c34ab74aa
shouldShowRequestPermissionRationale根据之前权限请求中的用户首选项返回true或false。
如果用户只是拒绝权限(不是永远)shouldShowRequestPermissionRationale将返回true。如果永远拒绝许可,则返回false。窍门是即使用户允许了权限shouldShowRequestPermissionRationale也会返回false。
因此,我们可以结合这两个条件来得到永不再问的选择与否。
因此,如果用户不允许权限,并且shouldShowRequestPermissionRationale返回false,那么这意味着用户选择永远不会再次请求权限。
https://stackoverflow.com/a/58114769/5151336
你可以使用
shouldShowRequestPermissionRationale()
内部
onRequestPermissionsResult()
请看下面的例子:
当用户点击按钮时检查是否有权限:
@Override
public void onClick(View v) {
if (v.getId() == R.id.appCompatBtn_changeProfileCoverPhoto) {
if (Build.VERSION.SDK_INT < 23) { // API < 23 don't need to ask permission
navigateTo(MainActivity.class); // Navigate to activity to change photos
} else {
if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted yet. Ask for permission...
requestWriteExternalPermission();
} else {
// Permission is already granted, good to go :)
navigateTo(MainActivity.class);
}
}
}
}
当用户回答权限对话框时,我们将进入onRequestPermissionResult:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == WRITE_EXTERNAL_PERMISSION_REQUEST_CODE) {
// Case 1. Permission is granted.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
// Before navigating, I still check one more time the permission for good practice.
navigateTo(MainActivity.class);
}
} else { // Case 2. Permission was refused
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// Case 2.1. shouldShowRequest... returns true because the
// permission was denied before. If it is the first time the app is running we will
// end up in this part of the code. Because he need to deny at least once to get
// to onRequestPermissionsResult.
Snackbar snackbar = Snackbar.make(findViewById(R.id.relLayout_container), R.string.you_must_verify_permissions_to_send_media, Snackbar.LENGTH_LONG);
snackbar.setAction("VERIFY", new View.OnClickListener() {
@Override
public void onClick(View v) {
ActivityCompat.requestPermissions(SettingsActivity.this
, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}
, WRITE_EXTERNAL_PERMISSION_REQUEST_CODE);
}
});
snackbar.show();
} else {
// Case 2.2. Permission was already denied and the user checked "Never ask again".
// Navigate user to settings if he choose to allow this time.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.instructions_to_turn_on_storage_permission)
.setPositiveButton(getString(R.string.settings), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
settingsIntent.setData(uri);
startActivityForResult(settingsIntent, 7);
}
})
.setNegativeButton(getString(R.string.not_now), null);
Dialog dialog = builder.create();
dialog.show();
}
}
}
}
您可以通过检查权限原理是否显示在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).
}
}
}