Android M對應用的授權策略做了變動,如果我們想調用getDeviceId()獲取手機串碼,只在Manifest裏添加android.permission.READ_PHONE_STATE權限是不夠的,如果不做權限的動態申請和處理,可能會報如下錯誤:
AndroidRuntime: java.lang.SecurityException: getDeviceId: Neither user 10201 nor current process has android.permission.READ_PHONE_STATE.1
那如何在代碼中動態申請權限呢?分四步進行:
第一步,在Manifest文件中添加權限:
1
第二步, 要獲取權限進行操作的Activity實現 ActivityCompat.OnRequestPermissionsResultCallback接口(這一步貌似不是必須):
public class MainActivity extends Activity
implements ActivityCompat.OnRequestPermissionsResultCallback {
第三步,動態申請權限並做處理:
int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_READ_PHONE_STATE);
} else {
//TODO
}
其中REQUEST_READ_PHONE_STATE 是自定義的類常量,可以像下面這樣在activity中定義:
public final static int REQUEST_READ_PHONE_STATE = 1;
第四步, 重寫onRequestPermissionsResult()方法,對權限申請結果做處理:
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_READ_PHONE_STATE:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
//TODO
}
break;
default:
break;
}
}
下面對關鍵方法做一個解釋:
1、檢查是否有權限:
ActivityCompat.checkSelfPermission
eg:檢查是否有讀取聯繫人權限
ActivityCompat.checkSelfPermission(this,Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED
2、是否重新請求授權(用戶之前拒絕過):
ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_CONTACTS)
如果應用之前請求過此權限但用戶拒絕了請求,此方法將返回 true,意思是說要給用戶一個 解釋,告訴用戶爲什麼要這個權限。
然而,在實際開發中,很多手機對原生系統做了修改,比如小米4的6.0的shouldShowRequestPermissionRationale 就一直返回false,而且在申請權限時,如果用戶選擇了拒絕,則不會再彈出對話框了。如果是這樣,我們可以在回調裏面處理,如果用戶拒絕了這個權限,則打開本應用信息界面,由用戶自己手動開啓這個權限。
3、請求授權:
ActivityCompat.requestPermissions
注意的是,調用此方法後,系統會彈出一個權限申請框,供用戶選擇,這個選擇框我們無法更改:
而且此時activity會調用onPause()方法,用戶做了選擇之後,此對話框消失,onResume()方法又會執行。
注:在華爲設備上測試,如果用戶勾選了“不再詢問”的選項的話,shouldShowRequestPermissionRationale會返回false。而且如果再次調用requestPermissions申請權限,就不會有申請框彈出,而是直接返回申請失敗。但是activity的生命週期方法的執行順序和有系統提示框彈出時的順序是一樣的。
4、搜權結果,通過 ActivityCompat.OnRequestPermissionsResultCallback 回調獲取授權結果,判斷是否授權。
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_INFO_OF_PHONE_SETTINGS) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
L.d("imei", "permission is granted after requested!");
} else if (grantResults[0] == PackageManager.PERMISSION_DENIED){
L.d("imei", "permission is not granted after requested!");
//這裏表示申請權限後被用戶拒絕了
} else {
L.d("imei", "permission is not granted after requested!");
}
}
}
關於更多運行時請求權限的問題,可以查看https://developer.android.com/training/permissions/requesting.html
更詳細請看http://mdsa.51cto.com/art/201508/489882_all.htm#topx