寫在前面
對(duì)于android 6.0來(lái)說(shuō),增加了權(quán)限的管理甚淡,能夠更好的保護(hù)用戶的隱私,當(dāng)用戶需要某權(quán)限時(shí)捅厂,才動(dòng)態(tài)的去申請(qǐng)贯卦。用戶也可以在應(yīng)用權(quán)限管理里面關(guān)閉和打開(kāi)资柔。為了方便以后使用,這里對(duì)權(quán)限使用相關(guān)做一個(gè)簡(jiǎn)單的總結(jié)撵割。
android權(quán)限分類
Android6.0系統(tǒng)把權(quán)限分為兩個(gè)級(jí)別:
- Normal Permissions贿堰,即普通權(quán)限,這類權(quán)限不會(huì)潛藏有侵害用戶隱私和安全的問(wèn)題睁枕,比如官边,訪問(wèn)網(wǎng)絡(luò)的權(quán)限,訪問(wèn)WIFI的權(quán)限等外遇;
- Dangerous Permissions注簿,即危險(xiǎn)權(quán)限,這類權(quán)限會(huì)直接的威脅到用戶的安全和隱私問(wèn)題跳仿,比如說(shuō)訪問(wèn)短信诡渴,相冊(cè)等權(quán)限。
普通權(quán)限是不會(huì)威脅到用戶安全的菲语,所以這類權(quán)限是可以直接在manifest里面直接的使用妄辩,而且在安裝后也會(huì)直接的生效了。不需要特殊處理山上。危險(xiǎn)權(quán)限在使用時(shí)不僅需要在manifest里面注冊(cè)眼耀,還需要?jiǎng)討B(tài)申請(qǐng),否則程序會(huì)崩潰佩憾,提示沒(méi)有權(quán)限哮伟。
危險(xiǎn)權(quán)限分為9組,總共24個(gè)權(quán)限妄帘,如下:
權(quán)限組名 | 權(quán)限名 |
---|---|
CALENDAR 日歷 | READ_CALENDAR WRITE_CALENDER |
CAMERA 相機(jī) | CAMERA |
CONTACTS 聯(lián)系人 | READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS |
LOCATION 定位 | ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION |
MICROPHONE 麥克風(fēng) | RECORD_AUDIO |
PHONE 電話 | READ_PHONE_STATE CALL_PHONE READ_CALL_LOG WRITE_CALL_LOG ADD_VOICEMAIL USE_SIP PROCESS_OUTGOING_CALLS |
SENSORS 傳感器 | BODY_SENSORS |
SMS 短信 | Short Message Service SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS |
STORAGE 數(shù)據(jù)存儲(chǔ) | READ_EXTRAL_STRORAGE WRITE_EXTERNAL_STORAGE |
申請(qǐng)權(quán)限時(shí):
1楞黄、在清單文件中聲明權(quán)限(如果不在這張表中,聲明完就可以了)
2抡驼、如果在這張表中的權(quán)限需要手動(dòng)來(lái)申請(qǐng)
這些權(quán)限6.0以后需要手動(dòng)申請(qǐng)鬼廓,,每一個(gè)權(quán)限組中的權(quán)限只要有一個(gè)權(quán)限同意授權(quán)了致盟,整個(gè)權(quán)限組中的權(quán)限就不用重復(fù)申請(qǐng)了碎税。
如果如果查看所有的權(quán)限,請(qǐng)參考:
https://developer.android.com/about/versions/marshmallow
android 權(quán)限使用場(chǎng)景
由于android 系統(tǒng)版本太多馏锡,并且用戶使用的手機(jī)版本也無(wú)法確定雷蹂,因此在權(quán)限處理時(shí),需要多方面考慮眷篇。 而對(duì)于開(kāi)發(fā)者而言萎河,最主要考慮的是 targetversion和buildVersion(即真機(jī)系統(tǒng)版本)荔泳。下面從以下方面考慮:
targetVersion | BuildVersion | 是否需要處理 |
---|---|---|
>=23 | >=23 | 需要?jiǎng)討B(tài)處理 |
>=23 | <23 | 不需要 |
< 23 | >=23 | 需要處理 |
< 23 | <23 | 不需要 |
權(quán)限基本使用
- 在manifest.xml文件中聲明需要的權(quán)限
- 檢查是否擁有權(quán)限蕉饼,通過(guò)checkSelfPermission函數(shù)虐杯,如下:
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
//沒(méi)有授權(quán),編寫申請(qǐng)權(quán)限代碼
}else{
//已經(jīng)授權(quán)昧港,執(zhí)行操作代碼
}
checkSelfPermission函數(shù)有兩個(gè)參數(shù):context和需要的權(quán)限
- 若沒(méi)有權(quán)限則申請(qǐng)權(quán)限擎椰,如下:
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
1);
這是一個(gè)異步的方法,第一個(gè)參數(shù)是Context创肥;第二個(gè)參數(shù)是需要申請(qǐng)的權(quán)限的字符串?dāng)?shù)組(這個(gè)是支持同時(shí)申請(qǐng)多個(gè)權(quán)限达舒,系統(tǒng)會(huì)逐個(gè)詢問(wèn)是否授權(quán));第三個(gè)參數(shù)為請(qǐng)求碼requestCode叹侄,主要用于回調(diào)的時(shí)候檢測(cè)巩搏。
- 處理權(quán)限的回調(diào)結(jié)果
//權(quán)限回調(diào)方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 0:
//grantResults數(shù)組存儲(chǔ)的申請(qǐng)的返回結(jié)果,
//PERMISSION_GRANTED 表示申請(qǐng)成功
if (grantResults.length>0&&grantResults[0]== PackageManager.PERMISSION_GRANTED){
//授權(quán)成功趾代,
//這里寫相應(yīng)的 操作代碼
}else{
//授權(quán)失敗贯底,可以簡(jiǎn)單提示用戶
Toast.makeText(this, "沒(méi)有授權(quán)繼續(xù)操作", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
注意:申請(qǐng)的時(shí)候是一個(gè)一個(gè)的申請(qǐng)的話,每次申請(qǐng)都有一個(gè)請(qǐng)求碼撒强,這里的grantResults數(shù)組就只有一個(gè)值禽捆,所以都是grantResults[0]來(lái)和PERMISSION_GRANTED來(lái)進(jìn)行比較
如果是一次申請(qǐng)多個(gè)權(quán)限,grantResults數(shù)組返回的值就不止一個(gè)飘哨,但是胚想,直接遍歷它就行,只要全部滿足條件才算申請(qǐng)成功芽隆,才能進(jìn)行相應(yīng)的操作
一般的寫法是:
通過(guò)if判斷權(quán)限是否申請(qǐng)浊服,沒(méi)有申請(qǐng),把它加到一個(gè)集合里面摆马,把所有的權(quán)限都判斷一遍以后臼闻,去遍歷這個(gè)集合,只要有一個(gè)沒(méi)有申請(qǐng)的囤采,就需述呐、要去申請(qǐng)權(quán)限, 把這個(gè)集合轉(zhuǎn)為數(shù)組蕉毯,傳到requestPermissions的第二個(gè)參數(shù)乓搬,然后就處理相應(yīng)結(jié)果就可以了,遍歷grantResults數(shù)組代虾,判斷是不是全部滿足條件
特殊處理
但 targetVersion小于23进肯,但是BuildVersion大于23這個(gè)場(chǎng)景時(shí),若用戶在應(yīng)用權(quán)限設(shè)置里面手動(dòng)關(guān)閉了要使用的權(quán)限棉磨,在應(yīng)用操作時(shí)江掩,檢查權(quán)限會(huì)一直返回true,并且系統(tǒng)崩潰。
導(dǎo)致這個(gè)的原因环形,是 ContextCompat.checkSelfPermission函數(shù)再TargetVersion<23時(shí)策泣,會(huì)一直返回true。因此為了兼容此情形抬吟,V4包里面提供了PermissionChecker.checkSelfPermission函數(shù)萨咕,用來(lái)處理這種情形。因此火本,考慮兩種情形危队,完成的權(quán)限檢查代碼如下:
/**
* android 6.0 以上檢查是否有權(quán)限
* @param context context
* @param primission 權(quán)限名稱
* @return false 沒(méi)有權(quán)限 true 有權(quán)限
*/
private boolean checkPrimission(Context context ,String primission)
{
int targetSdkVersion ;
boolean result = false;
PackageInfo info = null;
try {
info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
targetSdkVersion = info.applicationInfo.targetSdkVersion;
if (targetSdkVersion >= Build.VERSION_CODES.M) { //targetSdkVersion >= 23
if (ContextCompat.checkSelfPermission(cdActivity, primission) != PackageManager.PERMISSION_GRANTED) {
result = false;
}else{
result = true;
}
} else { //targetSdkVersion < 23
if (PermissionChecker.checkSelfPermission(cdActivity, Manifest.permission.CAMERA)
!= PermissionChecker.PERMISSION_GRANTED) {
result = false;
}else{
result = true;
}
}
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG,e.getMessage());
}
return result;
}
多次請(qǐng)求處理
shouldShowRequestPermissionRationale應(yīng)用場(chǎng)景
//參數(shù)是一個(gè)權(quán)限,返回true或false
shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
?當(dāng)用戶第一次拒絕申請(qǐng)的權(quán)限钙畔,第二次再申請(qǐng)權(quán)限之前彈出一個(gè)對(duì)話框茫陆,給用戶做出一個(gè)解釋,為啥需要申請(qǐng)權(quán)限擎析,根據(jù)用戶的選擇盅弛,再考慮是否申請(qǐng)權(quán)限。
該函數(shù)返回值根據(jù)不同情形有以下情況:
?1. 第一次請(qǐng)求某權(quán)限時(shí)叔锐,返回值為false
?2. 第一次請(qǐng)求某權(quán)限拒絕后挪鹏,返回值為true
?3. 第二次請(qǐng)求某權(quán)限拒絕后,返回值為true
?4. 第三次請(qǐng)求某權(quán)限愉烙,點(diǎn)了不再提醒讨盒,并拒絕,返回值為false
?5. 任何時(shí)候步责,只要允許了權(quán)限返顺,返回值就為false
因此根據(jù)這些情況可以做一下特殊處理
- 在請(qǐng)求權(quán)限前,調(diào)用此函數(shù)蔓肯,判斷是否需要和用戶解釋(true,表示拒絕過(guò)一次)遂鹊;
- 在onRequestPermissionsResult里面調(diào)用,判斷用戶是否點(diǎn)了“不在詢問(wèn)”蔗包,并拒絕秉扑。可以彈出對(duì)話框引導(dǎo)用戶去設(shè)置頁(yè)面設(shè)置调限。
??不再提醒權(quán)限方法:(用戶勾選拒絕后不再詢問(wèn))
//參數(shù)是一個(gè)權(quán)限舟陆,返回true或false
shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
返回true表示用戶沒(méi)有勾選 拒絕后不再詢問(wèn),你可以再去調(diào)用requestPermissions申請(qǐng)權(quán)限
返回false分幾種情況:
1.用戶勾選了 拒絕后不再詢問(wèn)耻矮,你只能引導(dǎo)用戶去設(shè)置中開(kāi)啟權(quán)限了
2.用戶自己在設(shè)置中把權(quán)限給關(guān)了...
3.系統(tǒng)禁止應(yīng)用具有該權(quán)限!
注意:部分手機(jī)會(huì)對(duì)權(quán)限有自己的默認(rèn)處理秦躯,比如小米,該函數(shù)一直返回false裆装,因此踱承,針對(duì)于不同的手機(jī)需要自己適配處理該方法倡缠。
android 8.0 處理
??在android 6.0 之上,最開(kāi)始的處理是: 只要一組權(quán)限中的一個(gè)權(quán)限通過(guò)茎活,該組其他權(quán)限也默認(rèn)通過(guò)毡琉。
??對(duì)于針對(duì)Android O的應(yīng)用,此行為已被糾正妙色。系統(tǒng)只會(huì)授予應(yīng)用明確請(qǐng)求的權(quán)限。然而一旦用戶為應(yīng)用授予某個(gè)權(quán)限慧耍,則所有后續(xù)對(duì)該權(quán)限組中權(quán)限的請(qǐng)求都將被自動(dòng)批準(zhǔn)身辨。
例如,假設(shè)某個(gè)應(yīng)用在其清單中列出READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE芍碧。應(yīng)用請(qǐng)求READ_EXTERNAL_STORAGE煌珊,并且用戶授予了該權(quán)限,如果該應(yīng)用針對(duì)的是API級(jí)別24或更低級(jí)別泌豆,系統(tǒng)還會(huì)同時(shí)授予WRITE_EXTERNAL_STORAGE定庵,因?yàn)樵摍?quán)限也屬于STORAGE權(quán)限組并且也在清單中注冊(cè)過(guò)。如果該應(yīng)用針對(duì)的是Android O踪危,則系統(tǒng)此時(shí)僅會(huì)授予READ_EXTERNAL_STORAGE蔬浙,不過(guò)在該應(yīng)用以后申請(qǐng)WRITE_EXTERNAL_STORAGE權(quán)限時(shí),系統(tǒng)會(huì)立即授予該權(quán)限贞远,而不會(huì)提示用戶畴博。
權(quán)限請(qǐng)求框架
- RxPermission
- PermissionsDispatcher
- EasyPermissions
具體使用方式后續(xù)補(bǔ)充±吨伲可以github上自行搜索使用方式俱病。
自己也封裝過(guò)一個(gè)框架
github地址:https://github.com/YuanQiCan/PermissionGrant
包含以下功能:
- 權(quán)限檢查,targetSdkVersion 大于23和小于23兩種情形
- 單個(gè)權(quán)限和多個(gè)權(quán)限申請(qǐng)?zhí)幚?/li>
- shouldShowRequestPermissionRationale包含的情形處理
- 基本對(duì)畫框顯示和頁(yè)面跳轉(zhuǎn)
有興趣的可以看看袱结,使用方便亮隙。