(注意:Android O 8.0對於權限更加嚴格,下面會說一下8.0)
android6.0之後有些危險權限須要手動去受權,就有了運行時權限的處理。下面的表格就是危險權限組:android
權限組名 | 權限名 |
---|---|
CALENDAR 日曆 | READ_CALENDAR WRITE_CALENDER |
CAMERA 相機 | CAMERA |
CONTACTS 聯繫人 | READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS |
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 |
SENSORS 傳感器 | BODY_SENSORS |
SMS 短信 | Short Message Service SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS |
STORAGE 數據存儲 | READ_EXTRAL_STRORAGE WRITE_EXTERNAL_STORAGE |
申請權限時:
一、在清單文件中聲明權限(若是不在這張表中,聲明完就能夠了)
二、若是在這張表中的權限須要手動來申請git
這些權限6.0之後須要手動申請,,每個權限組中的權限只要有一個權限贊成受權了,整個權限組中的權限就不用重複申請了。
若是若是查看全部的權限,請參考:https://segmentfault.com/a/11...github
傳統的申請過程是:
一、在AndroidManifest文件中添加須要的權限。
二、檢查權限是否受權
三、申請權限
四、處理受權的結果segmentfault
一步步來:
一、首先在請單文件中聲明,這個不用說
二、檢查權限是否受權api
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { //沒有受權,編寫申請權限代碼 }else{ //已經受權,執行操做代碼 }
基本上調用checkSelfPermission()函數傳入權限參數,返回的結果又兩個:
若是是已受權的權限,該方法返回結果是 PackageManager.PERMISSION_GRANTED 常量爲 0,
若是是未受權的權限,該方法返回結果是 PackageManager.PERMISSION_DENIED 常量爲 -1。
這樣就能夠判斷是否已經受權,來進行下一步的操做。數組
三、若是沒有受權,須要申請權限app
ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
這是一個異步的方法,第一個參數是Context;第二個參數是須要申請的權限的字符串數組(這個是支持同時申請多個權限,系統會逐個詢問是否受權);第三個參數爲請求碼requestCode,主要用於回調的時候檢測。框架
四、處理權限申請的回調結果
重寫Activity或者fragment的 onRequestPermissionsResul()方法異步
//權限回調方法 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 0: //grantResults數組存儲的申請的返回結果, //PERMISSION_GRANTED 表示申請成功 if (grantResults.length>0&&grantResults[0]== PackageManager.PERMISSION_GRANTED){ //受權成功, //這裏寫相應的 操做代碼 }else{ //受權失敗,能夠簡單提示用戶 Toast.makeText(this, "沒有受權繼續操做", Toast.LENGTH_SHORT).show(); } break; case 1: //同上 break; default: break; } } 這裏稍微說一下,申請的時候是一個一個的申請的話,每次申請都有一個請求碼, 這裏的grantResults數組就只有一個值,因此都是grantResults[0]來和 PERMISSION_GRANTED來進行比較 若是是一次申請多個權限,grantResults數組返回的值就不止一個,可是,直接遍歷 它就行,只要所有知足條件纔算申請成功,才能進行相應的操做 通常的寫法是:經過 if判斷權限是否申請,沒有申請,把它加到一個集合裏面,把全部的權限都判斷一遍 之後,去遍歷這個集合,只要有一個沒有申請的,就需、要去申請權限, 把這個集合轉爲數組,傳到requestPermissions的第二個參數,而後就處理相應 結果就能夠了,遍歷grantResults數組,判斷是否是所有知足條件
GitHub地址:https://github.com/googlesamp...
EasyPermissions是谷歌封裝的一個運行時權限申請的庫,簡化了操做的過程。
使用過程: 沒有什麼前後順序,下面沒有按這個順序。這麼作是能夠的,固然還有其餘的使用方法ide
一、builde gradle中依賴
二、清單文件中聲明權限
三、重寫onRequestPermissionsResult()方法,把執行操做給easyPermissions來
四、經過hasPermissions檢查權限,或者原生的也行,而後去申請權限
五、實現EasyPermissions.PermissionCallbacks接口,重寫兩個方法,成功或失敗
六、在成功或者失敗方法中編寫要具體作的事。
GitHub地址:
(1)依賴庫
dependencies { compile 'pub.devrel:easypermissions:1.0.1' }
(2)再在清單文件中聲明要申請的危險權限
若是不聲明的話,直接在代碼中寫也能申請成功,可是好想不會彈出詢問框,直接就申請了
(3)申請權限
能夠直接申請
EasyPermissions.requestPermissions( MainActivity.this, "申請權限", 0, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO);
最好仍是檢查一下權限是否申請:
EasyPermissions.hasPermissions(Context context, @NonNull String… perms)方法來檢測一個或者多個權限是否被容許,第二個參數是個可變數組,能夠申請多個
String[] perms = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION}; if (EasyPermissions.hasPermissions(this, perms)) { // 已經申請過權限,作想作的事 } else { // 沒有申請過權限,如今去申請 EasyPermissions.requestPermissions(this, getString(R.string.camera_and_location_rationale), RC_CAMERA_AND_LOCATION, perms); }
下面來講一個申請權限這個方法:
EasyPermissions.requestPermissions():
requestPermissions() 通常用這個四個參數的就能夠
第一個參數:Context對象
第二個參數:權限彈窗上的文字提示語。告訴用戶,這個權限用途。
第三個參數:此次請求權限的惟一標識請求碼,code。
第四個參數 : 一些系列的權限。
這裏說一下第二個參數,不是第一次申請系統默認彈出的提示語,而是,咱們拒絕後,再次點擊申請彈出的對話框,,顯示咱們設置的提示語,下面有兩個按鈕,確認和取消,我就不貼圖了。
還有六個參數的,多了兩個參數就是,修改咱們上面那個確認和取消的字樣,你能夠幹成yes 和no.
四、重寫onRequestPermissionsResult()方法,把執行操做給easyPermissions
一行代碼就搞定了
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); }
五、實現EasyPermissions.PermissionCallbacks接口,重寫兩個方法
public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // 把執行結果的操做給EasyPermissions EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } @Override //申請成功時調用 public void onPermissionsGranted(int requestCode, List<String> list) { //請求成功執行相應的操做 好比,舉個例子 switch (requestCode){ case 0: Toast.makeText(this, "已獲取WRITE_EXTERNAL_STORAGE權限", Toast.LENGTH_SHORT).show(); break; case 1: Toast.makeText(this, "已獲取WRITE_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE權限", Toast.LENGTH_SHORT).show(); break; } } @Override //申請失敗時調用 public void onPermissionsDenied(int requestCode, List<String> list) { // 請求失敗,執行相應操做 } }
接下來就要說一下成功或者失敗後的操做了: 申請成功就直接作該作的事就好了,沒啥。
申請若是失敗了,這時候有個方法出現了EasyPermissions.somePermissionPermanentlyDenied(this, perms)
這個方法是谷歌建議的。就是在咱們點了不在詢問並拒絕,會彈出對話框,告訴用戶這個權限時幹嗎的,很重要,建議不要拒絕哈哈
好比這樣:
@Override public void onPermissionsDenied(int requestCode, List<String> perms) { if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { new AppSettingsDialog.Builder(this).build().show(); //彈出個對話框 }
}
固然咱們能夠定製一下這個對話框:
@Override public void onPermissionsDenied(int requestCode, List<String> perms) { //處理權限名字字符串 StringBuffer sb = new StringBuffer(); for (String str : perms){ sb.append(str); sb.append("\n"); } sb.replace(sb.length() - 2,sb.length(),""); switch (requestCode){ case 0: Toast.makeText(this, "已拒絕權限" + perms.get(0), Toast.LENGTH_SHORT).show(); break; case 1: Toast.makeText(this, "已拒絕WRITE_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE權限"+ perms.get(0), Toast.LENGTH_SHORT).show(); break; } if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { Toast.makeText(this, "已拒絕權限" + sb + "並再也不詢問" , Toast.LENGTH_SHORT).show(); new AppSettingsDialog .Builder(this) .setRationale("此功能須要" + sb + "權限,不然沒法正常使用,是否打開設置") .setPositiveButton("是") .setNegativeButton("否") .build() .show(); } }
六、(可選)@AfterPermissionGranted()註解
使用 AfterPermissioonGranted 註解。這是可選的,可是提供出來是爲了方便。若是全部的請求的權限都被授予了,被註解的方法將會被執行,這樣作是爲了簡化一般的請求權限成功以後再調用方法的流程。同時也能夠在onPermissionsGranted 的回調中添加邏輯操做:
好比官網上的這個實例代碼:
這裏的方法名能夠本身取,主要是權限都申請完,就調用這個方法,執行裏面的操做。
其實就至關於在onPermissionsGranted()調用這個方法而已:
@AfterPermissionGranted(RC_CAMERA_AND_LOCATION) private void methodRequiresTwoPermission() { String[] perms = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION}; if (EasyPermissions.hasPermissions(this, perms)) { // Already have permission, do the thing // ... } else { // Do not have permissions, request them now EasyPermissions.requestPermissions(this, getString(R.string.camera_and_location_rationale), RC_CAMERA_AND_LOCATION, perms); } }
基本上介紹完了
對於針對Android O的應用,此行爲已被糾正。系統只會授予應用明確請求的權限。然而一旦用戶爲應用授予某個權限,則全部後續對該權限組中權限的請求都將被自動批准。
例如,假設某個應用在其清單中列出READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE。應用請求READ_EXTERNAL_STORAGE,而且用戶授予了該權限,若是該應用針對的是API級別24或更低級別,系統還會同時授予WRITE_EXTERNAL_STORAGE,由於該權限也屬於STORAGE權限組而且也在清單中註冊過。若是該應用針對的是Android O,則系統此時僅會授予READ_EXTERNAL_STORAGE,不過在該應用之後申請WRITE_EXTERNAL_STORAGE權限時,系統會當即授予該權限,而不會提示用戶。
注意:若是使用了沒有受權的權限,會崩潰的
因此對於8.0權限,咱們要作的處理,是儘可能把所用到的危險權限所有申請。可是有的權限在不一樣版本出現,因此要兼容不一樣的版本,因此要加一個版本的判斷。
歸根結底:android M (6.0)之後,申請權限組一個,即表示整個權限組能夠用,因此咱們乾脆,只要api 版本大於23(6.0),咱們申請的權限就是申請整個權限組。這樣就兼容了android8.0-------------------爲了省事的話能夠用AndPermission這個第三方框架,或者本身封裝一個。