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_STORAGE
和READ_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>
- 效果展示,当我们点击按钮申请多个权限时,就会开始申请多个权限。如上面所说的读取内存卡和写入内存卡属于一个组,所以我们在看到关于内存卡的只是申请一次,如果一个拒绝了,那就全部都拒绝了。