Keywords: Android Permissions | Runtime Permissions | Multiple Permission Requests | Marshmallow | User Privacy
Abstract: This article provides an in-depth analysis of the runtime permission mechanism introduced in Android 6.0, focusing on the implementation of multiple permission requests. Through detailed code examples, it demonstrates how to check, request, and handle multiple dangerous permissions including contacts, SMS, camera, and storage. The article combines official best practices to deliver complete permission management strategies for building privacy-conscious applications.
Overview of Android 6.0 Permission Mechanism
Android 6.0 (Marshmallow) introduced the runtime permission model, requiring applications to dynamically request user authorization when accessing sensitive data or functionality. This change significantly enhances user control over privacy, necessitating corresponding adjustments in permission handling logic by developers.
Core Principles of Multiple Permission Requests
The Android system supports requesting multiple permissions simultaneously. When an application calls the ActivityCompat.requestPermissions() method with an array of permissions, the system automatically groups related permissions and presents them through paginated dialogs, guiding users through the authorization process. This design ensures both smooth user experience and transparency in permission requests.
Permission Checking and Request Implementation
Before requesting permissions, it's essential to verify whether they are already granted. The following helper method efficiently checks the status of multiple permissions:
public static boolean hasPermissions(Context context, String... permissions) {
if (context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}The Kotlin version offers a more concise implementation:
fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}Based on the check results, multiple permissions can be requested:
int PERMISSION_ALL = 1;
String[] PERMISSIONS = {
android.Manifest.permission.READ_CONTACTS,
android.Manifest.permission.WRITE_CONTACTS,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.READ_SMS,
android.Manifest.permission.CAMERA
};
if (!hasPermissions(this, PERMISSIONS)) {
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
}Handling Permission Request Results
After user response, the system calls back to the onRequestPermissionsResult() method. Developers must handle authorization results here:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_ALL) {
// Check if all permissions are granted
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
// All permissions granted, proceed with normal flow
proceedWithNormalFlow();
} else {
// Some or all permissions denied, implement graceful degradation
handlePermissionDenial();
}
}
}Best Practices for Permission Requests
According to Android official guidelines, permission requests should follow these principles:
- Contextual Requesting: Request permissions when users trigger functionality that requires them, not at app startup
- Provide Explanation: Use
shouldShowRequestPermissionRationale()to determine if users need explanation about permission usage - Graceful Degradation: Provide alternatives rather than completely blocking users when permissions are denied
- Respect Choices: Avoid repeatedly requesting permissions that have been explicitly denied
Advanced Permission Management Strategies
For complex scenarios, more refined permission management can be implemented:
private boolean checkAndRequestPermissions() {
List<String> listPermissionsNeeded = new ArrayList<>();
// Check status of individual permissions
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_CONTACTS);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.CAMERA);
}
// Add other permissions to check...
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this,
listPermissionsNeeded.toArray(new String[0]),
REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}Permission Grouping and User Experience
The Android system automatically organizes request interfaces based on permission groups. For example, contact-related permissions (READ_CONTACTS, WRITE_CONTACTS) are typically grouped together. However, developers should not rely on specific grouping behavior but focus on providing clear explanations of permission usage.
Compatibility Considerations
Using AndroidX compatibility libraries (such as ActivityCompat and ContextCompat) ensures code functions correctly on versions prior to Android 6.0. In older system versions, permissions are automatically granted during installation, eliminating the need for runtime requests.
Testing and Debugging Recommendations
During development, thoroughly test various permission scenarios:
- Test functionality after permission grants
- Test degradation handling when permissions are denied
- Test edge cases with "Never ask again" options
- Use ADB commands to reset permission states for repeated testing
By following the methods and best practices outlined in this article, developers can build permission management systems that both comply with Android platform requirements and deliver excellent user experiences.