Android 6.0开始,对敏感权限需要动态申请,首先我们需要引入android.support.v4的兼容包,然后使用ActivityCompat这个类来处理权限。

比如最常用的

ActivityCompat.checkSelfPermission(...)ActivityCompat.requestPermissions(...)ActivityCompat.shouldShowRequestPermissionRationale(...)

第一个是检查某个权限是否授权
第二个是申请权限
第三个是判断是否需要合理显示授权对话框。具体含义参考文末。

Activity也有这些方法,为什么要使用ActivityCompat来检查权限和申请权限?

有两个原因
第一,如果应用的minSdkVersion小于23,那么IDE会提示你这些方法在6.0以下不存在,编译会不通过。
第二,ActivityCompat处理了一些兼容性判断,比如requestPermissions的实现里加了判断api 23。

Android 23以下如何检查权限呢?

一种方法是使用ActivityCompat或ContextCompat,调用checkSelfPermission方法。
另一种方法使用Activity提供的方法:checkPermission(String permission, int pid, int uid),需要传入当前进程id和uid。

checkSelfPermission方法其实也是调用checkPermission(String permission, int pid, int uid)。

动态权限示例代码:

package com.devnn.testdemo;import android.Manifest;import android.app.Activity;import android.content.pm.PackageManager;import android.os.Bundle;import android.support.annotation.NonNull;import android.support.v4.app.ActivityCompat;import android.widget.Toast;public class MainActivity extends Activity {    String permission = Manifest.permission.READ_EXTERNAL_STORAGE;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {            ActivityCompat.requestPermissions(this, new String[]{permission}, 100);        }else{            Toast.makeText(this, "已有读SDK卡权限", Toast.LENGTH_SHORT).show();        }    }    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        if(requestCode==100){            if(grantResults[0]==PackageManager.PERMISSION_GRANTED){                Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();            }else if(ActivityCompat.shouldShowRequestPermissionRationale(this,permission)==false){                Toast.makeText(this, "拒绝并勾选了不再提醒,不会弹了,需要引导用户去设置页", Toast.LENGTH_SHORT).show();            }else{                Toast.makeText(this, "拒绝了授权,下次还会再弹", Toast.LENGTH_SHORT).show();            }        }    }}

记得先要在AndroidManifest.xml里声明权限。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

在弹出系统的权限对话框前,弹出自已的对话框,用来说明权限用途,会更加友好一点。直接使用Materia风格的Dialog。

    public void showPermissionDialog() {        AlertDialog.Builder builder = new AlertDialog.Builder(this, android.R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth);        builder.setMessage("需要读SD卡权限,用来获取照片\n需要获取手机状态权限,用来获取设备号\n需要获取联系人权限,用来...");        builder.setTitle("权限说明");        builder.setCancelable(true);        builder.setPositiveButton("申请", new DialogInterface.OnClickListener() {            @Override            public void onClick(DialogInterface dialog, int which) {                ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, 100);            }        });        builder.show();    }

对话框效果:
关于Android动态权限的一些疑问_第1张图片

只有危险权限(或叫敏感权限)才需要申请,而且危险权限组中的某一个权限授权了,组内其它权限也被同时授权。

危险权限组:
关于Android动态权限的一些疑问_第2张图片

关于 ActivityCompat.shouldShowRequestPermissionRationale(...)方法的含义,有必要说明。从字面意思理解,即是否需要合理显示申请权限对话框,那么什么时候显示才是合理的呢?我们发现以下规律。

在第一次申请权限时,它返回了false
用户选择拒绝并没有勾选不再提醒时,它返回true
而用户选择拒绝并勾选不再提醒(永久拒绝),它返回了false

因此这个方法并不能用来判断是否需要显示自已的权限说明对话框。它只能在权限回调里用来判断是否要引导用户到设置页打开权限。

更多相关文章

  1. Android非UI线程访问UI线程的方法总结
  2. android 9.0 SD卡权限问题 文件管理器没有权限
  3. 查看基于Android 系统单个进程内存、CPU使用情况的几种方法
  4. 对话框式activity
  5. android 调试方法
  6. 整理android环境离线安装搭建方法——支持android 2.3.3和androi
  7. Android电话拨号器实现方法

随机推荐

  1. Android(安卓)学习笔记(二七):Menu
  2. 从iOS角度思考Android
  3. Android(安卓)RxJava:详解 条件 / 布尔操
  4. 如何编写高效的Android代码
  5. 浅析Android(安卓)View(一)
  6. Glide详细了解优缺点
  7. DynamicAPK基本概念
  8. Android手机开发总结
  9. Java内部类精炼详解—由Android点击事件
  10. 关于android UI布局自适应