Keywords: Android Permissions | Runtime Permissions | ActivityCompat.requestPermissions
Abstract: This article provides a comprehensive analysis of why ActivityCompat.requestPermissions may fail to display permission request dialogs in Android applications. It covers permission checking logic, callback handling mechanisms, and manifest merging issues, offering complete code examples and debugging methods. Based on actual Q&A data and best practices, the article systematically explains the complete permission request workflow and potential pitfalls.
Core Principles of Permission Request Mechanism
Starting from Android 6.0 (API level 23), the permission model underwent significant changes with the introduction of runtime permission requests. Developers must request dangerous permissions at runtime, not just declare them statically. While ActivityCompat.requestPermissions provides backward compatibility, developers often encounter issues where the dialog fails to appear.
Correct Implementation of Permission Checking and Request
First, ensure the required permission is declared in AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />In your Activity, implement the permission request logic following these steps:
- Check current permission status
- Decide whether to request permission based on the check result
- Handle the permission request result
Here's a complete implementation example:
private final int REQUEST_PERMISSION_PHONE_STATE = 1;
private void requestPhoneStatePermission() {
int permissionCheck = ContextCompat.checkSelfPermission(
this, Manifest.permission.READ_PHONE_STATE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_PHONE_STATE)) {
showRationaleDialog("Permission Required", "This app needs phone state permission for full functionality",
Manifest.permission.READ_PHONE_STATE, REQUEST_PERMISSION_PHONE_STATE);
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_PHONE_STATE},
REQUEST_PERMISSION_PHONE_STATE);
}
} else {
// Permission already granted, perform related operations
performPhoneStateOperation();
}
}
private void showRationaleDialog(String title, String message,
final String permission, final int requestCode) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{permission}, requestCode);
}
})
.setNegativeButton(android.R.string.cancel, null);
builder.create().show();
}Handling Permission Request Results
You must override the onRequestPermissionsResult method to handle user choices:
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION_PHONE_STATE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
performPhoneStateOperation();
} else {
// Permission denied
if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_PHONE_STATE)) {
// User selected "Don't ask again"
showSettingsDialog();
}
}
}
}
private void showSettingsDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Permission Required")
.setMessage("You have permanently denied this permission. Please enable it manually in app settings.")
.setPositiveButton("Go to Settings", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
})
.setNegativeButton("Cancel", null)
.create()
.show();
}Common Issues Diagnosis and Solutions
When the permission request dialog doesn't appear, possible causes include:
1. Manifest Merging Issues
Some third-party libraries may introduce permission restrictions through manifest merging. Check the final APK's permission declarations using:
aapt d permissions your-app.apkIf unexpected maxSdkVersion attributes are found, override them in your Manifest using the tools namespace:
<uses-permission android:name="android.permission.READ_PHONE_STATE"
tools:remove="android:maxSdkVersion" />Or completely replace third-party library permission declarations:
<uses-permission android:name="android.permission.READ_PHONE_STATE"
tools:node="replace" />2. Incorrect Permission Status Checking Logic
Ensure you use the correct constants for comparison:
// Correct approach
if (permissionCheck == PackageManager.PERMISSION_DENIED) {
// Request permission
}
// Or
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
// Request permission
}3. Target SDK Version Configuration
Ensure proper target SDK version configuration in build.gradle:
android {
compileSdkVersion 23
defaultConfig {
minSdkVersion 23
targetSdkVersion 23
}
}Best Practices Recommendations
1. Always check current permission status before requesting to avoid unnecessary requests.
2. Use shouldShowRequestPermissionRationale to determine if you need to explain the permission's purpose to users.
3. Properly handle permanently denied permissions by guiding users to app settings.
4. Recheck permission status in onResume since users may change permissions while the app is running.
5. Use the compatibility library ActivityCompat to ensure compatibility across older Android versions.
By following these principles and implementation details, developers can ensure the permission request mechanism works correctly across various Android versions and devices, providing a smooth user experience.