Android 权限请求框架,已适配 Android 13
GitHub 地址:XXPermissions
一句代码搞定权限请求,从未如此简单
二、框架亮点-
简洁易用,采用链式调用的方式,使用只需一句代码
-
支持单个权限、多个权限、单个权限组、多个权限组请求
-
不指定权限则自动获取清单文件上的危险权限进行申请
-
如果动态申请的权限没有在清单文件中注册会抛出异常
-
支持大部分国产手机直接跳转到具体的权限设置页面
-
可设置被拒绝后继续申请,直到用户授权或者永久拒绝
-
支持请求6.0及以上的悬浮窗权限和8.0及以上的安装权限
-
本框架不依赖AppCompatSupport库,兼容Eclipse和Studio
1. 集成
- 如果你的项目 Gradle 配置是在 7.0 以下,需要在 build.gradle 文件中加入
allprojects {
repositories {
// JitPack 远程仓库:https://jitpack.io
maven { url 'https://jitpack.io' }
}
}
- 如果你的 Gradle 配置是 7.0 及以上,则需要在 settings.gradle 文件中加入
dependencyResolutionManagement {
repositories {
// JitPack 远程仓库:https://jitpack.io
maven { url 'https://jitpack.io' }
}
}
- 在项目 app 模块下的 build.gradle 文件中加入远程依赖
android {
compileSdk 33
defaultConfig {
applicationId "com.hkt.locationdemo"
minSdk 21
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
-------------------------------------------------------------
// 权限请求框架:https://github.com/getActivity/XXPermissions
implementation 'com.github.getActivity:XXPermissions:16.2'
// 吐司框架:https://github.com/getActivity/ToastUtils
implementation 'com.github.getActivity:ToastUtils:10.5'
- 如果项目是基于 AndroidX 包,请在项目 gradle.properties 文件中加入
# 表示将第三方库迁移到 AndroidX
android.enableJetifier = true
2. 清单文件,添加权限
3. 代码
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// 初始化吐司工具类
ToastUtils.init(this, new WhiteToastStyle());
}
}
**
* Created on 2022/9/15 16:03
* 通知消息监控服务
* @author Gong Youqiang
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public class NotificationMonitorService extends NotificationListenerService {
/**
* 当系统收到新的通知后出发回调
*/
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Bundle extras = sbn.getNotification().extras;
if (extras != null) {
//获取通知消息标题
String title = extras.getString(Notification.EXTRA_TITLE);
// 获取通知消息内容
Object msgText = extras.getCharSequence(Notification.EXTRA_TEXT);
ToastUtils.show("监听到新的通知消息,标题为:" + title + ",内容为:" + msgText);
}
}
}
/**
* 当系统通知被删掉后出发回调
*/
@Override
public void onNotificationRemoved(StatusBarNotification sbn) {
super.onNotificationRemoved(sbn);
}
}
/**
* Created on 2022/9/15 16:05
* 权限申请拦截器
* @author Gong Youqiang
*/
public final class PermissionInterceptor implements IPermissionInterceptor {
@Override
public void grantedPermissions(Activity activity, List allPermissions, List grantedPermissions,
boolean all, OnPermissionCallback callback) {
if (callback == null) {
return;
}
callback.onGranted(grantedPermissions, all);
}
@Override
public void deniedPermissions(Activity activity, List allPermissions, List deniedPermissions,
boolean never, OnPermissionCallback callback) {
if (callback != null) {
callback.onDenied(deniedPermissions, never);
}
if (never) {
if (deniedPermissions.size() == 1 && Permission.ACCESS_MEDIA_LOCATION.equals(deniedPermissions.get(0))) {
ToastUtils.show(R.string.common_permission_media_location_hint_fail);
return;
}
showPermissionSettingDialog(activity, allPermissions, deniedPermissions, callback);
return;
}
if (deniedPermissions.size() == 1) {
String deniedPermission = deniedPermissions.get(0);
if (Permission.ACCESS_BACKGROUND_LOCATION.equals(deniedPermission)) {
ToastUtils.show(R.string.common_permission_background_location_fail_hint);
return;
}
if (Permission.BODY_SENSORS_BACKGROUND.equals(deniedPermission)) {
ToastUtils.show(R.string.common_permission_background_sensors_fail_hint);
return;
}
}
final String message;
List permissionNames = PermissionNameConvert.permissionsToNames(activity, deniedPermissions);
if (!permissionNames.isEmpty()) {
message = activity.getString(R.string.common_permission_fail_assign_hint, PermissionNameConvert.listToString(permissionNames));
} else {
message = activity.getString(R.string.common_permission_fail_hint);
}
ToastUtils.show(message);
}
/**
* 显示授权对话框
*/
private void showPermissionSettingDialog(Activity activity, List allPermissions,
List deniedPermissions, OnPermissionCallback callback) {
if (activity == null || activity.isFinishing() ||
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
return;
}
final String message;
List permissionNames = PermissionNameConvert.permissionsToNames(activity, deniedPermissions);
if (!permissionNames.isEmpty()) {
message = activity.getString(R.string.common_permission_manual_assign_fail_hint, PermissionNameConvert.listToString(permissionNames));
} else {
message = activity.getString(R.string.common_permission_manual_fail_hint);
}
// 这里的 Dialog 只是示例,没有用 DialogFragment 来处理 Dialog 生命周期
new AlertDialog.Builder(activity)
.setTitle(R.string.common_permission_alert)
.setMessage(message)
.setPositiveButton(R.string.common_permission_goto_setting_page, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
XXPermissions.startPermissionActivity(activity,
deniedPermissions, new OnPermissionPageCallback() {
@Override
public void onGranted() {
if (callback == null) {
return;
}
callback.onGranted(allPermissions, true);
}
@Override
public void onDenied() {
showPermissionSettingDialog(activity, allPermissions,
XXPermissions.getDenied(activity, allPermissions), callback);
}
});
}
})
.show();
}
}
/**
* Created on 2022/9/15 16:07
* 权限名称转换器
* @author Gong Youqiang
*/
public final class PermissionNameConvert {
/**
* 获取权限名称
*/
public static String getPermissionString(Context context, List permissions) {
return listToString(permissionsToNames(context, permissions));
}
/**
* String 列表拼接成一个字符串
*/
public static String listToString(List hints) {
if (hints == null || hints.isEmpty()) {
return "";
}
StringBuilder builder = new StringBuilder();
for (String text : hints) {
if (builder.length() == 0) {
builder.append(text);
} else {
builder.append("、")
.append(text);
}
}
return builder.toString();
}
/**
* 将权限列表转换成对应名称列表
*/
@NonNull
public static List permissionsToNames(Context context, List permissions) {
List permissionNames = new ArrayList();
if (context == null) {
return permissionNames;
}
if (permissions == null) {
return permissionNames;
}
for (String permission : permissions) {
switch (permission) {
case Permission.READ_EXTERNAL_STORAGE:
case Permission.WRITE_EXTERNAL_STORAGE: {
String hint = context.getString(R.string.common_permission_storage);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.READ_MEDIA_IMAGES:
case Permission.READ_MEDIA_VIDEO: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
String hint = context.getString(R.string.common_permission_image_and_video);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.READ_MEDIA_AUDIO: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
String hint = context.getString(R.string.common_permission_audio);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.CAMERA: {
String hint = context.getString(R.string.common_permission_camera);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.RECORD_AUDIO: {
String hint = context.getString(R.string.common_permission_microphone);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.ACCESS_FINE_LOCATION:
case Permission.ACCESS_COARSE_LOCATION:
case Permission.ACCESS_BACKGROUND_LOCATION: {
String hint;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
!permissions.contains(Permission.ACCESS_FINE_LOCATION) &&
!permissions.contains(Permission.ACCESS_COARSE_LOCATION)) {
hint = context.getString(R.string.common_permission_location_background);
} else {
hint = context.getString(R.string.common_permission_location);
}
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.BODY_SENSORS:
case Permission.BODY_SENSORS_BACKGROUND: {
String hint;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
!permissions.contains(Permission.BODY_SENSORS)) {
hint = context.getString(R.string.common_permission_sensors_background);
} else {
hint = context.getString(R.string.common_permission_sensors);
}
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.BLUETOOTH_SCAN:
case Permission.BLUETOOTH_CONNECT:
case Permission.BLUETOOTH_ADVERTISE: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
String hint = context.getString(R.string.common_permission_wireless_devices);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.NEARBY_WIFI_DEVICES: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
String hint = context.getString(R.string.common_permission_wireless_devices);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.READ_PHONE_STATE:
case Permission.CALL_PHONE:
case Permission.ADD_VOICEMAIL:
case Permission.USE_SIP:
case Permission.READ_PHONE_NUMBERS:
case Permission.ANSWER_PHONE_CALLS: {
String hint = context.getString(R.string.common_permission_phone);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.GET_ACCOUNTS:
case Permission.READ_CONTACTS:
case Permission.WRITE_CONTACTS: {
String hint = context.getString(R.string.common_permission_contacts);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.READ_CALENDAR:
case Permission.WRITE_CALENDAR: {
String hint = context.getString(R.string.common_permission_calendar);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.READ_CALL_LOG:
case Permission.WRITE_CALL_LOG:
case Permission.PROCESS_OUTGOING_CALLS: {
String hint = context.getString(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ?
R.string.common_permission_call_log :
R.string.common_permission_phone);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.ACTIVITY_RECOGNITION: {
String hint = context.getString(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ?
R.string.common_permission_activity_recognition_30 :
R.string.common_permission_activity_recognition_29);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.ACCESS_MEDIA_LOCATION: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
String hint = context.getString(R.string.common_permission_media_location);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.SEND_SMS:
case Permission.RECEIVE_SMS:
case Permission.READ_SMS:
case Permission.RECEIVE_WAP_PUSH:
case Permission.RECEIVE_MMS: {
String hint = context.getString(R.string.common_permission_sms);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.MANAGE_EXTERNAL_STORAGE: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
String hint = context.getString(R.string.common_permission_manage_storage);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.REQUEST_INSTALL_PACKAGES: {
String hint = context.getString(R.string.common_permission_install);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.SYSTEM_ALERT_WINDOW: {
String hint = context.getString(R.string.common_permission_window);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.WRITE_SETTINGS: {
String hint = context.getString(R.string.common_permission_setting);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.NOTIFICATION_SERVICE: {
String hint = context.getString(R.string.common_permission_notification);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.POST_NOTIFICATIONS: {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
String hint = context.getString(R.string.common_permission_post_notifications);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
}
break;
}
case Permission.BIND_NOTIFICATION_LISTENER_SERVICE: {
String hint = context.getString(R.string.common_permission_notification_listener);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.PACKAGE_USAGE_STATS: {
String hint = context.getString(R.string.common_permission_task);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.SCHEDULE_EXACT_ALARM: {
String hint = context.getString(R.string.common_permission_alarm);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.ACCESS_NOTIFICATION_POLICY: {
String hint = context.getString(R.string.common_permission_not_disturb);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS: {
String hint = context.getString(R.string.common_permission_ignore_battery);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.BIND_VPN_SERVICE: {
String hint = context.getString(R.string.common_permission_vpn);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
case Permission.PICTURE_IN_PICTURE: {
String hint = context.getString(R.string.common_permission_picture_in_picture);
if (!permissionNames.contains(hint)) {
permissionNames.add(hint);
}
break;
}
default:
break;
}
}
return permissionNames;
}
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_main_request_single).setOnClickListener(this);
findViewById(R.id.btn_main_request_group).setOnClickListener(this);
findViewById(R.id.btn_main_request_location).setOnClickListener(this);
findViewById(R.id.btn_main_request_sensors).setOnClickListener(this);
findViewById(R.id.btn_main_request_activity_recognition).setOnClickListener(this);
findViewById(R.id.btn_main_request_bluetooth).setOnClickListener(this);
findViewById(R.id.btn_main_request_wifi).setOnClickListener(this);
findViewById(R.id.btn_main_request_media_location).setOnClickListener(this);
findViewById(R.id.btn_main_request_media_storage).setOnClickListener(this);
findViewById(R.id.btn_main_request_manage_storage).setOnClickListener(this);
findViewById(R.id.btn_main_request_install).setOnClickListener(this);
findViewById(R.id.btn_main_request_window).setOnClickListener(this);
findViewById(R.id.btn_main_request_setting).setOnClickListener(this);
findViewById(R.id.btn_main_request_notification).setOnClickListener(this);
findViewById(R.id.btn_main_request_post_notification).setOnClickListener(this);
findViewById(R.id.btn_main_request_notification_listener).setOnClickListener(this);
findViewById(R.id.btn_main_request_package).setOnClickListener(this);
findViewById(R.id.btn_main_request_alarm).setOnClickListener(this);
findViewById(R.id.btn_main_request_not_disturb).setOnClickListener(this);
findViewById(R.id.btn_main_request_ignore_battery).setOnClickListener(this);
findViewById(R.id.btn_main_request_picture_in_picture).setOnClickListener(this);
findViewById(R.id.btn_main_request_open_vpn).setOnClickListener(this);
findViewById(R.id.btn_main_app_details).setOnClickListener(this);
}
@Override
public void onClick(View view) {
int viewId = view.getId();
if (viewId == R.id.btn_main_request_single) {
XXPermissions.with(this)
.permission(Permission.CAMERA)
.interceptor(new PermissionInterceptor())
.request(new OnPermissionCallback() {
@Override
public void onGranted(List permissions, boolean all) {
if (!all) {
return;
}
toast("获取" + PermissionNameConvert.getPermissionString(MainActivity.this, permissions) + "成功");
}
});
} else if (viewId == R.id.btn_main_request_group) {
XXPermissions.with(this)
.permission(Permission.RECORD_AUDIO)
.permission(Permission.Group.CALENDAR)
.interceptor(new PermissionInterceptor())
.request(new OnPermissionCallback() {
@Override
public void onGranted(List permissions, boolean all) {
if (!all) {
return;
}
toast("获取" + PermissionNameConvert.getPermissionString(MainActivity.this, permissions) + "成功");
}
});
} else if (viewId == R.id.btn_main_request_location) {
XXPermissions.with(this)
.permission(Permission.ACCESS_COARSE_LOCATION)
.permission(Permission.ACCESS_FINE_LOCATION)
// 如果不需要在后台使用定位功能,请不要申请此权限
.permission(Permission.ACCESS_BACKGROUND_LOCATION)
.interceptor(new PermissionInterceptor())
.request(new OnPermissionCallback() {
@Override
public void onGranted(List permissions, boolean all) {
if (!all) {
return;
}
toast("获取" + PermissionNameConvert.getPermissionString(MainActivity.this, permissions) + "成功");
}
});
} else if (viewId == R.id.btn_main_request_sensors) {
XXPermissions.with(this)
.permission(Permission.BODY_SENSORS)
.permission(Permission.BODY_SENSORS_BACKGROUND)
.interceptor(new PermissionInterceptor())
.request(new OnPermissionCallback() {
@Override
public void onGranted(List permissions, boolean all) {
if (!all) {
return;
}
toast("获取" + PermissionNameConvert.getPermissionString(MainActivity.this, permissions) + "成功");
}
});
} else if (viewId == R.id.btn_main_request_activity_recognition) {
XXPermissions.with(this)
.permission(Permission.ACTIVITY_RECOGNITION)
.interceptor(new PermissionInterceptor())
.request(new OnPermissionCallback() {
@Override
public void onGranted(List permissions, boolean all) {
if (!all) {
return;
}
toast("获取" + PermissionNameConvert.getPermissionString(MainActivity.this, permissions) + "成功");
addCountStepListener();
}
});
} else if (viewId == R.id.btn_main_request_bluetooth) {
long delayMillis = 0;
if (Build.VERSION.SDK_INT
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?