当前位置: 首页 > news >正文

Android 6.0+ 动态权限请求模块,这个模块会包含 权限检查、请求、结果处理 等核心功能,并且支持 单个 / 多个权限请求、权限拒绝后的引导

添加 Android 6.0+ 动态权限请求模块,这个模块会包含 权限检查、请求、结果处理 等核心功能,并且支持 单个 / 多个权限请求权限拒绝后的引导,可以直接集成到你的 MVVM 架构中。

一、动态权限模块设计思路

Android 6.0(API 23)后,将权限分为 普通权限(安装时授予)和 危险权限(运行时动态请求),我们需要:

  1. 封装一个工具类,统一处理权限检查和请求
  2. 在 Activity/Fragment 中接收权限请求结果
  3. 处理 “权限被永久拒绝” 的场景(引导用户去设置页开启)
  4. 适配 MVVM 架构,让 ViewModel 可间接触发权限请求

二、第一步:添加权限工具类 PermissionUtils

创建 com.nyw.mvvmmode.utils.PermissionUtils.java,封装核心逻辑:

package com.nyw.mvvmmode.utils;import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import java.util.ArrayList;
import java.util.List;/*** Android 6.0+ 动态权限工具类* 支持:单个/多个权限请求、权限检查、引导用户去设置页开启权限*/
public class PermissionUtils {// 权限请求码(自定义,确保唯一)public static final int REQUEST_CODE_PERMISSION = 100;// 跳转到应用设置页的请求码public static final int REQUEST_CODE_SETTINGS = 101;/*** 检查单个权限是否已授予*/public static boolean checkSinglePermission(Context context, @NonNull String permission) {// Android 6.0 以下默认授予所有权限if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {return true;}return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;}/*** 检查多个权限是否已全部授予*/public static boolean checkMultiplePermissions(Context context, @NonNull String[] permissions) {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || permissions == null || permissions.length == 0) {return true;}for (String permission : permissions) {if (!checkSinglePermission(context, permission)) {return false;}}return true;}/*** 筛选出未授予的权限*/public static List<String> getDeniedPermissions(Context context, @NonNull String[] permissions) {List<String> deniedPermissions = new ArrayList<>();if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || permissions == null || permissions.length == 0) {return deniedPermissions;}for (String permission : permissions) {if (!checkSinglePermission(context, permission)) {deniedPermissions.add(permission);}}return deniedPermissions;}/*** 请求单个权限*/public static void requestSinglePermission(Activity activity, @NonNull String permission) {requestMultiplePermissions(activity, new String[]{permission});}/*** 请求多个权限*/public static void requestMultiplePermissions(Activity activity, @NonNull String[] permissions) {if (activity == null || permissions == null || permissions.length == 0) {return;}// 筛选未授予的权限List<String> deniedPermissions = getDeniedPermissions(activity, permissions);if (deniedPermissions.isEmpty()) {// 所有权限已授予,直接回调成功if (sPermissionCallback != null) {sPermissionCallback.onPermissionGranted(permissions);}return;}// 发起权限请求ActivityCompat.requestPermissions(activity,deniedPermissions.toArray(new String[0]),REQUEST_CODE_PERMISSION);}/*** 检查是否需要显示权限说明(用户之前拒绝过权限)*/public static boolean shouldShowPermissionRationale(Activity activity, @NonNull String permission) {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {return false;}return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);}/*** 跳转到应用设置页(用户永久拒绝权限时调用)*/public static void goToAppSettings(Activity activity) {if (activity == null) {return;}Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);Uri uri = Uri.fromParts("package", activity.getPackageName(), null);intent.setData(uri);activity.startActivityForResult(intent, REQUEST_CODE_SETTINGS);}// ====================== 权限请求回调 ======================private static PermissionCallback sPermissionCallback;public interface PermissionCallback {/*** 所有请求的权限都已授予*/void onPermissionGranted(String[] grantedPermissions);/*** 部分/全部权限被拒绝*/void onPermissionDenied(String[] deniedPermissions, boolean isPermanentlyDenied);}/*** 设置权限请求回调(需在请求权限前设置)*/public static void setPermissionCallback(PermissionCallback callback) {sPermissionCallback = callback;}/*** 清除权限回调(避免内存泄漏)*/public static void clearPermissionCallback() {sPermissionCallback = null;}/*** 在 Activity 的 onRequestPermissionsResult 中调用,处理权限请求结果*/public static void onRequestPermissionsResult(Activity activity, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {if (requestCode != REQUEST_CODE_PERMISSION || sPermissionCallback == null) {return;}List<String> grantedPermissions = new ArrayList<>();List<String> deniedPermissions = new ArrayList<>();boolean isPermanentlyDenied = false;for (int i = 0; i < permissions.length; i++) {if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {grantedPermissions.add(permissions[i]);} else {deniedPermissions.add(permissions[i]);// 检查是否永久拒绝(用户勾选了“不再询问”)if (!shouldShowPermissionRationale(activity, permissions[i])) {isPermanentlyDenied = true;}}}if (deniedPermissions.isEmpty()) {// 所有权限都授予sPermissionCallback.onPermissionGranted(grantedPermissions.toArray(new String[0]));} else {// 部分/全部权限被拒绝sPermissionCallback.onPermissionDenied(deniedPermissions.toArray(new String[0]), isPermanentlyDenied);}}
}

