Android 权限总结

Android 权限总结

权限分类

官网文档

  • 普通权限:这类权限通常不会直接威胁到用户的隐私。如果你的应用列表中包含这类权限,需要在 AndroidManifest.xml 文件中定义,系统会自动授予权限,无需用户明确授予。如:android.permission.INTERNET 网络权限,android.permission.SET_WALLPAPER 壁纸权限。
  • 危险权限:这类权限可能会涉及到用户的隐私数据,或者可能会对用户的存储数据或操作产生影响。需要在 AndroidManifest.xml 文件中定义,同时必须通过权限请求对话框向用户请求这类权限。如:android.permission.READ_CONTACTS 允许应用读取用户的联系人数据,android.permission.WRITE_EXTERNAL_STORAGE 允许应用写入到外部存储。
  • 特殊权限:这类权限不属于正常和危险权限,它们有自己的处理方式。如:android.permission.REQUEST_INSTALL_PACKAGES 安装应用权限,android.permission.MANAGE_EXTERNAL_STORAGE Android11新增的文件管理权限。

危险权限:

在这里插入图片描述

API说明

targetSdkVersion>=23: 这时就需要在代码中检查权限了,否则打开app去执行需要权限的操作会崩溃。如果关闭权限将会弹出提示框提示你开启权限。

  • ContextCompact#checkSelfPermission():判断权限是否允许。
  • ActivityCompat#requestPermissions():申请权限。
  • ActivityCompat#onRequestPermissionsResult():权限结果回调。
  • ActivityCompat#shouldShowRequestPermissonRationale:返回true,表示权限被拒绝过,可以再次申请;返回false,表示权限被拒绝并且不再询问,必须在设置中打开。
/**
* 检查权限:
*  PackageManager.PERMISSION_GRANTED 权限已申请
*  PackageManager.PERMISSION_DENIED 权限拒绝
*/
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED ) {

    //申请权限:
    ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CALL_PHONE), 1)
}
/**
* 权限回调:
*
* @param requestCode Int :请求码
* @param permissions Array<out String> :申请的所有权限
* @param grantResults IntArray :权限申请结果
*/
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray,
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == 1) {

        //权限申请成功
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show()
        } else {
            //权限申请失败
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                                                                    Manifest.permission.CALL_PHONE)
               ) {
                //已经拒绝过一次
                AlertDialog.Builder(this)
                .setMessage("需要使用通话权限")
                .show()
            } else {
                Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

单次授权

从 Android 11(API 级别 30)开始,每当您的应用请求与位置信息、麦克风或摄像头相关的权限时,面向用户显示的权限对话框都会包含一个名为仅限这一次的选项,如图 2 所示。如果用户在对话框中选择此选项,系统会向应用授予临时的单次授权。

然后,应用可以在一段时间内访问相关数据,具体时间取决于应用的行为和用户的操作:

  • 当应用的 activity 可见时,应用可以访问相关数据。
  • 如果用户将应用转为后台运行,应用可以在短时间内继续访问相关数据。
  • 如果您在 activity 可见时启动了一项前台服务,并且用户随后将您的应用转到后台,那么您的应用可以继续访问相关数据,直到该前台服务停止。

权限被撤消时

如果用户撤消单次授权(例如在系统设置中撤消),无论您是否启动了前台服务,应用都无法访问相关数据。与任何权限一样,如果用户撤消了应用的单次授权,应用进程就会终止

当用户下次打开应用并且应用中的某项功能请求访问位置信息、麦克风或摄像头时,系统会再次提示用户授予权限。

基本使用

<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.CAMERA"/>
class MainActivity : AppCompatActivity() {
    companion object {
        const val REQUEST_PERMISSIONS = 111
    }

    private lateinit var context: Context

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        context = this;
        val btnCallPhone: Button = findViewById<Button>(R.id.btnCallPhone)
        btnCallPhone.setOnClickListener {
            doCallPhone()
        }
    }

    private fun doCallPhone() {
        if (requestPermissions()) {
            call()
        }
    }

    //申请权限
    private fun requestPermissions(): Boolean {
        val deniedPermissions = checkPermissions(Manifest.permission.CALL_PHONE, Manifest.permission.CAMERA)
        return if (deniedPermissions.isNotEmpty()) {
            requestPermissions(deniedPermissions)
            false
        } else {
            true
        }
    }

    //拨打电话
    private fun call() {
        try {
            val intent = Intent(Intent.ACTION_CALL)
            intent.data = Uri.parse("tel:10086")
            startActivity(intent)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 检查指定权限是否授权
     * 并返回未授权
     */
    private fun checkPermissions(vararg permissions: String): ArrayList<String> {
        return checkPermissions(listOf(*permissions))
    }

    private fun checkPermissions(permissionList: List<String>): ArrayList<String> {
        //未授权
        val deniedList = ArrayList<String>()
        for (permission in permissionList) {
            if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                deniedList.add(permission)
            }
        }
        return deniedList
    }

    /**
     * 申请指定权限
     */
    private fun requestPermissions(permissionList: ArrayList<String>) {
        ActivityCompat.requestPermissions(this, permissionList.toTypedArray(), REQUEST_PERMISSIONS)
    }

    /**
     * 授权结果回调
     */
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            REQUEST_PERMISSIONS -> {
                //已拒绝权限集合
                val deniedList = ArrayList<String>()
                //已拒绝权限且不再问询集合
                val deniedWithNeverList = ArrayList<String>()

                grantResults.forEachIndexed { 
                    index, result ->
                    if (result != PackageManager.PERMISSION_GRANTED) {
                        if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[index])) {
                            deniedList.add(permissions[index])
                        } else {
                            deniedWithNeverList.add(permissions[index])
                        }
                    }
                }

                if (deniedList.isEmpty() && deniedWithNeverList.isEmpty()) {
                    call()
                } else {
                    if (deniedList.isNotEmpty()) {
                        //再次申请权限
                        AlertDialog.Builder(context).apply {
                            setMessage("App需要以下权限才能继续")
                            setPositiveButton("确定") { 
                                dialog, which ->
                                requestPermissions()
                            }
                            setNegativeButton("取消", null)
                        }.show()
                    } else {
                        //跳转设置界面
                        gotoSetting()
                    }
                }
            }
        }
    }

    /**
     * 跳转权限设置界面
     */
    fun gotoSetting() {
        AlertDialog.Builder(context).apply {
            setMessage("请在设置中允许以下权限")
            setNegativeButton("拒绝") { dialog, which ->
                                    }
            setPositiveButton("开启") { 
                dialog, which ->
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                val uri = Uri.fromParts("package", packageName, null)
                intent.data = uri
                startActivityForResult(intent, 1)
            }
        }.show()
    }
}

