前言
谷歌在2015年8月份時候,發(fā)布了Android 6.0版本,代號叫做“棉花糖”(Marshmallow ),其中的很大的一部分變化跳夭,是在用戶權(quán)限授權(quán)上,或許是感覺之前默認授權(quán)的不合理们镜,現(xiàn)在6.0出來币叹,使得用戶權(quán)限授權(quán)變得合理。這可能也是參考IOS系統(tǒng)的模狭,只有在用戶需要使用權(quán)限的時候颈抚,才去授權(quán)請求,這樣做的目的是提高用戶體驗嚼鹉,當然贩汉,用戶感覺好了,受苦的是我們開發(fā)人員锚赤,原來的規(guī)則不適用了匹舞,現(xiàn)在我們?nèi)ミm應新的規(guī)則,畢竟是靠谷歌這顆大樹吃飯的嘛线脚。
原來權(quán)限模型
在Android 6.0版本之前赐稽,權(quán)限都是一條龍服務的,只要用戶安裝完浑侥,
AndroidManifest清單上申請的權(quán)限都會被系統(tǒng)默認授權(quán)姊舵,并且授權(quán)后也撤銷不了。這樣的弊端在哪里呢寓落?有些權(quán)限可能用戶覺得不需要括丁,比如他不想有通知的權(quán)限,不想受到通知的干擾伶选,那么他就不能屏蔽通知史飞,就是不需要的權(quán)限,他去不掉考蕾,自主權(quán)不在他那邊祸憋。還有一些情況是,一些惡意程序肖卧,會利用這個權(quán)限默認授權(quán)蚯窥,進行惡意獲取用戶數(shù)據(jù)和攻擊。所以Android 6.0版本,一方面讓用戶更加容易的控制自己的隱私拦赠,一方面需要重新適配應用權(quán)限巍沙。
Android 6.0權(quán)限模型
采用新的權(quán)限模型,只有在需要權(quán)限的時候荷鼠,才告知用戶是否授權(quán)句携,是在runtime時候授權(quán),而不是在原來安裝的時候 允乐,
同時默認情況下每次在運行時打開頁面時候矮嫉,需要先檢查是否有所需要的權(quán)限申請。這樣的用戶的自主性提高很多牍疏,比如用戶可以給APP賦予攝像的權(quán)限蠢笋,但是可以拒絕記錄設(shè)備位置的權(quán)限,就是怕位置信息上傳等等鳞陨。
權(quán)限流程
在API 23中昨寞,權(quán)限滿足的標準流程:
系統(tǒng)授權(quán)彈窗流程
但這里有個問題,那就是在系統(tǒng)授權(quán)彈窗環(huán)節(jié)厦滤,提醒框會有個不再提示的復選框援岩,如果用戶點擊不太提示,并拒絕授權(quán)掏导,那么再下次授權(quán)的時候享怀,系統(tǒng)授權(quán)彈窗的提示框就不會在提示,所以我們很有必要需要自定義權(quán)限彈窗提示框趟咆,那么流程圖就變成如下了凹蜈。
自定義權(quán)限彈窗流程
權(quán)限類型
在圖中,我們可以看到整個權(quán)限里忍啸,可以分為系統(tǒng)權(quán)限和特殊權(quán)限授權(quán)。
系統(tǒng)權(quán)限中履植,又分為normal和dangerous類型计雌。
- normal:這個權(quán)限類型并不直接威脅到用戶的隱私,可以直接在manifest清單里注冊玫霎,系統(tǒng)會幫我們默認授權(quán)的凿滤。
- dangerous:這個可以直接給app訪問用戶一些敏感的數(shù)據(jù),不僅需要在manifest清單里注冊庶近,同時在使用的時候翁脆,需要向系統(tǒng)請求授權(quán)。
- 值得注意一點鼻种,這里有特殊權(quán)限授權(quán)的區(qū)別反番,分別是
SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS,雖然這兩個權(quán)限也是屬于dangerous權(quán)限類型,但是這兩個授權(quán)請求方式和其他dangerous權(quán)限是不一樣的罢缸,需要特殊處理 篙贸。
normal列表:
- 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
- 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
dangerous列表:
- READ_CALENDAR
- WRITE_CALENDAR
- CAMERA
- CONTACTS
- READ_CONTACTS
- WRITE_CONTACTS
- GET_ACCOUNTS
- ACCESS_FINE_LOCATION
- ACCESS_COARSE_LOCATION
- RECORD_AUDIO
- READ_PHONE_STATE
- CALL_PHONE
- READ_CALL_LOG
- WRITE_CALL_LOG
- ADD_VOICEMAIL
- USE_SIP
- PROCESS_OUTGOING_CALLS
- BODY_SENSORS
- SEND_SMS
- RECEIVE_SMS
- READ_SMS
- RECEIVE_WAP_PUSH
- RECEIVE_MMS
- READ_EXTERNAL_STORAGE
- WRITE_EXTERNAL_STORAGE
版本兼容
- 當然,谷歌也是考慮到如果是以API 23之前的版本編譯的APP枫疆,在6.0的系統(tǒng)上運行爵川,還是能兼容的。如果是23之前的版本編譯的APP息楔,則權(quán)限模型走的是老的模式寝贡,也就是在一條龍的模式,在manifest清單注冊值依,系統(tǒng)會幫我們默認授權(quán)圃泡,并且也能運行。
- 但如果是以API 23的版本編譯的APP鳞滨,那走的的必須是新的權(quán)限模型洞焙,在遇到dangerous權(quán)限的時候,必須進行授權(quán)的拯啦,如果沒有進行授權(quán)話澡匪,系統(tǒng)則會提示崩潰信息。所以褒链,基于6.0系統(tǒng)的開發(fā)的程序唁情, 在打開頁面的時候,必須要考慮這個頁面是否用到需要授權(quán)的權(quán)限甫匹,頁面檢測是否已經(jīng)授權(quán)過了沒甸鸟。
實現(xiàn)方式
第一步:檢測權(quán)限
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(this Activity, Manifest.permission.WRITE_CALENDAR);
第二步:請求權(quán)限
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(this Activity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this Activity, 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.
}
}
第三步:處理權(quán)限請求結(jié)果
@Override
public void onRequestPermissionsResult(int requestCode,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;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
其中要特別注意的是,如果是針對android.permission.SYSTEM_ALERT_WINDOW
android.permission.WRITE_SETTINGS,這兩個權(quán)限兵迅,實現(xiàn)方式跟上面三步驟是不一樣的抢韭,需要另外特殊處理。
- 針對SYSTEM_ALERT_WINDOW權(quán)限恍箭,需要向系統(tǒng)發(fā)送一個ACTION_MANAGE_OVERLAY_PERMISSION這樣一個動作刻恭,同時可以用Settings.canDrawOverlays() 方法進行判斷之前是否已經(jīng)授權(quán)過了。
- 針對WRITE_SETTINGS權(quán)限扯夭,需要向系統(tǒng)發(fā)送一個
ACTION_MANAGE_WRITE_SETTINGS這樣一個動作鳍贾,同時可以用Settings.System.canWrite()方法進行判斷之前是否已經(jīng)授權(quán)過了。
具體代碼:
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
注意點
之前在工作中交洗,碰到一種情況骑科,如果是運行在6.0的版本上是需要走新的權(quán)限模型,如果是運行在老的版本上构拳,則需要進行一個判斷咆爽,此時碰到一個問題是梁棠,在谷歌官方推薦中,在判斷app運行的系統(tǒng)是否在Android M上時伍掀,它的判斷是如下: Build.VERSION.CODENAME.equals("MNC"); 可是在我實際適配中掰茶,發(fā)現(xiàn)這句卻無效的,就改用Build.VERSION.SDK_INT >= 23蜜笤。
總結(jié)
- 首先要知道6.0版本權(quán)限模型跟原來版本是不同的濒蒋,不再是統(tǒng)一在manifest中默認系統(tǒng)授權(quán),而是有需要的時候把兔,向系統(tǒng)請求授權(quán)沪伙,提高用戶體驗。
- 了解權(quán)限檢測流程县好,一點注意點是如果系統(tǒng)權(quán)限彈窗提示框被不再提醒了围橡,需要我們自定義提示彈窗,引導用戶去授權(quán)缕贡。
- 明白權(quán)限類型翁授,分為normal和dangerous類型,同時晾咪,在dangerous中還需要注意一點收擦,SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS這兩個特殊授權(quán)請求方式,跟一般授權(quán)請求方式不同谍倦。
- 在判斷APP是否運行在Android M上塞赂,可以用版本號來判斷,可以準確點昼蛀。
參考
有個具體demo:https://github.com/SpikeKing/wcl-permission-demo
流程圖:http://blog.csdn.net/caroline_wendy/article/details/50587230