Android的单个或多个权限动态申请

前言

在Android 6.0(API 级别 23)以下申请权限是非常简单的,直接在AndroidManifest.xml这个配置文件中加入申请权限的列表就可以了,比如我要申请四个权限,如下:

<!--打电话-->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!--使用相机-->
<uses-permission android:name="android.permission.CAMERA" />
<!--写入内存卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--读取内存卡-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

但是在Android 6.0(API 级别 23)以上的版就不可以这样申请了,因为这样申请权限对用户来说是非常危险的,应用已安装就获取了全部权限,也不知道这些权限应用要来干什么,可能是用户不希望发生的一些操作。所以在Android 6.0之后,一些危险的权限就要动态申请了,哪些是危险权限呢,下面是官方提供的一个需要动态申请的危险权限:

权限组

权限

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

如果要使用上面的权限,除了要在AndroidManifest.xml这个配置文件声明,还要在Java代码中增加动态申请。下面我们就介绍如何单个和多个权限动态申请。

单个权限的动态申请

比如我们的应用要打电话,打电话是一个危险权限.

  • 首先需要动态申请AndroidManifest.xml配置文件添加申请打电话权限的声明,如下:
<!--打电话-->
<uses-permission android:name="android.permission.CALL_PHONE" />
  • 然后在Java代码中编写一个动态申请打电话权限的方法,当我们需要打电话之前,先要调用这个方法获取权限:
// 请求单个权限
private void request_permission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
            != PackageManager.PERMISSION_GRANTED) {
        // 最后的请求码是对应回调方法的请求码
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.CALL_PHONE}, 1001);
    } else {
        Toast.makeText(this, "你已经有权限了,可以直接拨打电话", Toast.LENGTH_LONG).show();
    }
}
  • 请求申请权限之后,当用户同意或者拒绝权限之后,都会在请求权限的回调方法反馈,我们可以在这个回调方法中判断是否已经授权,并做相关的操作:
// 请求权限回调方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case 1001:
            // 1001的请求码对应的是申请打电话的权限
            // 判断是否同意授权,PERMISSION_GRANTED 这个值代表的是已经获取了权限
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(MainActivity.this, "你同意授权,可以打电话了", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(MainActivity.this, "你不同意授权,不可以打电话", Toast.LENGTH_LONG).show();
            }
            break;
    }
}
  • 我们增加一个按钮,让这个按钮的点击事件调用我们的申请权限方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button request_permission_btn = (Button) findViewById(R.id.request_permission_btn);

    // 点击获取单个权限
    request_permission_btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            request_permission();
        }
    });
}
  • activity_main中的界面代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.yeyupiaoling.testpermission.MainActivity">

    <Button
        android:id="@+id/request_permission_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请求单个权限" />
</LinearLayout>
  • 测试我们的程序,第二个按钮时下一部分的,读者目前可以不用理会。第一次申请的时候是没有权限的,然后就会动态申请权限,用户同意了就获得了权限。第二次申请权限时,因为第一次已经申请到了,所以可以直接使用了。

多个权限动态申请

  • 多个权限申请也是一样的,首先同样需要动态申请AndroidManifest.xml配置文件添加所有申请的权利,如下。值得注意的是WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE都是属于STORAGE组的,在申请它们两个的时候吗,只要同意一个,系统会立即另外一个权限,不会再弹出权限授予询问的对话框。
<!--使用相机-->
<uses-permission android:name="android.permission.CAMERA" />
<!--写入内存卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--读取内存卡-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  • 多个权限的申请就复杂一些,首先要先创建一个列表,把需要的申请的权限添加到这个列表中,最后统一提交申请:
// 请求多个权限
private void request_permissions() {
    // 创建一个权限列表,把需要使用而没用授权的的权限存放在这里
    List<String> permissionList = new ArrayList<>();

    // 判断权限是否已经授予,没有就把该权限添加到列表中
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        permissionList.add(Manifest.permission.CAMERA);
    }

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
    }

    // 如果列表为空,就是全部权限都获取了,不用再次获取了。不为空就去申请权限
    if (!permissionList.isEmpty()) {
        ActivityCompat.requestPermissions(this,
                permissionList.toArray(new String[permissionList.size()]), 1002);
    } else {
        Toast.makeText(this, "多个权限你都有了,不用再次申请", Toast.LENGTH_LONG).show();
    }
}
  • 申请多个权限,在回调方法中也会反馈多个权限的申请结果,所以我们要判断每个权限的申请结果,全部的权限都申请成功了,那才是申请成功了:
// 请求权限回调方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case 1002:
            // 1002请求码对应的是申请多个权限
            if (grantResults.length > 0) {
                // 因为是多个权限,所以需要一个循环获取每个权限的获取情况
                for (int i = 0; i < grantResults.length; i++) {
                    // PERMISSION_DENIED 这个值代表是没有授权,我们可以把被拒绝授权的权限显示出来
                    if (grantResults[i] == PackageManager.PERMISSION_DENIED){
                        Toast.makeText(MainActivity.this, permissions[i] + "权限被拒绝了", Toast.LENGTH_SHORT).show();
                    }
                }
            }
            break;
    }
}
  • 我们同样增加一个按钮,让这个按钮的点击事件调用我们的申请多个权限方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button request_permissions_btn = (Button) findViewById(R.id.request_permissions_btn);

    // 点击获取多个权限
    request_permissions_btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            request_permissions();
        }
    });
}
  • activity_main中的界面代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.yeyupiaoling.testpermission.MainActivity">

    <Button
        android:id="@+id/request_permissions_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请求多个权限" />
</LinearLayout>
  • 效果展示,当我们点击按钮申请多个权限时,就会开始申请多个权限。如上面所说的读取内存卡和写入内存卡属于一个组,所以我们在看到关于内存卡的只是申请一次,如果一个拒绝了,那就全部都拒绝了。

参考资料

  1. https://developer.android.com/guide/topics/security/permissions#normal-dangerous

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券