You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android麦克风权限请求陷入无限循环问题求助

解决麦克风权限请求无限循环问题

问题原因

当用户两次拒绝麦克风权限并勾选「不再询问」后,shouldShowRequestPermissionRationale()会返回false,此时调用requestPermissions()不会弹出系统权限弹窗,直接触发onRequestPermissionsResult返回未授权状态。由于checkPermissions()在onResume()中被调用,权限回调后页面回到onResume,再次触发权限请求,形成无限循环。

解决方案

核心思路是:识别权限被永久拒绝的状态,避免重复发起无效的系统权限请求,转而引导用户前往应用设置手动开启权限。

1. 新增永久权限拒绝判断方法

private fun isPermissionPermanentlyDenied(permission: String): Boolean {
    return !ActivityCompat.shouldShowRequestPermissionRationale(this, permission) &&
            ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED
}

2. 修改权限检查逻辑

private fun checkPermissions() {
    val recordAudioPermission = Manifest.permission.RECORD_AUDIO
    if (ContextCompat.checkSelfPermission(this, recordAudioPermission) == PackageManager.PERMISSION_GRANTED) {
        checkSignIn()
    } else {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, recordAudioPermission)) {
            explainRecordingRequest()
        } else {
            // 判断是否为永久拒绝,是则引导去设置,否则发起权限请求
            if (isPermissionPermanentlyDenied(recordAudioPermission)) {
                showGoToSettingsDialog()
            } else {
                ActivityCompat.requestPermissions(this@MainActivity, arrayOf(recordAudioPermission), 1000)
            }
        }
    }
}

3. 添加引导至设置的对话框

private fun showGoToSettingsDialog() {
    val builder = AlertDialog.Builder(this)
    builder.setTitle("需要麦克风权限")
        .setMessage("您已永久拒绝麦克风权限,请前往应用设置开启,否则无法使用相关功能")
        .setPositiveButton("去设置") { _, _ ->
            // 跳转至应用详情设置页
            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
            val uri = Uri.fromParts("package", packageName, null)
            intent.data = uri
            startActivity(intent)
        }
        .setNegativeButton("取消", null)
    builder.create().show()
}

4. 更新权限回调处理

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    Timber.d("FLOW: received req=$requestCode, len(grants)=${grantResults.size}")
    when (requestCode) {
        1000 -> {
            val permission = permissions[0]
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Timber.d("FLOW: ...granted")
                checkSignIn()
            } else {
                Timber.d("FLOW: ...not granted")
                // 权限被拒绝时,检查是否为永久拒绝
                if (isPermissionPermanentlyDenied(permission)) {
                    showGoToSettingsDialog()
                }
            }
        }
        else -> {
            Timber.e("FLOW: unhandled permission request for $requestCode")
        }
    }
}

额外优化建议

避免在onResume()中每次都触发权限检查,可改为在进入需要权限的功能页、用户主动触发相关操作时再调用checkPermissions(),减少不必要的请求触发。

内容的提问来源于stack exchange,提问作者Yanay Lehavi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:38:12