參考:
一. 權(quán)限說明:
1. 權(quán)限種類:
Android中權(quán)限分為正常權(quán)限(即拣度,不會(huì)對(duì)用戶隱私或設(shè)備操作造成很大風(fēng)險(xiǎn)的權(quán)限)和危險(xiǎn)權(quán)限(即趣席,可能影響用戶隱私或設(shè)備正常操作的權(quán)限):
正常權(quán)限涵蓋應(yīng)用需要訪問其沙盒外部數(shù)據(jù)或資源,但對(duì)用戶隱私或其他應(yīng)用操作風(fēng)險(xiǎn)很小的區(qū)域孩哑。例如癌蓖,設(shè)置時(shí)區(qū)的權(quán)限就是正常權(quán)限怯晕。如果應(yīng)用聲明其需要正常權(quán)限哟旗,系統(tǒng)會(huì)自動(dòng)向應(yīng)用授予該權(quán)限。如需當(dāng)前正常權(quán)限的完整列表荣病,請(qǐng)參閱正常權(quán)限。
危險(xiǎn)權(quán)限涵蓋應(yīng)用需要涉及用戶隱私信息的數(shù)據(jù)或資源个盆,或者可能對(duì)用戶存儲(chǔ)的數(shù)據(jù)或其他應(yīng)用的操作產(chǎn)生影響的區(qū)域脖岛。例如颊亮,能夠讀取用戶的聯(lián)系人屬于危險(xiǎn)權(quán)限。如果應(yīng)用聲明其需要危險(xiǎn)權(quán)限,則用戶必須明確向應(yīng)用授予該權(quán)限件舵。
危險(xiǎn)權(quán)限和權(quán)限組:
2. 權(quán)限的授予:
如果您的應(yīng)用在其清單中列出正常權(quán)限,系統(tǒng)會(huì)自動(dòng)授予這些權(quán)限。如果您的應(yīng)用在其清單中列出危險(xiǎn)權(quán)限合武,系統(tǒng)會(huì)要求用戶明確授予這些權(quán)限临梗。Android 發(fā)出請(qǐng)求的方式取決于系統(tǒng)版本:
如果設(shè)備運(yùn)行的是 Android 6.0(API 級(jí)別 23)或更高版本,并且應(yīng)用的 targetSdkVersion
是 23 或更高版本稼跳,則應(yīng)用在運(yùn)行時(shí)向用戶請(qǐng)求權(quán)限盟庞。用戶可隨時(shí)調(diào)用權(quán)限,因此應(yīng)用在每次運(yùn)行時(shí)均需檢查自身是否具備所需的權(quán)限汤善。如果設(shè)備運(yùn)行的是 Android 5.1(API 級(jí)別 22)或更低版本什猖,并且應(yīng)用的 targetSdkVersion
是 22 或更低版本票彪,則系統(tǒng)會(huì)在用戶安裝應(yīng)用時(shí)要求用戶授予權(quán)限。如果將新權(quán)限添加到更新的應(yīng)用版本不狮,系統(tǒng)會(huì)在用戶更新應(yīng)用時(shí)要求授予該權(quán)限降铸。用戶一旦安裝應(yīng)用,他們撤銷權(quán)限的唯一方式是卸載應(yīng)用摇零。
二. 動(dòng)態(tài)權(quán)限授予的幾個(gè)重要的方法:
注意:在Activity里調(diào)用時(shí)Context和Activity參數(shù)可以忽略
int ContextCompat.checkSelfPermission (Context context, String permission)參數(shù):(上下文, 需要判斷的權(quán)限[如:Manifest.permission.READ_CONTACTS])
該方法用來檢測(cè)應(yīng)用是否具有某權(quán)限推掸,返回值是PackageManager.PERMISSION_GRANTED(已授權(quán))或PackageManager.PERMISSION_GRANTED(未授權(quán))void requestPermissions (Activity, permissions, int requestCode)參數(shù):(上下文,需要申請(qǐng)的權(quán)限的列表(String數(shù)組)[如:new String[]{Manifest.permission.READ_CONTACTS}]驻仅,自己定義的requestCode[如:REQUEST_READ_CONTACTS(自定義int值)](主要是回調(diào)的時(shí)候用來判斷授權(quán)種類))
該方法用來請(qǐng)求權(quán)限终佛,請(qǐng)求過程會(huì)顯示一個(gè)Dialog(不可自定義),無論用戶是否確認(rèn)授權(quán)都會(huì)調(diào)用回調(diào)方法onRequestPermissionsResult()
void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults)參數(shù):(requestPermissions方法傳過來的參數(shù)雾家,要請(qǐng)求的權(quán)限列表铃彰,各權(quán)限的授權(quán)情況(與需要權(quán)限的數(shù)組對(duì)應(yīng)))
該方法是用戶請(qǐng)求權(quán)限之后的回調(diào)方法,用戶可以在這里做判斷進(jìn)行需要的操作芯咧。boolean shouldShowRequestPermissionRationale (Activity activity, String permission)參數(shù):(上下文牙捉,需要判斷的權(quán)限)
該方法判斷一個(gè)權(quán)限是否被拒絕過,Android官方對(duì)此方法的解釋是用該方法判斷是否需要給用戶進(jìn)行為什么需要權(quán)限的提示敬飒。
三. 動(dòng)態(tài)權(quán)限的申請(qǐng)
- manifest中注冊(cè)權(quán)限:(如需要訪問通訊錄權(quán)限)
<uses-permission android:name="android.permission.READ_CONTACTS" />
- 詢問是否有該權(quán)限:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
switch (checkSelfPermission(Manifest.permission.READ_CONTACTS)){
case PackageManager.PERMISSION_GRANTED:
Log.i(TAG, "onCreate: Granted...");
break;
case PackageManager.PERMISSION_DENIED:
Log.i(TAG, "onCreate: Denied...");
Log.i(TAG, "onCreate: 是否被拒絕過:"+shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS));
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},REQUEST_READ_CONTACTS);//請(qǐng)求權(quán)限
break;
}
}
- 當(dāng)沒有該權(quán)限時(shí)請(qǐng)求授予權(quán)限:
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},REQUEST_READ_CONTACTS);
- 重載回調(diào)方法:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
/*判斷授權(quán)種類*/
if(requestCode == REQUEST_READ_CONTACTS){
/*授權(quán)成功*/
if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
Log.i(TAG, "onRequestPermissionsResult: 權(quán)限請(qǐng)求通過");
}
/*授權(quán)失敗*/
else {
Log.i(TAG, "onRequestPermissionsResult: 權(quán)限請(qǐng)求未通過");
}
}
}
四. 源碼:
package cn.foxnickel.androidpermission;
import android.Manifest;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
public static int REQUEST_READ_CONTACTS=100;
private final String TAG = getClass().getSimpleName();
@TargetApi(Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
switch (checkSelfPermission(Manifest.permission.READ_CONTACTS)){
case PackageManager.PERMISSION_GRANTED:
Log.i(TAG, "onCreate: Granted...");
break;
case PackageManager.PERMISSION_DENIED:
Log.i(TAG, "onCreate: Denied...");
Log.i(TAG, "onCreate: 是否被拒絕過:"+shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS));
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},REQUEST_READ_CONTACTS);
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
/*判斷授權(quán)種類*/
if(requestCode == REQUEST_READ_CONTACTS){
/*授權(quán)成功*/
if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
Log.i(TAG, "onRequestPermissionsResult: 權(quán)限請(qǐng)求通過");
}
/*授權(quán)失敗*/
else {
Log.i(TAG, "onRequestPermissionsResult: 權(quán)限請(qǐng)求未通過");
}
}
}
}
五. 封裝(轉(zhuǎn)自吳小龍博客)
BaseActivity:
public class BaseActivity extends AppCompatActivity {
public static int REQUEST_PERMISSION = 100;
public onPermissionCallbackListener onPermissionCallbackListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@TargetApi(M)
public void requestRuntimePermission(String permission, onPermissionCallbackListener onPermissionCallbackListener) {
this.onPermissionCallbackListener = onPermissionCallbackListener;
switch (checkSelfPermission(permission)) {
case PackageManager.PERMISSION_GRANTED:
// 已有授權(quán)
Log.i("wxl", "已有授權(quán)");
if (this.onPermissionCallbackListener != null)
onPermissionCallbackListener.onGranted();
break;
case PackageManager.PERMISSION_DENIED:
// 1邪铲、沒有權(quán)限:尚未請(qǐng)求過權(quán)限;
// 2无拗、或者請(qǐng)求授權(quán)被拒絕带到,用shouldShowRequestPermissionRationale判斷用戶是否拒絕過,如果返回true英染,表示用戶拒絕過揽惹,
// 再次請(qǐng)求權(quán)限,將會(huì)出現(xiàn)“不再詢問”四康,勾上“不再詢問”搪搏,只能選擇拒絕,再次進(jìn)入闪金,shouldShowRequestPermissionRationale始終false
// 3疯溺、或者曾經(jīng)授權(quán)過,但用戶在設(shè)置中禁用權(quán)限
Log.i("wxl", "是否拒絕過=" + shouldShowRequestPermissionRationale(permission));
requestPermissions(new String[]{permission}, REQUEST_PERMISSION);
break;
default:
break;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_PERMISSION) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 授權(quán)請(qǐng)求被通過哎垦,讀取通訊錄
Log.i("wxl", "onRequestPermissionsResult=授權(quán)請(qǐng)求被通過");
if (onPermissionCallbackListener != null)
onPermissionCallbackListener.onGranted();
} else {
Log.i("wxl", "onRequestPermissionsResult=授權(quán)請(qǐng)求不被通過");
if (onPermissionCallbackListener != null)
onPermissionCallbackListener.onDenied();
}
}
}
}
/*這里新建了接口onPermissionCallbackListener囱嫩,為了回調(diào)方便:*/
public interface onPermissionCallbackListener {
void onGranted();
void onDenied();
}
在需要使用到權(quán)限之前調(diào)用requestRuntimePermission方法,如通訊錄權(quán)限:
requestRuntimePermission(READ_CONTACTS, new onPermissionCallbackListener() {
@Override
public void onGranted() {
Log.i("wxl", "授權(quán)請(qǐng)求通過");
}
@Override
public void onDenied() {
Log.i("wxl", "授權(quán)請(qǐng)求拒絕");
}
});
六. 總結(jié)
- 先詢問是否已經(jīng)得到授權(quán)漏设,若已經(jīng)授權(quán)墨闲,則直接進(jìn)行操作,若未授權(quán)愿题,則請(qǐng)求權(quán)限损俭,然后在授權(quán)回調(diào)中進(jìn)行操作蛙奖。
- 可以在MainActivity中進(jìn)行授權(quán)管理,也可以封裝授權(quán)管理到BaseActivity
- 多個(gè)權(quán)限可以直接在String數(shù)組中加入(壞處:公用一個(gè)requestCode杆兵,不方便回調(diào)的判斷)雁仲,也可以重新詢問是否授權(quán)。
七.補(bǔ)充
- 申請(qǐng)多個(gè)權(quán)限時(shí)可以先判斷有沒有該權(quán)限琐脏,如果沒有就加到List中去攒砖,然后將List轉(zhuǎn)換為數(shù)組,然后調(diào)用
ActivityCompat.requestPermissions(Context,String []permissions,PERMISSIONS_REQ);
申請(qǐng)全部權(quán)限日裙。
代碼:
List<String> permissionList = new ArrayList<>();//申請(qǐng)權(quán)限的List
/*判斷*/
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){
if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
Log.i(TAG, "onCreate: finelocation denied");
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if(checkSelfPermission(Manifest.permission.READ_PHONE_STATE)!=PackageManager.PERMISSION_GRANTED){
Log.i(TAG, "onCreate: phonestate denied");
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED){
Log.i(TAG, "onCreate: write storage denied");
permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if(checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
Log.i(TAG, "onCreate: coarse location denied");
permissionList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
/*申請(qǐng)*/
if(!permissionList.isEmpty()){
String permissions[] = permissionList.toArray(new String[permissionList.size()]);
ActivityCompat.requestPermissions(this,permissions,PERMISSIONS_REQ);
}else {
requestLocation();
}
}else {
requestLocation();
}
- 另一種申請(qǐng)多個(gè)權(quán)限的寫法(自己定義申請(qǐng)權(quán)限的函數(shù))
- 調(diào)用requestPermission方法申請(qǐng)權(quán)限
/*判斷SDK版本吹艇,6.0以上就申請(qǐng)權(quán)限,將要申請(qǐng)的權(quán)限傳給requestPermission方法*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermission(Manifest.permission.SEND_SMS, Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_COARSE_LOCATION);
}
- requestPermission方法
@TargetApi(Build.VERSION_CODES.M)
private void requestPermission(String... permissions) {
List<String> permissionList = new ArrayList<>();//要申請(qǐng)的權(quán)限列表
/**
* 判斷權(quán)限是否已經(jīng)擁有昂拂,若未擁有則添加到List中
*/
for (String permission : permissions) {
switch (checkSelfPermission(permission)) {
case PackageManager.PERMISSION_GRANTED:
Log.i(TAG, "onCreate: Granted...");
break;
case PackageManager.PERMISSION_DENIED:
Log.i(TAG, "onCreate: Denied...");
permissionList.add(permission);
break;
}
}
//申請(qǐng)未擁有的權(quán)限
if (!permissionList.isEmpty()) {
requestPermissions(permissionList.toArray(new String[permissionList.size()]),REQUEST_PERMISSIONS);
}
}