根据这个:http://developer.android.com/preview/features/runtime-permissions.html#coding一个应用程序可以检查运行时权限和请求权限,如果它还没有被授予。弹出如下对话框:
如果用户拒绝一个重要的权限,在我看来,应用程序应该显示一个解释为什么需要权限和什么影响拒绝。该对话框有两个选项:
重试(再次请求许可)
拒绝(应用程序将工作没有该许可)。
但是,如果用户选中“Never ask again”,则不应该显示带有解释的第二个对话框,特别是如果用户之前已经拒绝了一次。
现在的问题是:我的应用程序如何知道用户是否选中了Never ask again?IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)没有给我这个信息。
第二个问题是:谷歌是否计划在权限对话框中包含一个自定义消息,以解释为什么应用程序需要权限?这样就不会出现第二个对话框,这肯定会带来更好的用户体验。
我必须实现相机的动态权限。有三种可能的情况:允许2。否认,3。别再问了。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
for (String permission : permissions) {
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permission)) {
//denied
Log.e("denied", permission);
} else {
if (ActivityCompat.checkSelfPermission(getActivity(), permission) == PackageManager.PERMISSION_GRANTED) {
//allowed
Log.e("allowed", permission);
} else {
//set to never ask again
Log.e("set to never ask again", permission);
//do something here.
}
}
}
if (requestCode != MaterialBarcodeScanner.RC_HANDLE_CAMERA_PERM) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
return;
}
if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mScannerView.setResultHandler(this);
mScannerView.startCamera(mCameraId);
mScannerView.setFlash(mFlash);
mScannerView.setAutoFocus(mAutoFocus);
return;
} else {
//set to never ask again
Log.e("set to never ask again", permissions[0]);
}
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Error")
.setMessage(R.string.no_camera_permission)
.setPositiveButton(android.R.string.ok, listener)
.show();
}
private void insertDummyContactWrapper() {
int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CAMERA);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA},
REQUEST_CODE_ASK_PERMISSIONS);
return;
}
mScannerView.setResultHandler(this);
mScannerView.startCamera(mCameraId);
mScannerView.setFlash(mFlash);
mScannerView.setAutoFocus(mAutoFocus);
}
private int checkSelfPermission(String camera) {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
return REQUEST_CODE_ASK_PERMISSIONS;
} else {
return REQUEST_NOT_CODE_ASK_PERMISSIONS;
}
}
这里有一个很好的和简单的方法来检查当前的权限状态:
@Retention(RetentionPolicy.SOURCE)
@IntDef({GRANTED, DENIED, BLOCKED_OR_NEVER_ASKED })
public @interface PermissionStatus {}
public static final int GRANTED = 0;
public static final int DENIED = 1;
public static final int BLOCKED_OR_NEVER_ASKED = 2;
@PermissionStatus
public static int getPermissionStatus(Activity activity, String androidPermissionName) {
if(ContextCompat.checkSelfPermission(activity, androidPermissionName) != PackageManager.PERMISSION_GRANTED) {
if(!ActivityCompat.shouldShowRequestPermissionRationale(activity, androidPermissionName)){
return BLOCKED_OR_NEVER_ASKED;
}
return DENIED;
}
return GRANTED;
}
警告:在用户通过用户提示接受/拒绝权限之前,在第一个应用程序启动时返回BLOCKED_OR_NEVER_ASKED(在sdk 23+设备上)
更新:
Android支持库现在似乎也有一个非常类似的类Android .support.v4.content。PermissionChecker,包含checkSelfPermission(),返回:
public static final int PERMISSION_GRANTED = 0;
public static final int PERMISSION_DENIED = -1;
public static final int PERMISSION_DENIED_APP_OP = -2;
我有点晚了,我也遇到过类似的问题。解决此问题如下
假设您需要位置权限
请求权限启动器
private final ActivityResultLauncher<String> requestPermissionLauncher =
registerForActivityResult(
new RequestPermission(),
isGranted -> {
if (isGranted) {
// Permission is granted go ahead
} else {
shouldShowRequestPermissionRationale();
}
});
权限检查
private boolean hasPermissions() {
if (checkSelfPermission(requireActivity(), ACCESS_FINE_LOCATION) == PERMISSION_GRANTED) {
// Permission is granted go ahead
} else {
requestPermissionLauncher.launch(ACCESS_FINE_LOCATION);
}
}
检查是否需要显示权限理性/自定义对话来教育用户
private void shouldShowRequestPermissionRationale() {
if (!shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
// need to show permission rational custom dialog.
}
}
一旦用户标记了“不要再问”,该问题就不能再次显示。
但是可以向用户解释,他之前拒绝了权限,必须在设置中授予权限。并参考他的设置,使用以下代码:
@Override
public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// now, you have permission go ahead
// TODO: something
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.READ_CALL_LOG)) {
// now, user has denied permission (but not permanently!)
} else {
// now, user has denied permission permanently!
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), "You have previously declined this permission.\n" +
"You must approve this permission in \"Permissions\" in the app settings on your device.", Snackbar.LENGTH_LONG).setAction("Settings", new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + BuildConfig.APPLICATION_ID)));
}
});
View snackbarView = snackbar.getView();
TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text);
textView.setMaxLines(5); //Or as much as you need
snackbar.show();
}
}
return;
}
我在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