淺談Android 6.0之Runtime Permissions
前言
Android6.0發布后,其一系列新特新足夠讓我們這些Android程序員興奮一段時間了。首先我們先看看具體有哪些新特性:
-鎖頻下語音搜索
-指紋識別
-更完整的應用權限管理
-Doze電量管理
-Now on Tap
-App link
具體可以參考Android 6.0有哪些新特性。
上面六個新特性中更完整的應用權限管理
應該是和我們開發者關系最密切的了,接下來我們就來具體了解一下如何在Android 6.0上更好的使用Android系統權限。
Runtime Permissions
在Android 6.0中谷歌摒棄了之前的install time permissions model
取而代之的是runtime permissions model
。先來說說install time permissions model
,這個大家不陌生,就是當Android App安裝的時候會向用戶展示一坨權限,如果此時用戶選擇安裝,則表示用戶同意將這些權限賦予App,如果用戶不同意那么這個App就會取消安裝。runtime permissions model
就牛逼了,在App安裝的時候同樣會向用戶展示所需要的權限,并且在用戶選擇安裝App的時候并不表示用戶將這些權限賦予了App,而是需要App在運行階段主動去申請這些權限。這樣做的好處顯而易見,App對權限的申請對于用戶來說變得更加透明,而且用戶對App權限的控制也更加靈活。
權限的分類
Android將系統權限分成了四個保護等級normal
,dangerous
,signature
,signatureOrSystem
,其中最常見的是normal permission
和dangerous permission
兩類。
normal permission涵蓋的一系列權限的共同點是:App需要訪問App運行沙盒以外的數據或資源,但是這些資源對用戶的隱私或其他App的危險性較小,下面列舉一下這些權限:
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
FLASHLIGHT
GET_PACKAGE_SIZE
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
SET_ALARM
INSTALL_SHORTCUT
以上這些就是Android 6.0中所有的normal permissions
了。
dangerous permissions 涵蓋的一系列權限的共同點是:這些權限會讀寫用戶的隱私信息,也可能會讀寫用戶存儲的數據或影響其他App的正常運行。下面例舉出這些權限:
| 權限組| 權限|
|------------------|--------------------------------------------------------------------------------------------------------------|
|CALENDAR | READ_CALENDAR,WRITE_CALENDAR |
|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 | SEND_SMS,RECEIVE_SMS,READ_SMS,RECEIVE_WAP_PUSH,RECEIVE_MMS |
|STORAGE | READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE |
以上這些權限就是Android6.0中所有的dangerous permissions
。
Runtime Permissions針對的是dangerous permissions
,normal permissions
還是會在App安裝期間被默認賦予。
實戰
下面我們就以STORAGE
組中的WRITE_EXTERNAL_STORAGE
為例子,嘗試在Android 6.0中使用runtime permission
相關api。
我們要做的事情非常簡單,在手機的存儲設備上新建一個hello.txt。
1.在AndroidManifest文件中添加如下權限生命
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2.在MainActivity中添加如下方法:
//在sdcard上新建一個名為fileName的文件
private void createFile(String fileName){
File sdcard = Environment.getExternalStorageDirectory();
File newFile = new File(sdcard,"/" + fileName) ;
if(!newFile.exists()){
try {
newFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
好的,如果沒有runtime permissions
這個概念的話,那其實這個功能已經完成了,我們來看看它在Android 6.0之前的版本上的運行情況,
首先是安裝時的界面:
它提示用戶該應用會修改會刪除SD卡的內容,如果此時用戶選擇安裝,那么也就是默認將WRITE_EXTERNAL_STORAGE
這個權限賦予了該應用。
再來看運行結果:
看吧,文件直接就創建成功了,這樣真的是很危險的。
接下來再在Android6.0的機子上安裝這個應用,安裝截圖如下:
這個安裝界面和之前的一樣,也是向用戶展示了App所涉及的權限。
下面看運行結果:
這里就出問題了,log顯示App沒有權限在SD卡上創建文件。這里要再講一下runtime permissions
原理
對于權限分類中的
dangerous permissions
,runtime permissions要求App在運行的時候做權限請求,某則App則無法獲得相應請求。
接下來看一下怎么在代碼中進行權限的申請:
public static final int EXTERNAL_STORAGE_REQ_CODE = 10 ;
public void requestPermission(){
//判斷當前Activity是否已經獲得了該權限
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//如果App的權限申請曾經被用戶拒絕過,就需要在這里跟用戶做出解釋
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this,"please give me the permission",Toast.LENGTH_SHORT).show();
} else {
//進行權限請求
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
EXTERNAL_STORAGE_REQ_CODE);
}
}
}</code></pre>
當進行權限申請,并且用戶做出選擇后會回調onRequestPermissionsResult這個方法,在這個方法中做相關處理
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case EXTERNAL_STORAGE_REQ_CODE: {
// 如果請求被拒絕,那么通常grantResults數組為空
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//申請成功,進行相應操作
createFile("hello.txt");
} else {
//申請失敗,可以繼續向用戶解釋。
}
return;
}
}
}
到這里runtime permissions
的權限申請操作就結束了,我們看一下效果:

允許后會再次調用createFile("hello.txt")方法,這次文件會被成功創建。

總結
其實還有一些內容需要寫,這里先//TODO一下,希望以上內容對你有所幫助。