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

Android Kotlin 权限工具类封装:简化动态权限管理

在 Android 开发中,动态权限管理是一个常见的需求,尤其是在高版本 Android 系统中,权限管理变得更加严格和复杂。为了简化权限申请的流程,减少重复代码,本文将介绍如何使用 Kotlin 封装一个高效、易用的权限工具类。


  1. 权限工具类封装

    • 检查权限
    • 请求权限
    • 处理权限请求结果
    • 显示权限请求理由
    • 跳转到应用设置
  2. 使用示例

    • 在 Activity 中使用
    • 在 Fragment 中使用
  3. 适配高版本 Android

    • Android 12 及以上版本的权限适配
    • 后台权限处理
  4. 扩展功能

    • 批量检查权限
    • 自动处理权限请求理由

回调接口定义
定义一个回调接口,用于返回权限请求的结果。

interface PermissionResultCallback {
    fun onPermissionsGranted() // 所有权限已授予
    fun onPermissionsDenied()  // 部分或全部权限被拒绝
}

权限工具类封装

将权限相关的逻辑封装在工具类 PermissionUtils 中。

import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.provider.Settings
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.ActivityResultRegistry
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner

object PermissionUtils {

    /**
     * 请求权限
     *
     * @param lifecycleOwner LifecycleOwner(Activity 或 Fragment)
     * @param registry ActivityResultRegistry
     * @param permissions 需要请求的权限数组
     * @param callback 权限请求结果回调
     */
    fun requestPermissions(
        lifecycleOwner: LifecycleOwner,
        registry: ActivityResultRegistry,
        permissions: Array<String>,
        callback: PermissionResultCallback
    ) {
        val launcher = registry.register(
            "permission_request_key", // 唯一的 key
            lifecycleOwner,
            ActivityResultContracts.RequestMultiplePermissions()
        ) { results ->
            if (results.all { it.value }) {
                // 所有权限已授予
                callback.onPermissionsGranted()
            } else {
                // 部分或全部权限被拒绝
                callback.onPermissionsDenied()
            }
        }

        // 启动权限请求
        launcher.launch(permissions)
    }

    /**
     * 检查单个权限是否已授予
     *
     * @param permission 需要检查的权限
     * @return 是否已授予
     */
    fun Context.isPermissionGranted(permission: String): Boolean {
        return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
    }

    /**
     * 检查多个权限是否已全部授予
     *
     * @param permissions 需要检查的权限数组
     * @return 是否全部已授予
     */
    fun Context.arePermissionsGranted(permissions: Array<String>): Boolean {
        return permissions.all { isPermissionGranted(it) }
    }

    /**
     * 显示权限请求理由弹窗
     *
     * @param permission 需要请求的权限
     * @param message 弹窗提示信息
     * @param onRequestAgain 用户点击“确定”后的回调
     */
    fun Activity.showPermissionRationale(
        permission: String,
        message: String,
        onRequestAgain: () -> Unit
    ) {
        AlertDialog.Builder(this)
            .setTitle("Permission Required")
            .setMessage(message)
            .setPositiveButton("OK") { _, _ -> onRequestAgain() }
            .setNegativeButton("Cancel", null)
            .show()
    }

    /**
     * 跳转到应用设置页面
     */
    fun Activity.openAppSettings() {
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
            data = Uri.fromParts("package", packageName, null)
        }
        startActivity(intent)
    }
}

3. 在 Activity 中使用
Activity 中调用工具类,并实现回调接口。

import android.Manifest
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity(), PermissionResultCallback {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 定义需要请求的权限
        val permissions = arrayOf(
            Manifest.permission.CAMERA,
            Manifest.permission.READ_EXTERNAL_STORAGE
        )

        // 检查权限是否已授予
        if (PermissionUtils.arePermissionsGranted(this, permissions)) {
            onPermissionsGranted()
        } else {
            // 请求权限
            PermissionUtils.requestPermissions(
                this, // LifecycleOwner
                activityResultRegistry, // ActivityResultRegistry
                permissions,
                this // PermissionResultCallback
            )
        }
    }

    override fun onPermissionsGranted() {
        // 权限已授予的逻辑
        Toast.makeText(this, "All permissions granted!", Toast.LENGTH_SHORT).show()
    }

    override fun onPermissionsDenied() {
        // 权限被拒绝的逻辑
        Toast.makeText(this, "Some permissions denied!", Toast.LENGTH_SHORT).show()
    }
}

4. 在 Fragment 中使用
Fragment 中调用工具类,并实现回调接口。

import android.Manifest
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment

class MyFragment : Fragment(), PermissionResultCallback {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // 定义需要请求的权限
        val permissions = arrayOf(
            Manifest.permission.CAMERA,
            Manifest.permission.READ_EXTERNAL_STORAGE
        )

        // 检查权限是否已授予
        if (PermissionUtils.arePermissionsGranted(requireContext(), permissions)) {
            onPermissionsGranted()
        } else {
            // 请求权限
            PermissionUtils.requestPermissions(
                viewLifecycleOwner, // LifecycleOwner
                requireActivity().activityResultRegistry, // ActivityResultRegistry
                permissions,
                this // PermissionResultCallback
            )
        }
    }

    override fun onPermissionsGranted() {
        // 权限已授予的逻辑
        Toast.makeText(requireContext(), "All permissions granted!", Toast.LENGTH_SHORT).show()
    }

    override fun onPermissionsDenied() {
        // 权限被拒绝的逻辑
        Toast.makeText(requireContext(), "Some permissions denied!", Toast.LENGTH_SHORT).show()
    }
}

5. 总结
工具类封装:将权限检查、请求、弹窗和设置跳转逻辑封装在 PermissionUtils 中。

**回调机制:**通过 PermissionResultCallback 接口返回权限请求结果。

**灵活调用:**支持在 ActivityFragment 中调用工具类。

通过这种方式,代码结构清晰,逻辑复用性强,且与 Activity 和 Fragment 解耦。如果有其他需求或问题,欢迎继续讨论!

相关文章:

  • 三维空间中点、线、面的关系
  • 【Elasticsearch】开启大数据分析的探索与预处理之旅
  • dynamic_cast的理解
  • 使用OpenGL实现双线性插值和双三次插值C++实现
  • 【C++】类和对象(二)默认成员函数之拷贝构造函数、运算符重载
  • IPShocks:行星际激波数据库
  • 机器学习——Bagging、随机森林
  • leetcode day31 453+435
  • 代理服务器中的代理服务器与SSL协议有什么关系?
  • 元宇宙中的“数字护照“:代理IP如何重构虚拟世界的网络规则
  • 无序抓取系列(四)
  • linux的基础命令
  • 微信小程序登录和获取手机号
  • [学习笔记]NC工具安装及使用
  • 【AI News | 20250326】每日AI进展
  • 最大字段和问题 C++(穷举、分治法、动态规划)
  • h5运行在手机浏览器查看控制台信息
  • leetcode41.缺失的第一个正数
  • 数智读书笔记系列025《智能医疗:医学人工智能的未来》
  • Rust安装并配置配置vscode编译器
  • 东方红资管官宣:41岁原国信资管董事长成飞出任新总经理
  • 2025上海科技节将于5月17日开幕,拟设6大板块专题活动
  • 李彦宏:技术迭代速度之快从业30年来未见过,要提升执行力战胜对手
  • 蓝佛安:中方将采取更加积极有为的宏观政策,有信心实现今年5%左右增长目标
  • 新加坡总理黄循财领导人民行动党胜选,外交部回应
  • 为什么所有动物里,只有人类幼崽发育得这么慢?