三、第二步:在 BaseActivity 中集成权限处理

为了让所有 Activity 都能复用权限功能,创建 com.nyw.mvvmmode.ui.base.BaseActivity.java,统一处理权限请求和结果:

package com.nyw.mvvmmode.ui.base;import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;import com.nyw.mvvmmode.utils.PermissionUtils;/*** 基础 Activity,封装权限处理、生命周期管理等通用功能*/
public abstract class BaseActivity extends AppCompatActivity implements PermissionUtils.PermissionCallback {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 设置布局(由子类实现)setContentView(getLayoutId());// 初始化视图(由子类实现)initView();// 初始化数据(由子类实现)initData();}/*** 获取布局 ID(子类必须实现)*/protected abstract int getLayoutId();/*** 初始化视图(子类按需实现)*/protected abstract void initView();/*** 初始化数据(子类按需实现)*/protected abstract void initData();// ====================== 权限相关方法 ======================/*** 请求单个权限*/protected void requestSinglePermission(String permission) {PermissionUtils.setPermissionCallback(this);PermissionUtils.requestSinglePermission(this, permission);}/*** 请求多个权限*/protected void requestMultiplePermissions(String[] permissions) {PermissionUtils.setPermissionCallback(this);PermissionUtils.requestMultiplePermissions(this, permissions);}/*** 权限请求结果回调(交给 PermissionUtils 处理)*/@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);PermissionUtils.onRequestPermissionsResult(this, requestCode, permissions, grantResults);}/*** 从应用设置页返回的结果*/@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == PermissionUtils.REQUEST_CODE_SETTINGS) {// 返回设置页后,重新检查权限(子类可重写此方法处理具体逻辑)onPermissionSettingsBack();}}/*** 从设置页返回后,重新检查权限(子类按需重写)*/protected void onPermissionSettingsBack() {// 示例:默认提示“请开启所需权限”Toast.makeText(this, "请开启应用所需权限以正常使用", Toast.LENGTH_SHORT).show();}// ====================== 权限回调实现 ======================/*** 所有权限都授予(子类可重写处理具体业务)*/@Overridepublic void onPermissionGranted(String[] grantedPermissions) {// 示例:默认提示“权限已授予”Toast.makeText(this, "所需权限已授予", Toast.LENGTH_SHORT).show();}/*** 权限被拒绝(子类可重写处理具体业务)* @param isPermanentlyDenied 是否永久拒绝(用户勾选“不再询问”)*/@Overridepublic void onPermissionDenied(String[] deniedPermissions, boolean isPermanentlyDenied) {if (isPermanentlyDenied) {// 永久拒绝:引导用户去设置页开启Toast.makeText(this, "权限已被永久拒绝,请在设置中开启", Toast.LENGTH_SHORT).show();PermissionUtils.goToAppSettings(this);} else {// 临时拒绝:提示用户需要权限Toast.makeText(this, "请授予必要权限以正常使用功能", Toast.LENGTH_SHORT).show();}}// ====================== 避免内存泄漏 ======================@Overrideprotected void onDestroy() {super.onDestroy();// 清除权限回调,避免内存泄漏PermissionUtils.clearPermissionCallback();}
}

四、第三步:在 MVVM 架构中使用动态权限

以 MainActivity 中请求 “相机 + 存储权限” 为例,演示如何在 View(Activity)和 ViewModel 中配合使用权限模块:

1. View 层(MainActivity)

继承 BaseActivity,发起权限请求并处理业务逻辑:

package com.nyw.mvvmmode.ui.activity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;import com.nyw.mvvmmode.R;
import com.nyw.mvvmmode.ui.base.BaseActivity;
import com.nyw.mvvmmode.viewmodel.MainViewModel;/*** 示例:在 View 层发起权限请求,配合 ViewModel 处理业务*/
public class MainActivity extends BaseActivity {private MainViewModel mainViewModel;// 需要请求的权限(相机 + 读写存储)private final String[] REQUIRED_PERMISSIONS = {android.Manifest.permission.CAMERA,android.Manifest.permission.READ_EXTERNAL_STORAGE,android.Manifest.permission.WRITE_EXTERNAL_STORAGE};@Overrideprotected int getLayoutId() {// 返回当前 Activity 的布局 IDreturn R.layout.activity_main;}@Overrideprotected void initView() {// 初始化 ViewModelmainViewModel = new MainViewModel();// 初始化按钮(点击触发权限请求)Button btnRequestPermission = findViewById(R.id.btn_request_permission);btnRequestPermission.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 点击按钮,发起权限请求requestMultiplePermissions(REQUIRED_PERMISSIONS);}});}@Overrideprotected void initData() {// 初始化数据(如加载列表、请求接口等)}/*** 重写:权限全部授予后,调用 ViewModel 处理业务(如打开相机)*/@Overridepublic void onPermissionGranted(String[] grantedPermissions) {super.onPermissionGranted(grantedPermissions);// 权限授予成功,通知 ViewModel 执行业务逻辑(如打开相机)mainViewModel.openCamera(this);}/*** 重写:从设置页返回后,重新检查权限*/@Overrideprotected void onPermissionSettingsBack() {super.onPermissionSettingsBack();// 重新检查权限,如果已授予则执行业务if (PermissionUtils.checkMultiplePermissions(this, REQUIRED_PERMISSIONS)) {mainViewModel.openCamera(this);}}
}

2、’ViewModel 层(MainViewModel)

处理业务逻辑(如打开相机),不直接操作权限:

package com.nyw.mvvmmode.viewmodel;import android.app.Activity;
import android.content.Intent;
import android.provider.MediaStore;import androidx.lifecycle.ViewModel;/*** 示例:ViewModel 处理业务逻辑,不直接操作权限*/
public class MainViewModel extends ViewModel {/*** 打开相机(权限已在 View 层授予)*/public void openCamera(Activity activity) {// 跳转到系统相机(业务逻辑)Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);activity.startActivityForResult(intent, 1002); // 1002 是相机请求码}// 其他业务逻辑...
}

五、第四步:在 AndroidManifest 中声明权限

无论是否需要动态请求,都必须在 AndroidManifest.xml 中声明权限(否则动态请求也会失败):

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.nyw.mvvmmode"><!-- 声明需要的权限(示例:相机、存储) --><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!-- 之前的网络权限 --><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.INTERNET" /><applicationandroid:name=".MyApplication"android:allowBackup="true"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/AppTheme"> <!-- 之前设置的自定义主题 --><activity android:name=".ui.activity.MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

六、核心功能说明

功能实现方式调用示例
单个权限请求requestSinglePermission(Manifest.permission.CAMERA)打开相机前请求相机权限
多个权限请求requestMultiplePermissions(new String[]{CAMERA, READ_EXTERNAL_STORAGE})拍照并保存时请求相机 + 存储权限
权限检查PermissionUtils.checkSinglePermission(context, permission)初始化时检查是否已有权限
永久拒绝处理引导用户去设置页(PermissionUtils.goToAppSettings(activity)用户勾选 “不再询问” 后触发
内存泄漏防护在 onDestroy 中清除权限回调PermissionUtils.clearPermissionCallback()

七、适配注意事项

  1. Android 13+ 特殊权限:如 READ_MEDIA_IMAGES(替代 `READ_EX
http://www.dtcms.com/a/415138.html

相关文章:

  • Android -自定义Binding Adapter实战应用
  • 网站优化提升速度网站建设权利义务
  • 【复现】一种基于价格弹性矩阵的居民峰谷分时电价激励策略【需求响应】
  • 【怎么复制cmd命令行里面的文字输出和报错】
  • Oracle体系结构-RECO详解
  • 2025.9.27总结
  • 做网站怎么跟客户谈话搜狗优化好的网站
  • 乐清网站推广公司怎样取消2345网址导航
  • AI时代大数据分布的深入洞察与应用
  • Istio - 开源服务网格平台
  • NLP:关于Bert模型的基础讲解
  • 兰州新区建设局网站地址金华做网站报价
  • seo网站推广龙岩网红餐厅
  • 20252803《Linux内核原理与分析》第三周作业
  • SpringIoC容器对bean的管理
  • 无广告阅读新体验:Reader与cpolar的远程访问方案
  • 集团网站建设行业现状电商网站开发 文献综述
  • 南昌做兼职的网站设计wordpress建站 客户端
  • ManualResetEventSlim:C# 线程同步工具
  • 手机网站制作织梦网站模板网站这么建设
  • 第2章 进程与线程
  • 网站编辑外包汕头 网站建设
  • 做企业网站支付功能网站建设主持词
  • 怎么把自己做的网站登录到网上html编辑器手机版
  • 南昌公司做网站需要多少钱wordpress页面定制
  • 作者须知 — Transactions Journals
  • 强化学习(3)策略梯度
  • langchain的核心组件
  • 算法基础篇(6)差分
  • Umbra(陰影):DDS底層協議漏洞遠程惡意組件注入Botnets