聊聊Android6.0 以上系統(tǒng)權(quán)限

發(fā)熱放入Android6.0帶來了新的權(quán)限管理方式,根據(jù)提供的官方文檔,再加上自己的理解,做了以下匯總僅供大家伙參考,不好勿噴。

一個新建的Android應(yīng)用默認是沒有權(quán)限的,這意味著它不能執(zhí)行任何可能對用戶體驗有不利影響的操作或者訪問設(shè)備數(shù)據(jù)。為了使用受保護的功能,你必須包含一個或者多個標(biāo)簽在你的app manifest中。

1、Android 6.0中權(quán)限分為兩種,普通權(quán)限和危險權(quán)限(即運行時權(quán)限,下面統(tǒng)稱運行時權(quán)限)。

1.1普通權(quán)限

如果你的應(yīng)用manifest中只申明了普通權(quán)限(也就是說,這些權(quán)限對于用戶隱私和設(shè)備操作不會造成太多危險),系統(tǒng)會自動授予這些權(quán)限。

1.2運行時權(quán)限

如果你的應(yīng)用manifest中聲明了運行時權(quán)限(也就是說,這些權(quán)限可能會影響用戶隱私和設(shè)備的普通操作),系統(tǒng)會明確的讓用戶決定是否授予這些權(quán)限。系統(tǒng)請求用戶授予這些權(quán)限的方式是由當(dāng)前應(yīng)用運行的系統(tǒng)版本來決定的。

1.2.1 Android6.0及以上的系統(tǒng)

如果你的設(shè)備運行的是Android6.0(API level 23)及以上的系統(tǒng),并且你的應(yīng)用的targetSdkVersion也是23或者更高,那么應(yīng)用向用戶請求這些權(quán)限是實時的。這意味著用戶可以隨時取消 這些運行時權(quán)限的授權(quán)。所以應(yīng)用在每次需要用到這些運行時權(quán)限的時候都需要去檢查是否還有這些權(quán)限的授權(quán)。

1.2.2 Android 5.1及以下的系統(tǒng)

如果你的設(shè)備運行在Android5.1(API level 22)及以下的系統(tǒng)中,或者你的app的targetSdkVersion是22或者更低。系統(tǒng)會請求用戶在apk安裝的時候授予這些權(quán)限。

如果你的應(yīng)用更新的時候添加了一個權(quán)限,系統(tǒng)會在用戶更新應(yīng)用的時候請求用戶授予這個權(quán)限一旦用戶安裝了這個應(yīng)用,唯一可以取消授權(quán)的方式就是卸載掉這個應(yīng)用。注意這句話的意思,想一下如果app的targetSdkVersion是22或者以下,但是運行在Android6.0及以上的設(shè)備中會有什么問題?后面會分析這個問題

常常來說一個授權(quán)失敗會拋出SecurityException,然而這并不是在 所有情況下都會發(fā)生。比如,發(fā)送一個廣播去檢查授權(quán)(SendBroadcast(Intent)),數(shù)據(jù)會被發(fā)送給所有接收者,但是當(dāng)這個方法的請求返 回的時候,你不會收到任何一個因為授權(quán)失敗拋出的異常,其實在大多數(shù)情況下,授權(quán)失敗只會打印系統(tǒng)日志。

1.3自動權(quán)限調(diào)整

簡單的說,如果你的app targetSdkVersion是3,而你當(dāng)前運行的系統(tǒng)版本是4,那么在android version 4 中新添加的權(quán)限會自動添加到你的app中。

比如WRITE_EXTERNAL_STORAGE權(quán)限是在api 4的時候添加的,而你的應(yīng)用的targetSdkVersion是3,那么這個權(quán)限會自動添加到你的應(yīng)用中。而且在官方商店上這個權(quán)限也會列出來(盡管可能你并不需要這個權(quán)限)。

所以建議經(jīng)常更新你的targetSdkVersion到最新版本。

下面來回答上面的那個問題,如果app的targetSdkVersion是22或者以下,但是運行在android 6.0或以上版本的手機中,會發(fā)生什么?

安裝過程中,會一起請求用戶授予所有 權(quán)限,如果用戶拒絕,將不能安裝這個app,只有用戶全部同意這些授權(quán),才能安裝這個應(yīng)用,但是問題來了,安裝好了這個應(yīng)用之后,android6.0以 上的系統(tǒng)中,用戶是可以去設(shè)置中取消授權(quán)的,而且是隨時都可以取消,所以很多運行時權(quán)限可能也得不到,目前官方的做法是,如果用戶取消該項授權(quán),那么依賴 該項授權(quán)的方法的返回值為null,所以你的app可能會報空指針異常。以后是否會針對22以下的app做改變還不得而知,畢竟crash是很難讓人接受 的,但是crash是由用戶造成的,用戶應(yīng)該也可以理解。

