AndroidManifest.xml 已聲明 READ_CONTACTS、WRITE_CONTACTS,但在 Android 6.0 (API 23) 以上設備運行時仍拋出 SecurityException: Permission Denial。
Android 6.0 引入 運行時權限模型:危險權限(通訊錄、定位、存儲等)除在 Manifest 聲明外,必須在運行時向用戶彈窗請求授權,用戶同意後方可使用。
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)。ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_CODE)。onRequestPermissionsResult,根據 grantResults 判斷用戶是否授權。private static final int REQ_CONTACTS = 100;
private void loadContacts() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// 需請求
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_CONTACTS)) {
// 解釋對話框
new AlertDialog.Builder(this)
.setMessage("需要讀取通訊錄才能顯示聯系人")
.setPositiveButton("確定", (d, w) -> request())
.show();
} else {
request();
}
} else {
doQueryContacts(); // 已授權直接查詢
}
}
private void request() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS}, REQ_CONTACTS);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQ_CONTACTS) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
doQueryContacts();
} else {
Toast.makeText(this, "權限被拒絕,無法讀取通訊錄", Toast.LENGTH_SHORT).show();
}
}
}
EasyPermissions、PermissionX、Accompanist Permissions)。Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)。Manifest 聲明只是「申請資格」,運行時請求才是「拿到通行證」。Android 6.0+ 所有危險權限均需雙重保障,否則必崩。