Android6.0+运行时权限的处理
来源:互联网 发布:双色球杀红球算法 编辑:程序博客网 时间:2024/05/17 04:43
我的简书:简书
前言
目前Android8.0已经发布,我们都知道从Android6.0开始开发者需要处理运行时权限,所以还是要记录一下在6.0+的设备上如何处理运行时权限。
从 Android 6.0开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予。此方法可以简化应用安装过程,因为用户在安装或更新应用时不需要授予权限。它还让用户可以对应用的功能进行更多控制;例如,用户可以选择为相机应用提供相机访问权限,而不提供设备位置的访问权限。用户可以随时进入“设置”中对应用进行权限管理。
一、概述
1、系统权限的分类
系统权限分为两类:正常权限(Normal Permissions)和危险权限(Dangerous Permission):
正常权限涵盖应用需要访问其沙盒外部数据或资源,但对用户隐私或其他应用操作风险很小的区域。例如,设置时区的权限就是正常权限。只需要在Manifest中列出了正常权限,系统就会将自动授予该权限。
危险权限涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如,能够读取用户的联系人属于危险权限。如果在Manifest(android6.0+)中列出了危险权限,则用户必须明确批准此应用使用这些权限方可使用。
2、权限列表
- 正常权限(不需要运行时申请的权限)
ACCESS_LOCATION_EXTRA_COMMANDSACCESS_NETWORK_STATEACCESS_NOTIFICATION_POLICYACCESS_WIFI_STATEBLUETOOTHBLUETOOTH_ADMINBROADCAST_STICKYCHANGE_NETWORK_STATECHANGE_WIFI_MULTICAST_STATECHANGE_WIFI_STATEDISABLE_KEYGUARDEXPAND_STATUS_BARGET_PACKAGE_SIZEINSTALL_SHORTCUTINTERNETKILL_BACKGROUND_PROCESSESMODIFY_AUDIO_SETTINGSNFCREAD_SYNC_SETTINGSREAD_SYNC_STATSRECEIVE_BOOT_COMPLETEDREORDER_TASKSREQUEST_IGNORE_BATTERY_OPTIMIZATIONSREQUEST_INSTALL_PACKAGESSET_ALARMSET_TIME_ZONESET_WALLPAPERSET_WALLPAPER_HINTSTRANSMIT_IRUNINSTALL_SHORTCUTUSE_FINGERPRINTVIBRATEWAKE_LOCKWRITE_SYNC_SETTINGS
- 危险权限
2、WRITE_CALENDAR CAMERA(相机) 1、CAMERA CONTACTS(联系人) 1、READ_CONTACTS
2、WRITE_CONTACTS
3、GET_ACCOUNTS LOCATION(位置) 1、ACCESS_FINE_LOCATION
2、ACCESS_COARSE_LOCATION MICROPHONE(麦克风) 1、RECORD_AUDIO PHONE(手机) 1、READ_PHONE_STATE
2、CALL_PHONE
3、READ_CALL_LOG
4、WRITE_CALL_LOG
5、ADD_VOICEMAIL
6、USE_SIP
7、PROCESS_OUTGOING_CALLS SENSORS(传感器) 1、BODY_SENSORS SMS(短信) 1、SEND_SMS
2、RECEIVE_SMS
3、READ_SMS
4、RECEIVE_WAP_PUSH
5、RECEIVE_MMS STORAGE(存储卡) 1、READ_EXTERNAL_STORAGE
2、WRITE_EXTERNAL_STORAGE
二、使用
0、方法和变量说明
- Activity或Fragment用到的方法:
- 检查权限:int ContextCompat.checkSelfPermission(Context, String)
- 申请权限:ActivityCompat.requestPermissions(Context, String[], int)
- 权限申请回调:onRequestPermissionsResult(int, String[], String[])
- 权限解释说明:ActivityCompat.shouldShowRequestPermissionRationale()
- 用到的系统常量:
- 已授权:PackageManager.PERMISSION_GRANTED
- 未授权:PackageManager.PERMISSION_DENIED
1、检查权限checkSelfPermission()
如果APP中要使用危险权限,那么在使用之前一定要检查是否已经授权,如果应用具有此权限,方法将返回 PackageManager.PERMISSION_GRANTED,并且应用可以继续操作。如果应用不具有此权限,方法将返回 PERMISSION_DENIED,且应用必须明确向用户要求权限。
int permissionCheck = ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA);if (permissionCheck != PackageManager.PERMISSION_GRANTED) { Log.e(TAG, "已经授权"); } else { Log.e(TAG, "未授权"); }
2、申请权限requestPermissions()
如果APP未获取某项权限,那么需要调用该方法申请权限。手机系统会弹出一个对话框,让用户进行授权选择。
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
3、处理回调onRequestPermissionsResult()
通过对话框提示,用户选择“授权”或“拒绝”之后,将会执行此方法。
permissions[]:申请权限时的数组
grantResults[]: 授权结果的数组,与申请权限数组相对应。
通过这两个参数,我们可以判断哪些权限授权,哪些权限未授权,然后对用户做出相应的提示。
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.e(TAG, "授权成功" + permissions[0]); } else { Log.e(TAG, "授权失败"); } return; } } }
4、权限的解释说明shouldShowRequestPermissionRationale()
在某些情况下,我们需要对用户解释一下为什么使用该权限。例如,如果用户启动一个相机应用,用户对此应用要求使用相机的权限可能不会感到吃惊,但用户可能无法理解为什么此应用想要访问用户的位置或联系人。在请求权限之前,不妨为用户提供一个解释。
这个方法只在用户已拒绝某项权限请求时调用。如果用户继续尝试使用需要某项权限的功能,但继续拒绝权限请求,则可能表明用户不理解应用为什么需要此权限才能提供相关功能。对于这种情况,比较好的做法是显示解释。
注:如果用户在过去拒绝了权限请求,并在权限请求系统对话框中选择了 “禁用后不在提示”选项,此方法将返回 false。如果设备规范禁止应用具有该权限,此方法也会返回 false。
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { Log.e(TAG, "权限使用解释"); }
- 附上申请权限的示例代码:
private void permission() { //检查权限 int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA); if (permissionCheck != PackageManager.PERMISSION_GRANTED) { Log.e(TAG, "已经授权"); } else { Log.e(TAG, "未授权"); if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { Log.e(TAG, "权限使用解释"); } //申请权限 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); } } //申请权限回调 @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.e(TAG, "授权成功" + permissions[0]); } else { Log.e(TAG, "授权失败"); } return; } } }
三、简单封装
本封装方法是学习了郭霖的一次公开课,特此记录一下,嘿嘿~
1、编写APP的Activity管理类
2、定义权限接口
public interface OnPermissionListener { /** * 允许权限 */ void onGranted(); /** * 拒绝权限 */ void onDenied(List<String> deniedPermission);}
- 3、在BaseActivity统一对权限进行处理
只做了简单的封装,如果用户申请的权限中有一项未授权,则视为授权失败。
public class BaseAppcompatActivity extends AppCompatActivity { private static OnPermissionListener mOnPermissionListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AppManager.getInstance().addActivity(this); } /** * 申请运行时权限 * * @param permissions * @param listener */ public void requestRuntimePermission(String[] permissions, OnPermissionListener listener) { mOnPermissionListener = listener; List<String> permissionList = new ArrayList<>(); Activity activity = AppManager.getInstance().getTopActivity(); if (activity == null) { return; } for (String permission : permissions) { if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) { permissionList.add(permission); } } if (!permissionList.isEmpty()) { ActivityCompat.requestPermissions(activity, permissionList.toArray(new String[permissionList.size()]), 1); } else { mOnPermissionListener.onGranted(); } } protected void callbackOnClickNavigationAction(View view) { onBackPressed(); } /** * 申请权限回调 * * @param requestCode * @param permissions * @param grantResults */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case 1: if (grantResults.length > 0) { List<String> deniedPermissions = new ArrayList<>(); for (int i = 0; i < grantResults.length; i++) { int grantResult = grantResults[i]; String permission = permissions[i]; if (grantResult != PackageManager.PERMISSION_GRANTED) { deniedPermissions.add(permission); } } if (deniedPermissions.isEmpty()) { mOnPermissionListener.onGranted(); } else { mOnPermissionListener.onDenied(deniedPermissions); } } break; } }}
- 4、在子类中申请权限
requestRuntimePermission(new String[{ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, new OnPermissionListener() { @Override public void onGranted() { //授权成功 } @Override public void onDenied(List<String> deniedPermission) { //授权失败 } });
四、关于处理运行时权限的建议
应用如果一味要求用户提供授权,可能会让用户无所适从。如果用户发现应用难以使用,或者担心应用会滥用其信息,他们可能不愿意使用该应用,甚至会将其完全卸载。以下最佳做法有助于避免此类糟糕的用户体验。具体可以参考权限最佳做法。
1、考虑使用Intent,避免使用权限
2、仅授权应用使用到的权限
3、避免一次申请多项权限,让用户感到厌烦
4、解释需要权限的原因
五、参考阅读
Android6.0的行为变更
处理运行时权限
- Android6.0运行时权限的处理
- Android6.0+运行时权限的处理
- Android6.0运行时权限处理
- Android6.0运行时权限处理详解
- android6.0运行时权限处理简介
- Android6.0运行时权限处理
- Android6.0运行时权限处理透析
- 关于Android6.0运行时权限处理
- Android6.0运行时权限的处理及解决办法
- Android6.0运行时权限的处理及解决办法
- Android6.0运行时权限的封装
- Android6.0的运行时权限
- android6.0 运行时权限处理完全解析
- Android6.0运行时权限处理-超简单封装
- Android6.0运行时权限:处理定位和存储问题
- 再谈Android6.0 运行时权限(快速处理)
- Android6.0运行时权限处理架构搭建
- Android6.0 运行时权限
- PAT (Advanced) 1001. A+B Format (20)
- 灌水的一天
- windows核心编程之亲缘性
- 编译原理与编译构造 文法的优化1
- python Requests 初级
- Android6.0+运行时权限的处理
- 所谓的跨域(Cross-Origin),究竟是什么?——你所不知道浏览器跨域的小知识
- TCP,UDP,HTPP关系
- android Thread和Runable区别 精讲
- 轻院1077字符串加密
- MySQL中的慢查询日志(Slow Query Log)
- 重写对象equals和compareTo方法
- antd-admin 错误排查
- HTML学习之路03--超链接标签