目录
权限分类
动态权限核心函数
简易实现案例
完整代码
Google 在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限和危险权限。App 每次在使用危险权限时需要动态的申请并得到用户的授权才能使用。
权限分类
系统权限分为两类:正常权限和危险权限。
正常权限:不会直接给用户隐私带来危险。如果你在其清单中列出了正常权限,系统将自动授予该权限。
危险权限:授予应用访问用户机密数据的权限。如果你在清单文件中列出了危险权限,则用户必须明确批准你的应用使用这些权限。那么危险权限有那些?日历(CALENDAR)、相机(CAMERA) 、通讯录(CONTACTS)、位置(LOCATION)、拨号(PHONE)、短信(SMS)和存储(STORAGE)等。
<!-- 权限组:CALENDAR == 日历读取的权限申请 -->
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<!-- 权限组:CAMERA == 相机打开的权限申请 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 权限组:CONTACTS == 联系人通讯录信息获取/写入的权限申请 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<!-- 权限组:LOCATION == 位置相关的权限申请 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 权限组:PHONE == 拨号相关的权限申请 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 权限组:SMS == 短信相关的权限申请 -->
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<!-- 权限组:STORAGE == 读取存储相关的权限申请 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
申请以上权限时,除了要在清单文件中添加权限,还需要通过代码动态申请。
动态权限核心函数
1. 检测权限
checkSelfPermission(@NonNull String permission)
2. 申请权限
requestPermissions(@NonNull String[] permissions, int requestCode)
3. 处理结果回调
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
4. 是否需要显示 UI 界面提示用户为什么需要这个权限
shouldShowRequestPermissionRationale(@NonNull String permission)
简易实现案例
步骤1:在 AndroidManifest.xml 添加要申请的权限。这里以存储权限为例
<!-- STORAGE == 读取存储相关权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
步骤2:封装一个 requestPermission 方法来动态检测和申请权限
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();
}
requestPermission() 函数里会先检测存储权限,如果没开启则动态申请存储权限。
private void requestPermission() {
// checkSelfPermission() 检测权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//TODO 申请存储权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
PERMISSION_REQUEST_CODE);
}
}
注意:这个 demo 里只申请了一个权限,当我们需要申请多个权限时,可以往requestPermissions 里的第二个参数添加其它需要的权限,因为它本就是一个 String 数组,且也要在 AndroidManifest里添加。
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE
,Manifest.permission.CAMERA}
步骤3:处理用户选择的结果(“允许” / “拒绝”),重写 onRequestPermissionsResult()方法。
//TODO 处理权限结果回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE) {
//用户点击了“确定” == grantResults[0] == PackageManager.PERMISSION_GRANTED)
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i("TAG", "onRequestPermissionsResult granted");
} else {
Log.i("TAG", "onRequestPermissionsResult denied");
// TODO 用户拒绝权限申请,则弹出警示框
showWaringDialog();
}
}
}
步骤4:当用户拒绝权限,则弹出警示框,并在用户点击“确定”后直接退出页面。因为没有存储权限肯定不能使用该应用的。
/**
* 用户拒绝权限的警示
*/
private void showWaringDialog() {
new AlertDialog.Builder(this)
.setTitle("警告!")
.setMessage("请前往设置->应用->权限管理->打开存储权限,否则无法正常使用!")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//TODO 一般情况下如果用户不授权的话,功能时无法运行的,则直接退出
finish();
}
}).show();
}
完整代码
MainActivity.java
package com.example.dynamicauthority;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_CODE = 999;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermission();
}
private void requestPermission() {
// checkSelfPermission() 检测权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//TODO 申请存储权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
PERMISSION_REQUEST_CODE);
}
}
//TODO 处理权限结果回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE) {
//用户点击了“确定” == grantResults[0] == PackageManager.PERMISSION_GRANTED)
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i("TAG", "onRequestPermissionsResult granted");
} else {
Log.i("TAG", "onRequestPermissionsResult denied");
// TODO 用户拒绝权限申请,则弹出警示框
showWaringDialog();
}
}
}
/**
* 用户拒绝权限的警示
*/
private void showWaringDialog() {
new AlertDialog.Builder(this)
.setTitle("警告!")
.setMessage("请前往设置->应用->权限管理->打开存储权限,否则无法正常使用!")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//TODO 一般情况下如果用户不授权的话,功能时无法运行的,则直接退出
finish();
}
}).show();
}
}