这一篇是运行时权限申请的基础篇,关于国内版本的适配,请看这一篇 Android 6.0 运行时权限管理最佳实践。
在Android6.0之前,应用程序开发时在清单文件中声明需要的权限就可以了,用户只有同意这些权限才可以安装app,为了安装app,就不得不忍受一些不必要的权限。在Android6.0(棉花糖)之后,可以在设置界面查看每个应用程序的全新,以及对单个权限进行授权或者解除授权。
新的权限机制保护了用户的隐私,新的权限机制将权限分为了两种,,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。
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
Dangerous Permissions:
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进行查看。
对于Normal Permissions的权限,还是直接在清单文件中授权,
而对于Dangerous Permissions:需要一个一个询问用户授权,而且这些权限需要开发者自己调用弹出请求权限
注意:如果用户拒绝,对可能产生的异常进行处理。
同时zhuyi上面都是分组的,在权限授权时,也是每次授权一组的权限,例如你的APP对android.permission-group.SMS已经授权,那么当你授权android.permission.READ_SMS时,系统默认直接通过。也就是其他的都已经授权了。
注意:不要对权限组过多的依赖,尽可能对每个危险权限都进行正常流程的申请,因为在后期的版本中这个权限组可能会产生变化。
Dangerous Permissions权限获取
1.在AndroidManifest文件中添加需要的权限
2.检测权限
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
}else{
//
}
ContextCompat.checkSelfPermission,主要用于检测某个权限是否已经被授予,方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。当返回GRANTED就需要进行申请授权了。
3.申请权限
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
requestCode);
该方法是异步的,第一个参数是Context;第二个参数是需要申请的权限的字符串数组;第三个参数为requestCode,主要用于回调的时候检测。可以从方法名requestPermissions以及第二个参数看出,是支持一次性申请多个权限的,系统会通过对话框逐一询问用户是否授权。
4.处理权限申请回调
@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;
}
}
}
在用户已经拒绝一次了,你弹出授权框,你需要给用户一个解释,为什么要授权,则使用该方法,使用下面的Api。注意,方法只有在用户在上一次已经拒绝过你的这个权限申请。
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.
}
// 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.
}
}
“`
在实际使用中,我发现一个有趣的事情,就是在用户点击不再询问后并且拒绝权限后,可以在回调方法中判断!this.shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)来提醒用户必要的而且拒绝过的权限
转载自http://blog.csdn.net/lmj623565791/article/details/50709663; 张鸿洋的博客,进行部分改动,已经封装好的库以及源码,具体查看张鸿洋大神的博客