简单封装

object PermissionUtils {
    const val REQUEST_PERMISSION_CODE = 6666

    const val CAMERA = Manifest.permission.CAMERA // 摄像头
    const val CALL_PHONE = Manifest.permission.CALL_PHONE // 拨打电话

    private const val TYPE_REQUEST_PERMISSION = 1 // 表示权限申请
    private const val TYPE_GOTO_SETTING = 2 // 表示跳转设置页面

    private val permissionMap = LinkedHashMap<String, String>()

    init {
        permissionMap[CAMERA] = "相机权限"
        permissionMap[CALL_PHONE] = "拨打电话"
    }

    /**
     * 判断权限是否全部通过
     */
    fun isGrantedPermissions(context: Context, permissionList: ArrayList<String>): Boolean {
        for (permission in permissionList) {
            if (ContextCompat.checkSelfPermission(context, permission)
                != PackageManager.PERMISSION_GRANTED
            ) {
                return false
            }
        }
        return true
    }

    /**
     * 检查权限,并返回已拒绝的权限
     */
    fun checkPermissions(context: Context, permissionList: ArrayList<String>): ArrayList<String> {
        val deniedPermissionList = ArrayList<String>()
        for (permission in permissionList) {
            if (ContextCompat.checkSelfPermission(context, permission)
                != PackageManager.PERMISSION_GRANTED
            ) {
                deniedPermissionList.add(permission)
            }
        }
        return deniedPermissionList
    }

