首先我要感謝這么長(zhǎng)時(shí)間以來(lái),一直堅(jiān)持看我文章的同學(xué),是你們的支持點(diǎn)贊讓我有了繼續(xù)寫作的力量。感謝你們,本文還有一個(gè)小名,Android運(yùn)行權(quán)限機(jī)制從啥也不是,到誰(shuí)也不慣著,請(qǐng)?jiān)徫沂侨绱说亩罕取?/p>
先來(lái)介紹一下,Android6.0引入了動(dòng)態(tài)權(quán)限,目前權(quán)限分兩種,一種不涉及用戶隱私的敏感權(quán)限,還是直接在清單文件AndroidManifest.xml中定義,還有一種類似通訊錄,相冊(cè)這些觸碰到用戶隱私的權(quán)限需要?jiǎng)討B(tài)實(shí)時(shí)的去申請(qǐng),具體的需要申請(qǐng)動(dòng)態(tài)權(quán)限的如下表格。
| 權(quán)限 | 權(quán)限組 | 名稱 |
|---|---|---|
| CALENDAR | READ_CALENDAR WRITE_CALENDAR |
日歷 |
| CAMERA | CAMERA | 相機(jī) |
| CONTACTS | READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS |
聯(lián)系人 |
| LOCATION | ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION |
位置 |
| MICROPHONE | RECORD_AUDIO | 話筒 |
| PHONE | READ_PHONE_STATE CALL_PHONE READ_CALL_LOG WRITE_CALL_LOG ADD_VOICEMAIL USE_SIP PROCESS_OUTGOING_CALLS |
電話 |
| SMS | SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS |
短信 |
| STORAGE | READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE |
存儲(chǔ) |
這里需要注意的是這些敏感權(quán)限一共分9組,如果需要使用某一組內(nèi)的權(quán)限,申請(qǐng)一次當(dāng)前組內(nèi)其他權(quán)限則不需要重復(fù)申請(qǐng)。
接下來(lái)梳理一下,申請(qǐng)動(dòng)態(tài)權(quán)限的流程,以打電話為例,場(chǎng)景是我寫了一個(gè)按鈕來(lái)?yè)艽螂娫挕?br> 1)在執(zhí)行敏感操作前,檢查是否已經(jīng)存在該權(quán)限,有則通過(guò),無(wú)則申請(qǐng)。
public void requestPermissionAndCall(){
//檢查權(quán)限是否存在
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CALL_PHONE},PERMISSION_REQUEST_CODE);
}else{
callPhone();
}
}
在申請(qǐng)權(quán)限的過(guò)程中,會(huì)彈窗讓用戶選擇,允許則直接撥打,拒絕則下次點(diǎn)擊時(shí)候繼續(xù)彈窗向用戶索取權(quán)限,不同的是拒絕后的彈窗會(huì)顯示不再詢問(wèn)。如下圖:

2)系統(tǒng)提供了權(quán)限對(duì)話框的點(diǎn)擊回調(diào),后續(xù)操作可以在回調(diào)中完成
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//首先在權(quán)限返回的回調(diào)中根據(jù)定義的PERMISSION_REQUEST_CODE確定是哪個(gè)權(quán)限
if (requestCode == PERMISSION_REQUEST_CODE){
//根據(jù)用戶點(diǎn)擊判斷,是否點(diǎn)擊授權(quán)或者拒絕,做不同的操作
if (grantResults[0] ==PackageManager.PERMISSION_GRANTED){
callPhone();
}else{
//拒絕
}
return;
}
}
這里還存在一個(gè)問(wèn)題,如果用戶點(diǎn)擊了不再詢問(wèn)。那么打電話這個(gè)需求就掛掉了。但是用戶可能無(wú)意按錯(cuò)或者其他情況,就不好了。所以這里的不再詢問(wèn)也是可以捕捉的,可以進(jìn)行彈窗或者跳轉(zhuǎn)設(shè)置界面。接下來(lái)簡(jiǎn)單的修改一下上面的例子:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//首先在權(quán)限返回的回調(diào)中根據(jù)定義的PERMISSION_REQUEST_CODE確定是哪個(gè)權(quán)限
if (requestCode == PERMISSION_REQUEST_CODE){
//根據(jù)用戶點(diǎn)擊判斷,是否點(diǎn)擊授權(quán)或者拒絕,做不同的操作
if (grantResults[0] ==PackageManager.PERMISSION_GRANTED){
callPhone();
}else{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("您已拒絕當(dāng)前功能所需要的權(quán)限,無(wú)法正常工作");
builder.create().show();
}
return;
}
}
效果如下:

閑言:
相機(jī)的動(dòng)態(tài)權(quán)限不用申請(qǐng)兼容android7.0版本可以轉(zhuǎn)戰(zhàn) https://blog.csdn.net/lmj623565791/article/details/72859156
本來(lái)是想用相機(jī)來(lái)演示權(quán)限,結(jié)果我用的android8.1的sdk,并不需要申請(qǐng)動(dòng)態(tài)權(quán)限,至于為什么上面文章說(shuō)的很清楚了,我又打算試試打電話,結(jié)果發(fā)現(xiàn)按照傳統(tǒng)的打電話的寫法:
public void callPhone(String phoneNum) {
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + phoneNum);
intent.setData(data);
startActivity(intent);
}
在sdk27下, startActivity(intent)編譯就不通過(guò),提示沒(méi)有添加動(dòng)態(tài)權(quán)限,快捷鍵直接生成了權(quán)限的代碼:
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + phoneNum);
intent.setData(data);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
startActivity(intent);
}