一、运行时动态申请权限
1、Android系统为了防止某些App滥用权限,从6.0开始引入了运行时权限管理机制,允许App在运行过程中动态检查是否拥有某些权限,一旦发现缺少某种必需的权限,则系统会自动弹出小窗提示用户去开启该权限

二、动态申请权限的步骤
1、检查App是否开启了指定权限
调用ContextCompat的checkSelfPermission方法
public static int checkSelfPermission(@NonNull Context context, @NonNull String permission)
说明:
(1)context:传所在的Activity
(2)permission:权限
2、请求系统弹窗,以便用户选择是否开启权限
调用ActivityCompat的requestPermissions方法,即可命令系统自动弹出权限申请窗口
public static void requestPermissions(final @NonNull Activity activity, final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode)
说明:
(1)activity:传所在的Activity
(2)permissions:权限数组
(3)requestCode:标识符,表示请求的是什么类型的权限
3、判断用户的权限选择结果
重写Activity页面的权限请求回调方法onRequestPermissionsResult,在该方法内部处理用户的权限选择结果
public void onRequestPermissionsResult(requestCode, permissions, grantResults)
说明:
(1)requestCode:申请权限的时候,传递进去,回调方法使用这个来进行判断
(2)permissions:权限的数组列表(读、写)
(3)grantResults:用户操作后返回的授权结果
4、在清单文件里定义权限
老版本只要在清单文件里定义就好了,新版本不仅要在清单文件里定义,还需要动态去申请权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
三、运行时动态申请权限-懒汉模式
1、懒汉模式,就是点击按钮时申请权限
2、例子
PermissionLazyActivity.java
java
package com.example.chapter07_client;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import com.example.chapter07_client.util.PermissionUtil;
import com.example.chapter07_client.util.ToastUtil;
/**
* 懒汉式
*/
public class PermissionLazyActivity extends AppCompatActivity implements View.OnClickListener {
// 读写通讯录权限
private static final String[] PERMISSIONS_CONTACTS = new String[] {
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS
};
// 读写短信的权限
private static final String[] PERMISSIONS_SMS = new String[] {
Manifest.permission.READ_SMS,
Manifest.permission.SEND_SMS
};
// 标识符,表示请求的是什么类型的权限(通讯录、短信等)
private static final int REQUEST_CODE_CONTACTS = 1;
private static final int REQUEST_CODE_SMS = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_permission_lazy);
findViewById(R.id.btn_contact).setOnClickListener(this);
findViewById(R.id.btn_sms).setOnClickListener(this);
}
@Override
public void onClick(View view) {
boolean result;
if (view.getId() == R.id.btn_contact) {
// 点击按钮后,首先检查有没有权限
result = PermissionUtil.checkPermission(this, PERMISSIONS_CONTACTS, REQUEST_CODE_CONTACTS);
if (result) {
ToastUtil.show(this, "通讯录权限已获取");
}
} else if (view.getId() == R.id.btn_sms) {
result = PermissionUtil.checkPermission(this, PERMISSIONS_SMS, REQUEST_CODE_SMS);
if (result) {
ToastUtil.show(this, "收发短信权限已获取");
}
}
}
/**
*
* @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 REQUEST_CODE_CONTACTS:
// 在这里弹窗用户操作
if (PermissionUtil.checkGrant(grantResults)) {
Log.d("sam", "通讯录权限获取成功");
} else {
ToastUtil.show(this, "获取通讯录读写权限失败");
jumpToSettings();
}
break;
case REQUEST_CODE_SMS:
if (PermissionUtil.checkGrant(grantResults)) {
Log.d("sam", "收发短信权限获取成功");
} else {
ToastUtil.show(this, "获取收发短信权限失败");
jumpToSettings();
}
break;
}
}
/**
* 拒绝多了,就不会弹窗了
* 所以跳转到应用设置界面,让用户手工设置
*/
private void jumpToSettings() {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", getPackageName(), null));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
工具类PermissionUtil.java
java
package com.example.chapter07_client.util;
import android.app.Activity;
import android.content.pm.PackageManager;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class PermissionUtil {
// 检查多个权限,返回true表示已完全启用权限,返回false表示未完全启用权限
public static boolean checkPermission(Activity act, String[] permissions, int requestCode) {
int check = PackageManager.PERMISSION_GRANTED; // 默认的是已经授权了
for (String permission : permissions) {
check = ContextCompat.checkSelfPermission(act, permission);
if (check != PackageManager.PERMISSION_GRANTED) {
break; // 如果权限组里只要有一个没有授权,退出循环
}
}
// 未开启该权限,则请求系统弹窗,让用户选择是否立即开启权限
if (check != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(act, permissions, requestCode);
return false;
}
return true;
}
// 检查权限结果数组,返回true表示都已经获得授权,返回false表示至少有一个未获得授权
public static boolean checkGrant(int[] grantResults) {
// 遍历权限结果数组中的每条选择结果
for (int grant : grantResults) {
if (grant != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
}
布局文件activity_permission_lazy.xml
XML
<?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=".PermissionLazyActivity">
<Button
android:id="@+id/btn_contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="读写通讯录"/>
<Button
android:id="@+id/btn_sms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="收发短信"/>
</LinearLayout>
清单文件
XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<package android:name="com.example.chapter07_server" />
</queries>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication">
<activity
android:name=".PermissionLazyActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
四、运行时动态权限申请-饿汉模式
1、饿汉模式,就是当我们打开Activity的时候,上来就申请通讯录读写权限、收发短信权限
2、