    /**
     * 申请权限
     */
    fun applyPermission(activity: Activity, permissionList: ArrayList<String>) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val list = checkPermissions(activity, permissionList)
            if (list.size > 0) {
                showPermissionDialog(
                    activity, TYPE_REQUEST_PERMISSION, "需要您同意以下权限才能正常使用", list
                )
            }
        }
    }

    /**
     * 申请权限
     */
    fun applyPermission(fragment: Fragment, permissionList: ArrayList<String>) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val list = checkPermissions(fragment.context!!, permissionList)
            if (list.size > 0) {
                showPermissionDialog(
                    fragment, TYPE_REQUEST_PERMISSION, "需要您同意以下权限才能正常使用", list
                )
            }
        }
    }

    private fun showPermissionDialog(
        fragment: Fragment,
        type: Int,
        title: String,
        permissionList: ArrayList<String>
    ) {
        val descList = ArrayList<String>()
        for (permission in permissionList) {
            val permissionDesc: String = permissionMap[permission]!!
            if (!descList.contains(permissionDesc)) {
                descList.add(permissionDesc)
            }
        }
        val builder = StringBuilder()
        if (descList.size > 0) {
            for ((index, value) in descList.withIndex()) {
                if (index == descList.size - 1) {
                    builder.append(value)
                } else {
                    builder.append(value).append("\n")
                }
            }
        }
        val message = builder.toString()
        if (type == TYPE_REQUEST_PERMISSION) {
            AlertDialog.Builder(fragment.context)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton(
                    "允许"
                ) { dialog, which ->
                    requestPermissions(fragment, permissionList)
                }
                .setNegativeButton(
                    "拒绝"
                ) { dialog, which -> }
                .show()
        } else if (type == TYPE_GOTO_SETTING) {
            AlertDialog.Builder(fragment.context)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("打开") { dialog, which ->
                    gotoSettings(fragment)
                }
                .setNegativeButton(
                    "拒绝"
                ) { dialog, which -> }
                .show()
        }
    }


    /**
     * 显示权限弹窗
     */
    fun showPermissionDialog(
        activity: Activity,
        type: Int,
        title: String,
        permissionList: ArrayList<String>
    ) {
        val descList = ArrayList<String>()
        for (permission in permissionList) {
            val d: String = permissionMap.get(permission)!!
            if (!descList.contains(d)) {
                descList.add(d)
            }
        }
        val builder = StringBuilder()
        if (descList.size > 0) {
            for ((index, value) in descList.withIndex()) {
                if (index == descList.size - 1) {
                    builder.append(value)
                } else {
                    builder.append(value).append("\n")
                }
            }
        }
        val message = builder.toString()
        if (type == TYPE_REQUEST_PERMISSION) {
            AlertDialog.Builder(activity)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton(
                    "允许"
                ) { dialog, which ->
                    requestPermissions(activity, permissionList)
                }
                .setNegativeButton(
                    "拒绝"
                ) { dialog, which -> }
                .show()
        } else if (type == TYPE_GOTO_SETTING) {
            AlertDialog.Builder(activity)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("打开") { dialog, which ->
                    gotoSettings(activity)
                }
                .setNegativeButton(
                    "拒绝"
                ) { dialog, which -> }
                .show()
        }
    }

    /**
     * 回调权限结果
     */
    fun <T> onRequestPermissionsResult(
        obj: T,
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ): Boolean {
        return if (requestCode == REQUEST_PERMISSION_CODE) {
            if (obj is Fragment) {
                val fragment = obj as Fragment
                val deniedList = ArrayList<String>() // 已拒绝权限集合
                val deniedWithNeverList = ArrayList<String>() // 已拒绝且不再问询集合
                for (i in grantResults.indices) {
                    if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
                        if (ActivityCompat.shouldShowRequestPermissionRationale(
                                fragment.activity!!,
                                permissions[i]
                            )
                        ) {
                            deniedList.add(permissions[i])
                        } else {
                            deniedWithNeverList.add(permissions[i])
                        }
                    }
                }
                if (deniedList.size > 0) {
                    showPermissionDialog(
                        fragment,
                        TYPE_REQUEST_PERMISSION,
                        "需要您同意以下权限才能正常使用",
                        deniedList
                    )
                    false
                } else if (deniedWithNeverList.size > 0) {
                    showPermissionDialog(
                        fragment,
                        TYPE_GOTO_SETTING,
                        "请在设置中允许以下权限",
                        deniedWithNeverList
                    )
                    false
                } else {
                    true
                }
            } else if (obj is Activity) {
                val activity = obj as Activity
                val deniedList = ArrayList<String>() //拒绝权限集合
                val deniedWithNeverList = ArrayList<String>() //已拒绝且不再问询集合
                for (i in grantResults.indices) {
                    if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
                        if (ActivityCompat.shouldShowRequestPermissionRationale(
                                activity,
                                permissions[i]
                            )
                        ) {
                            deniedList.add(permissions[i])
                        } else {
                            deniedWithNeverList.add(permissions[i])
                        }
                    }
                }
                if (deniedList.size > 0) {
                    showPermissionDialog(
                        activity,
                        TYPE_REQUEST_PERMISSION,
                        "需要您同意以下权限才能正常使用",
                        deniedList
                    )
                    false
                } else if (deniedWithNeverList.size > 0) {
                    showPermissionDialog(
                        activity,
                        TYPE_GOTO_SETTING,
                        "请在设置中允许以下权限",
                        deniedWithNeverList
                    )
                    false
                } else {
                    true
                }
            } else {
                throw java.lang.IllegalStateException("obj不是一个Fragment或Activity")
            }
        } else false
    }

    /**
     * 真正申请权限
     */
    fun <T> requestPermissions(obj: T, permissionList: ArrayList<String>) {
        when (obj) {
            is Activity -> {
                ActivityCompat.requestPermissions(
                    obj,
                    permissionList.toTypedArray(),
                    REQUEST_PERMISSION_CODE
                )
            }
            is Fragment -> {
                obj.requestPermissions(
                    permissionList.toTypedArray(),
                    REQUEST_PERMISSION_CODE
                )
            }
            else -> {
                throw java.lang.IllegalStateException("obj不是一个Fragment或Activity")
            }
        }
    }

    /**
     * 跳转设置页面
     */
    fun <T> gotoSettings(obj: T) {
        when (obj) {
            is Fragment -> {
                val packageURI = Uri.parse("package:" + obj.activity!!.packageName)
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI)
                obj.startActivityForResult(intent, 1)
            }
            is Activity -> {
                val packageURI = Uri.parse("package:" + obj.packageName)
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI)
                obj.startActivityForResult(intent, 2)
            }
            else -> {
                throw IllegalStateException("obj不是一个Fragment或Activity")
            }
        }
    }
}

