android 6.0開始谷歌推行新的權(quán)限管理機制——動態(tài)權(quán)限管理,類似于ios上的權(quán)限申請,權(quán)限的獲取不再是在app安裝時進行,而是在運行時申請。
當然并不是所有的權(quán)限都需要動態(tài)申請,谷歌把權(quán)限劃分為兩大類,普通權(quán)限和危險權(quán)限。對于普通權(quán)限,還是和之前一樣在AndroidManifest.xml里申請就行,而對于危險權(quán)限,就必須在運行時動態(tài)申請,得到用戶的授權(quán)后才可使用。
下面羅列的是普通權(quán)限分類下的權(quán)限:
- 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
- UNINSTALL_SHORTCUT
可以看出普通權(quán)限都是和手機本身有關(guān)的功能,而用戶數(shù)據(jù)的權(quán)限(包括幾乎所有app都要申請的讀寫SD卡得權(quán)限)已被劃入危險權(quán)限中。
API23中新增了幾個與權(quán)限有關(guān)的接口
第一個是用于檢查權(quán)限的接口,該接口可以通過ContextCompat調(diào)用,也可以在當前的activity里直接調(diào)用。
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);
該接口的返回值代表權(quán)限查詢的結(jié)果,PackageManager.PERMISSION_GRANTED表示用戶已經(jīng)授權(quán),PackageManager.PERMISSION_DENIED表示用戶還沒有授權(quán),這是需要使用另一個接口進行權(quán)限申請。這個方法在使用時不需要再判斷系統(tǒng)版本了,因為方法內(nèi)部會區(qū)分版本,如果是API23以下會直接通過檢查manifest的方式進行。
public static void requestPermissions (Activity activity, String[]
permissions, int requestCode)
參數(shù)的第一個activity,也就是說權(quán)限的申請必須在UI線程去做,第二個參數(shù)是要申請的權(quán)限數(shù)組,第三個參數(shù)請求碼用于在回調(diào)時區(qū)分不同的權(quán)限申請(比如你可能在同一個activity的兩處申請了兩個不同的權(quán)限)。
通過實現(xiàn)接口
ActivityCompat.OnRequestPermissionsResultCallback中的
public abstract void onRequestPermissionsResult (int requestCode, String[]
permissions, int[] grantResults)
activity就能接收到請求申請結(jié)果。grantResults數(shù)組記錄了每個權(quán)限申請的結(jié)果。requestCode就是剛剛申請時的值。
即使為了安全,也不能不考慮用戶體驗,為了防止用戶被過多的打擾,API 23還提出了pemisssion_group權(quán)限組概念,即把權(quán)限分組,用戶只要授權(quán)了某個組里的某一個權(quán)限,那么該組的其他權(quán)限就不需要再次授權(quán)了。比如用戶已經(jīng)授權(quán)了READ_PHONE_STATE,那么下次再申請CALL_PHONE時就不會再彈窗讓用戶授權(quán)了。
| Permission Group | Permissions |
|---|---|
| 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 |
另一個API,ActivityCompat.shouldShowRequestPermissionRationale
public static boolean shouldShowRequestPermissionRationale (Activity
activity, String permission)
用來檢查是否之前用戶已經(jīng)拒絕過這個權(quán)限了,包括已經(jīng)勾選了不再提示的,這種情況下,可能需要進行提示,告訴用戶這個權(quán)限app用來做什么。
另外有兩個特殊的權(quán)限,SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS,這兩個權(quán)限的管理在系統(tǒng)應(yīng)用管理里,如果需要使用,需要通過intent方式啟動該管理頁面,用戶允許后方可使用,判斷是否有這兩個權(quán)限的方法分別是
Settings.canDrawOverlays(Context) //SYSTEM_ALERT_WINDOW
Settings.System.canWrite(Context) //WRITE_SETTINGS
另外可以再intent指定URI,這樣在啟動應(yīng)用管理UI后可以直接進入指定app的管理頁面,如下的方式。
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:com.app.my"));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
當然這些變化只有在app改變編譯時使用的sdk版本到23時才需要用到,如果編譯時sdk版本不是23,那么會以兼容方式運行,系統(tǒng)仍然會通過靜態(tài)方式進行權(quán)限檢查。