无法拦截用户拒绝 Marshmallow 中的权限
Cannot intercept user denying permission in Marshmallow
我当前的应用程序有一个 FeedbackFragment
,它使用支持库中的 Fragment
并提供一个复选框以允许用户有选择地发送系统日志及其反馈。因为将日志附加到外发电子邮件需要访问外部存储(WRITE_EXTERNAL_STORAGE
权限),所以我必须在请求 FeedbackFragment
时请求权限。如果用户拒绝写入外部存储的权限,我想 disable/hide 'Include system logs' 复选框,但我希望此屏幕的其余功能正常工作(在 Marshmallow 之前的设备上工作正常,顺便提一句)。我已经根据Android官方的文档,结合很多SO文章,写出了合适的方法,这就是我目前所拥有的。请注意,我不会在这段代码的 'deny' 分支中的任何断点处停止。
下面的所有逻辑都是在 onCreateView()
对 checkExternalStoragePermissions()
的调用中创建的
我错过了什么?
private void checkExternalStoragePermissions() {
if (ContextCompat.checkSelfPermission(getContext(), WRITE_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {
canSendAttachments = true;
systemLogsCheckbox.setEnabled(true);
} else {
requestExternalStoragePermission();
}
}
private void requestExternalStoragePermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), WRITE_EXTERNAL_STORAGE)) {
new SnackBar.Builder(getActivity())
.withMessage(getString(R.string.write_external_storage_permission_rationale))
.withDuration(SnackBar.PERMANENT_SNACK)
.withActionMessage("OK")
.withOnClickListener(new SnackBar.OnMessageClickListener() {
@Override
public void onMessageClick(Parcelable token) {
ActivityCompat.requestPermissions(getActivity(),
new String[]{WRITE_EXTERNAL_STORAGE},
WRITE_TO_EXTERNAL_STORAGE_PERMISSION);
}
})
.withTextColorId(R.color.almanac_red_tab_highlight)
.show();
} else {
ActivityCompat.requestPermissions(getActivity(),
new String[]{WRITE_EXTERNAL_STORAGE}, WRITE_TO_EXTERNAL_STORAGE_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
if (requestCode == WRITE_TO_EXTERNAL_STORAGE_PERMISSION) {
if ((grantResults.length == 1) && (grantResults[0] == PERMISSION_GRANTED)) {
canSendAttachments = true;
systemLogsCheckbox.setEnabled(true);
} else {
canSendAttachments = false;
systemLogsCheckbox.setEnabled(false);
systemLogsCheckbox.setChecked(false);
}
} else
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
如果您从 Fragment
调用,您应该调用 FragmentCompat.requestPermissions
以便回调路由您的片段而不是您的 activity。
您可能需要将此添加到您的 gradle 文件中,因为 FragmentCompat
在 support-v13 库中。
compile 'com.android.support:support-v13:23.1.1'
首先你需要在你的 Activity
中实现 OnRequestPermissionsResultCallback
Listener
of ActivityCompat
class 并覆盖 void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
方法来检查用户是否允许或拒绝权限
你可以这样做:
int REQUEST_STORAGE = 1;
private void checkExternalStoragePermissions() {
if (hasStoragePermissionGranted()) {
canSendAttachments = true;
systemLogsCheckbox.setEnabled(true);
} else {
requestExternalStoragePermission();
}
}
public boolean hasStoragePermissionGranted(){
return ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
public void requestExternalStoragePermission() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
ActivityCompat.requestPermissions(MainActivity.this, {Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_STORAGE);
}
}
这里是 onRequestPermissionsResult()
当用户允许或拒绝运行时权限对话框中的权限时将调用的方法。
您还可以处理用户选中从不显示运行时权限对话框的情况。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_STORAGE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Storage permission is enabled
canSendAttachments = true;
systemLogsCheckbox.setEnabled(true);
} else if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivtity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
//User has deny from permission dialog
Snackbar.make(mainLayout, getResources().getString("Please enable storage permission"),
Snackbar.LENGTH_INDEFINITE)
.setAction("OK", new View.OnClickListener() {
@Override
public void onClick(View view) {
ActivityCompat.requestPermissions(MainActivity.this, {Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_STORAGE);
}
})
.show();
} else {
// User has deny permission and checked never show permission dialog so you can redirect to Application settings page
Snackbar.make(mainLayout, getResources().getString("Please enable permission from settings"),
Snackbar.LENGTH_INDEFINITE)
.setAction("OK", new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", MainActivity.this.getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
})
.show();
}
}
}
希望对你有帮助。
虽然 @iagreen 的答案很接近,但我最初遇到的问题是因为我使用的是适当的 ActivityCompat
版本我的代码中的方法。一旦我从方法调用中删除了该前缀并使用了 Fragment
class 中的相应方法,现在一切都按我预期的那样工作并且原始问题已经解决。
话虽如此,我也在研究如何使用 ContentProvider
来完全否定对 WRITE_EXTERNAL_STORAGE
权限的需求,正如 @Chris Stratton 所建议的那样.
我当前的应用程序有一个 FeedbackFragment
,它使用支持库中的 Fragment
并提供一个复选框以允许用户有选择地发送系统日志及其反馈。因为将日志附加到外发电子邮件需要访问外部存储(WRITE_EXTERNAL_STORAGE
权限),所以我必须在请求 FeedbackFragment
时请求权限。如果用户拒绝写入外部存储的权限,我想 disable/hide 'Include system logs' 复选框,但我希望此屏幕的其余功能正常工作(在 Marshmallow 之前的设备上工作正常,顺便提一句)。我已经根据Android官方的文档,结合很多SO文章,写出了合适的方法,这就是我目前所拥有的。请注意,我不会在这段代码的 'deny' 分支中的任何断点处停止。
下面的所有逻辑都是在 onCreateView()
checkExternalStoragePermissions()
的调用中创建的
我错过了什么?
private void checkExternalStoragePermissions() {
if (ContextCompat.checkSelfPermission(getContext(), WRITE_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {
canSendAttachments = true;
systemLogsCheckbox.setEnabled(true);
} else {
requestExternalStoragePermission();
}
}
private void requestExternalStoragePermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), WRITE_EXTERNAL_STORAGE)) {
new SnackBar.Builder(getActivity())
.withMessage(getString(R.string.write_external_storage_permission_rationale))
.withDuration(SnackBar.PERMANENT_SNACK)
.withActionMessage("OK")
.withOnClickListener(new SnackBar.OnMessageClickListener() {
@Override
public void onMessageClick(Parcelable token) {
ActivityCompat.requestPermissions(getActivity(),
new String[]{WRITE_EXTERNAL_STORAGE},
WRITE_TO_EXTERNAL_STORAGE_PERMISSION);
}
})
.withTextColorId(R.color.almanac_red_tab_highlight)
.show();
} else {
ActivityCompat.requestPermissions(getActivity(),
new String[]{WRITE_EXTERNAL_STORAGE}, WRITE_TO_EXTERNAL_STORAGE_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
@NonNull int[] grantResults) {
if (requestCode == WRITE_TO_EXTERNAL_STORAGE_PERMISSION) {
if ((grantResults.length == 1) && (grantResults[0] == PERMISSION_GRANTED)) {
canSendAttachments = true;
systemLogsCheckbox.setEnabled(true);
} else {
canSendAttachments = false;
systemLogsCheckbox.setEnabled(false);
systemLogsCheckbox.setChecked(false);
}
} else
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
如果您从 Fragment
调用,您应该调用 FragmentCompat.requestPermissions
以便回调路由您的片段而不是您的 activity。
您可能需要将此添加到您的 gradle 文件中,因为 FragmentCompat
在 support-v13 库中。
compile 'com.android.support:support-v13:23.1.1'
首先你需要在你的 Activity
中实现 OnRequestPermissionsResultCallback
Listener
of ActivityCompat
class 并覆盖 void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
方法来检查用户是否允许或拒绝权限
你可以这样做:
int REQUEST_STORAGE = 1;
private void checkExternalStoragePermissions() {
if (hasStoragePermissionGranted()) {
canSendAttachments = true;
systemLogsCheckbox.setEnabled(true);
} else {
requestExternalStoragePermission();
}
}
public boolean hasStoragePermissionGranted(){
return ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
public void requestExternalStoragePermission() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
ActivityCompat.requestPermissions(MainActivity.this, {Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_STORAGE);
}
}
这里是 onRequestPermissionsResult()
当用户允许或拒绝运行时权限对话框中的权限时将调用的方法。
您还可以处理用户选中从不显示运行时权限对话框的情况。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_STORAGE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Storage permission is enabled
canSendAttachments = true;
systemLogsCheckbox.setEnabled(true);
} else if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivtity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
//User has deny from permission dialog
Snackbar.make(mainLayout, getResources().getString("Please enable storage permission"),
Snackbar.LENGTH_INDEFINITE)
.setAction("OK", new View.OnClickListener() {
@Override
public void onClick(View view) {
ActivityCompat.requestPermissions(MainActivity.this, {Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_STORAGE);
}
})
.show();
} else {
// User has deny permission and checked never show permission dialog so you can redirect to Application settings page
Snackbar.make(mainLayout, getResources().getString("Please enable permission from settings"),
Snackbar.LENGTH_INDEFINITE)
.setAction("OK", new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", MainActivity.this.getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
})
.show();
}
}
}
希望对你有帮助。
虽然 @iagreen 的答案很接近,但我最初遇到的问题是因为我使用的是适当的 ActivityCompat
版本我的代码中的方法。一旦我从方法调用中删除了该前缀并使用了 Fragment
class 中的相应方法,现在一切都按我预期的那样工作并且原始问题已经解决。
话虽如此,我也在研究如何使用 ContentProvider
来完全否定对 WRITE_EXTERNAL_STORAGE
权限的需求,正如 @Chris Stratton 所建议的那样.