在Activity中使用;

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

    fun onCallPhone(view: View) {
        doCallPhone()
    }

    private fun doCallPhone() {
        val permissionList = arrayListOf(PermissionUtils.CALL_PHONE, PermissionUtils.CAMERA)
        if (PermissionUtils.isGrantedPermissions(mContext, permissionList)) {
            val callIntent = Intent(Intent.ACTION_CALL).apply {
                data = Uri.parse("tel:" + "1234567890")
            }
            startActivity(callIntent)
        } else {
            PermissionUtils.applyPermission(this, permissionList)
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (PermissionUtils.onRequestPermissionsResult(
                this,
                requestCode,
                permissions,
                grantResults
            )
        ) {
            Toast.makeText(mContext, "权限已全部允许", Toast.LENGTH_SHORT).show()
            doCallPhone()
        }
    }
}

在Fragment中使用:

class MyFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_two, container!!, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.btn_call_phone).setOnClickListener {
            doCallPhone()
        }
    }

    private fun doCallPhone() {
        val permissionList = arrayListOf(PermissionUtils.CALL_PHONE, PermissionUtils.CAMERA)
        if (PermissionUtils.isGrantedPermissions(context!!, permissionList)) {
            val callIntent = Intent(Intent.ACTION_CALL).apply {
                data = Uri.parse("tel:" + "1234567890")
            }
            startActivity(callIntent)
        } else {
            PermissionUtils.applyPermission(this, permissionList)
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (PermissionUtils.onRequestPermissionsResult(
                this,
                requestCode,
                permissions,
                grantResults
            )
        ) {
            Toast.makeText(context, "权限已全部允许", Toast.LENGTH_SHORT).show()
            doCallPhone()
        }
    }
}

第三方权限框架

推荐第三方权限框架:XXPermissionsPermissionX

这里使用 PermissionX 框架:

安装:

dependencies {
    implementation 'com.permissionx.guolindev:permissionx:1.4.0'
}

基本使用:

PermissionX.init(this)
    .permissions(Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION)
    .onExplainRequestReason { scope, deniedList ->
        val message = "拍照功能需要您同意相册和定位权限"
        val ok = "确定"
        scope.showRequestReasonDialog(deniedList, message, ok)
    }
    .onForwardToSettings { scope, deniedList ->
        val message = "您需要去设置当中同意相册和定位权限"
        val ok = "确定"
        scope.showForwardToSettingsDialog(deniedList, message, ok)
    }
    .request { _, _, _ ->
        call()
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android 录屏权限是指用户在使用Android设备时,可以给予应用程序录制屏幕的权限。这样,应用程序就可以在设备屏幕上进行录制,并将其保存为视频文件。 为了保护用户的隐私和安全,Android系统为录屏权限设置了限制。通常情况下,应用程序默认是没有录屏权限的,需要用户在使用应用程序时手动授权。 要在Android应用程序中获取录屏权限,开发者需要在应用的清单文件(Manifest)中添加相应的权限声明,以指示应用程序需要访问录屏功能。例如,可以使用以下代码添加录屏权限声明: ```xml <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" /> ``` 用户在安装或打开应用程序时,系统会显示让用户选择是否授予录屏权限的对话框。用户可以选择授予或拒绝该权限。如果用户授予了权限,应用程序就可以在设备屏幕上进行录制。 需要注意的是,获取录屏权限并不意味着应用程序可以随意录制屏幕。Android系统对录屏权限进行了限制,只有当应用程序处于前台运行状态时,才有权限进行录制。这是为了保护用户的隐私和避免恶意行为。 最后,当应用程序不再需要录屏权限时,开发者应该及时释放这个权限,以提高用户的隐私保护和系统性能。在应用程序中,可以使用以下代码取消录屏权限: ```kotlin revokeUriPermission(/*uri*/) ``` 总结来说,Android 录屏权限是一项重要的功能,可以在屏幕上录制应用程序的操作,并将其保存为视频文件。然而,获取这个权限需要用户手动授权,并且仅允许在应用程序处于前台运行状态时进行录制。开发者在使用录屏权限时需要注意保护用户的隐私和合理使用这项功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值