2、普通權(quán)限和運行時權(quán)限

系統(tǒng)權(quán)限會被傳遞給兩種不同的保護級別,我們所知道這兩種最重要的保護級別就是普通權(quán)限和運行時權(quán)限。

2.1 普通權(quán)限

普通權(quán)限的覆蓋區(qū)域是在你的app需要訪問沙盒以外的數(shù)據(jù)和資源的時候,但是對用戶隱私和其他app的操作只有很少的影響,比如開啟手電筒的權(quán)限。這個時候,系統(tǒng)會自動授權(quán)這些普通權(quán)限。

Normal Permissions:

ACCESS_LOCATION_EXTRA_COMMANDS

ACCESS_NETWORK_STATE

ACCESS_NOTIFICATION_POLICY

ACCESS_WIFI_STATE

BLUETOOTH

BLUETOOTH_ADMIN

BROADCAST_STICKY

CHANGE_NETWORK_STATE

CHANGE_WIFI_MULTICAST_STATE

CHANGE_WIFI_STATE

DISABLE_KEYGUARD

EXPAND_STATUS_BAR

GET_PACKAGE_SIZE

INSTALL_SHORTCUT

INTERNET

KILL_BACKGROUND_PROCESSES

MODIFY_AUDIO_SETTINGS

NFC

READ_SYNC_SETTINGS

READ_SYNC_STATS

RECEIVE_BOOT_COMPLETED

REORDER_TASKS

REQUEST_INSTALL_PACKAGES

SET_ALARM

SET_TIME_ZONE

SET_WALLPAPER

SET_WALLPAPER_HINTS

TRANSMIT_IR

UNINSTALL_SHORTCUT

USE_FINGERPRINT

VIBRATE

WAKE_LOCK

WRITE_SYNC_SETTINGS

2.2 運行時權(quán)限

運行時權(quán)限的覆蓋區(qū)域是你的app想要的數(shù)據(jù)和資源涉及用戶的隱私信息,或者是可能潛在的影響用戶的存儲數(shù)據(jù)或者其他app的操作。比如,請求獲取用戶聯(lián)系人信息的權(quán)限。如果一個app申明了運行時權(quán)限,用戶必須明確的授權(quán)這些權(quán)限給app。

2.3 權(quán)限組

所有的運行時權(quán)限都屬于對應(yīng)的權(quán)限組,如果你的app運行在android6.0及以上系統(tǒng),下面的規(guī)則都適用:

2.3.1?如果一個app在manifest中請求了一個運行時權(quán)限,而且app還沒有得到這個運行時權(quán)限所在的權(quán)限組中的任何一個運行時權(quán)限授權(quán),那么系統(tǒng)會彈出一個對話框,描述app想要訪問的運行時權(quán)限的權(quán)限組,這個對話框不會描述這個權(quán)限組中某一個特定的權(quán)限。比如,你的app想要請求READ_CONTACT權(quán)限,對話框只會描述app想要請求設(shè)備的聯(lián)系人,如果用戶授權(quán)通過,系統(tǒng)會授予app所請求的該項權(quán)限。

2.3.2?如果一個app在manifest中請求一個運行時權(quán)限,并且這個app已經(jīng)在相同的權(quán)限組中有了另一個運行時權(quán)限的授權(quán),那么系統(tǒng)不會彈出對話框,而是會立即授予app該項運行時權(quán)限的授權(quán)。比如,一個app之前請求過一個READ_CONTACT的權(quán)限并且被授權(quán)通過,之后又請求一個WRITE_CONTACT(在同一個權(quán)限組)權(quán)限,那么系統(tǒng)會自動授予該權(quán)限。

其實所有權(quán)限(普通權(quán)限、運行時權(quán)限、用戶自定義權(quán)限)都屬于特定的權(quán)限組,但是只有運行時權(quán)限的權(quán)限組才會影響用戶體驗。

2.3.3運行時權(quán)限組和權(quán)限組列表

group:android.permission-group.CONTACTS

permission:android.permission.WRITE_CONTACTS

permission:android.permission.GET_ACCOUNTS

permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE

permission:android.permission.READ_CALL_LOG

permission:android.permission.READ_PHONE_STATE

permission:android.permission.CALL_PHONE

permission:android.permission.WRITE_CALL_LOG

permission:android.permission.USE_SIP

permission:android.permission.PROCESS_OUTGOING_CALLS

permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR

permission:android.permission.READ_CALENDAR

permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA

permission:android.permission.CAMERA

group:android.permission-group.SENSORS

permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION

permission:android.permission.ACCESS_FINE_LOCATION

permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE

permission:android.permission.READ_EXTERNAL_STORAGE

permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE

permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS

permission:android.permission.READ_SMS

permission:android.permission.RECEIVE_WAP_PUSH

permission:android.permission.RECEIVE_MMS

permission:android.permission.RECEIVE_SMS

permission:android.permission.SEND_SMS

permission:android.permission.READ_CELL_BROADCASTS

可以通過adb shell pm list permissions -d -g進行查看。

看到上面的dangerous permissions,會發(fā)現(xiàn)一個問題,好像危險權(quán)限都是一組一組的,恩,沒錯,的確是這樣的,那么有個問題:分組對我們的權(quán)限機制有什么影響嗎?的確是有影響的,如果app運行在Android 6.x的機器上,對于授權(quán)機制是這樣的。如果你申請某個危險的權(quán)限,假設(shè)你的app早已被用戶授權(quán)了同一組的某個危險權(quán)限,那么系統(tǒng)會立即授權(quán),而不需要用戶去點擊授權(quán)。比如你的app對READ_CONTACTS已經(jīng)授權(quán)了,當(dāng)你的app申請WRITE_CONTACTS時,系統(tǒng)會直接授權(quán)通過。此外,對于申請時彈出的dialog上面的文本說明也是對整個權(quán)限組的說明,而不是單個權(quán)限(ps:這個dialog是不能進行定制的)。不過需要注意的是,不要對權(quán)限組過多的依賴,盡可能對每個危險權(quán)限都進行正常流程的申請,因為在后期的版本中這個權(quán)限組可能會產(chǎn)生變化。

3、相關(guān)API

3.1 在AndroidManifest文件中添加需要的權(quán)限。

這個步驟和我們之前的開發(fā)并沒有什么變化,試圖去申請一個沒有聲明的權(quán)限可能會導(dǎo)致程序崩潰。

3.2 檢查權(quán)限

if (ContextCompat.checkSelfPermission(thisActivity,

Manifest.permission.READ_CONTACTS)

!= PackageManager.PERMISSION_GRANTED) {

}else{

//

}

這里涉及到一個API,ContextCompat.checkSelfPermission,主要用于檢測某個權(quán)限是否已經(jīng)被授予,方法返回值為PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。當(dāng)返回DENIED就需要進行申請授權(quán)了

3.3 申請授權(quán)

ActivityCompat.requestPermissions(thisActivity,

new String[]{Manifest.permission.READ_CONTACTS},

MY_PERMISSIONS_REQUEST_READ_CONTACTS);

該方法是異步的,第一個參數(shù)是Context;第二個參數(shù)是需要申請的權(quán)限的字符串?dāng)?shù)組;第三個參數(shù)為requestCode,主要用于回調(diào)的時候檢測。可以從方法名requestPermissions以及第二個參數(shù)看出,是支持一次性申請多個權(quán)限的,系統(tǒng)會通過對話框逐一詢問用戶是否授權(quán)。

3.4 處理權(quán)限申請回調(diào)

@Override

publicvoidonRequestPermissionsResult(intrequestCode,

String permissions[],int[] grantResults) {

switch(requestCode) {

case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {

// If request is cancelled, the result arrays are empty.

if(grantResults.length >0&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {

// permission was granted, yay! Do the contacts-related task you need to do.

}else{

// permission denied, boo! Disable the functionality that depends on this permission.

}

return;

}

}

}

ok,對于權(quán)限的申請結(jié)果,首先驗證requestCode定位到你的申請,然后驗證grantResults對應(yīng)于申請的結(jié)果,這里的數(shù)組對應(yīng)于申請時的第二個權(quán)限字符串?dāng)?shù)組。如果你同時申請兩個權(quán)限,那么grantResults的length就為2,分別記錄你兩個權(quán)限的申請結(jié)果。如果申請成功,就可以做你的事情了!

那么將上述幾個步驟結(jié)合到一起就是:

// Here, thisActivity is the current activity

if (ContextCompat.checkSelfPermission(thisActivity,

Manifest.permission.READ_CONTACTS)

!= PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?

if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,

Manifest.permission.READ_CONTACTS)) {

// Show an expanation to the user *asynchronously* -- don't block

// this thread waiting for the user's response! After the user

// sees the explanation, try again to request the permission.

} else {

// No explanation needed, we can request the permission.

ActivityCompat.requestPermissions(thisActivity,

new String[]{Manifest.permission.READ_CONTACTS},

MY_PERMISSIONS_REQUEST_READ_CONTACTS);

// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an

// app-defined int constant. The callback method gets the

// result of the request.

}

}

謝幕,至此有關(guān)于android6.0 以上權(quán)限相關(guān)的內(nèi)容已經(jīng)詳細講完了!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容