基本概念大家都知道
我就一筆帶過了
Android 6.0是Android發展史上的一個分水嶺,從這個版本開始無論是系統流暢度、運行速度、安全性、用戶隱私保護、用戶控制、動態授權等都得到了質的提升。
其中隱私保護就體現在動態權限獲取上,也是從這個版本開始需要進行動態的用戶權限獲取
既然說到權限獲取,那就需要先知道爲什麼要獲取權限
google 將一些權限等級提升,歸爲危險權限,將這些權限是否授權給App的選擇權交給用戶
危險權限列表,這裏不列出,也不一定想看這些列表,請自行搜索
動態權限申請涉及到四個系統方法的使用
我們以WRITE_EXTERNAL_STORAGE爲例
// 判斷當前權限是否曾經授權過
1:ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)
// 請求權限
2:ActivityCompat.requestPermissions(SplashActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_CODE)
// 權限結果回調
3:onRequestPermissionsResult()
// ??????這是個啥?我敢保證你不知道,如果你知道就不會看到我這篇博客了(是否需要解釋我爲什麼需要這個權限)
4:ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
開始進行動態權限申請
第一步:在清單文件中配置相關權限
一定要聲明相關權限,不然不管如何申請系統都不會彈出權限彈窗的
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
然後就要在App啓動時或者需要權限的地方進行權限申請了
因爲權限是隻需要授權一次之後,就不需要多次請求了,所以說理想狀態下,一個App在一個手機中的一生,只會進行一次權限申請,如果是已經授權過的還要重複申請顯然是有點浪費
所以我們在進行權限申請之前,先判斷當前權限是否需要申請,也就是說是否已經授權過了
// 判斷權限是否需要申請
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 需要進行權限申請
} else {
// 不需要進行權限申請或者所有權限都已授權
}
需要注意的有兩點
1、 有權限則會返回常量 PackageManager.PERMISSION_GRANTED,他的值是0;
沒有權限則返回 PackageManager.PERMISSION_DENIED,他的值爲 -1;
2、這裏傳進去的是一個常量PackageManager.PERMISSION_DENIED,他對應的值是
public static final String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
當然,我們可以將這個字符串手寫傳進去,但注意:如果值不對是無法彈出權限申請窗的。所以說既然android系統提供了這個常量,那我們爲什麼不使用呢?
如果不需要申請權限則正常執行業務流程就OK
我們要說的是需要申請權限的情況
一般國內的做法是直接進行權限申請了,很霸道,用戶壓根不知道你爲什麼要這麼多權限,給一個還要,給一個還要,給着給着心裏就開始發毛了
官方建議的做法通常是先彈出一個自己的彈窗,告訴用戶我需要哪些權限以及拿這些權限的原因和目的,讓用戶有足夠的心理準備,用戶點擊知道後,就可以開始進行權限申請了
我們繼續說用戶點擊知道後的操作
我們調用這個方法來進行權限申請:
ActivityCompat.requestPermissions(SplashActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_CODE)
注意:String數組的的權限是一次性可以放進去一組的,不需要分開來重複調用此方法
調用完此方法之後,系統會自動彈出權限申請彈窗像用戶索取權限,在權限申請回調中我們能監聽到用戶是否授予了我們權限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 判斷是否是我們剛剛發起的權限申請
switch (requestCode) {
case PERMISSIONS_REQUEST_CODE:
// 判斷是否是已經授權過
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 執行授權後的操作
} else {
// 執行未授權的操作
// 判斷是否曾經拒絕並且勾選了不再提醒(我應該向用戶解釋一下我爲什麼要這些權限嗎)
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// 彈出解釋框
} else {
// 跳轉到系統權限設置頁面
}
}
break;
default:
break
}
}
好我們來看一下回調裏的這一堆判斷
首先判斷一下請求碼是不是我們剛剛發起的請求
然後判斷是否已經授權過當前權限,其實如果你在權限申請之前做的夠好的話是永遠不會走到這個判斷裏面來的,有權限了爲什麼還要申請讓系統告訴你你有權限了呢,直接自己判斷不就好了,還省效率,按照我們上面的判斷就可以實現了
然後我們重點講一下未授權的時候的操作
我們先調用ActivityCompat.shouldShowRequestPermissionRationale
我們先來翻譯一下,大白話就是:我應該向用戶解釋一下我爲什麼要這些權限嗎?
假如說你是android系統,一個App問你需不需要解釋,那你會在什麼時候告訴他需要,什麼時候告訴他不需要呢?
我們來分不同的場景來分析一下
1:App第一次安裝打開,android認爲是不需要解釋的,所以這個時候返回的是false,這時候有人要說了,你上面不是說要加提醒告訴你要申請什麼權限讓他們心裏有數嗎?是的,但是注意那是說明,不是解釋,說明彈窗和解釋彈窗的目的是不一樣的,所以說內容也不一樣,當然你也可以寫成一樣的
2:從來都沒有展示給用戶權限申請的彈窗,android認爲是不需要解釋的,因爲用戶都沒有看到權限申請,說不定就同意了呢,爲什麼要解釋呢?這個其實和第一種是同一個情況
3:用戶點擊了拒絕,然後再次進行權限申請前,android認爲是需要解釋的,因爲android認爲用戶拒絕了,你有必要解釋一下了
4:用戶點擊了拒絕,並且勾選了不再提醒,android認爲是不需要解釋的,因爲解釋也沒有卵用了,系統是再也不會拉起權限彈窗詢問用戶了,那你還解釋個毛
總結一下:只要第3種情況是需要解釋的,其他的情況都不需要解釋
所以說ActivityCompat.shouldShowRequestPermissionRationale真正用法是在回調中配合需要申請權限的時候使用的,有人在沒調用權限申請之前就詢問系統,所以說永遠返回的是false
所以說ActivityCompat.shouldShowRequestPermissionRationale的作用也是可以判斷是否勾選了不再提醒,如果沒勾選就解釋,勾選了就跳轉到系統設置頁面
有時間錄製一個gif圖展示給大家