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

华为HarmonyOS设备中shouldShowRequestPermissionRationale函数异常问题

华为HarmonyOS设备上shouldShowRequestPermissionRationale行为异常的解决方法

问题描述

开发需申请相机权限的应用时,在华为HarmonyOS设备上发现shouldShowRequestPermissionRationale()函数行为不符合Android官方文档预期:

  • 异常场景:首次请求相机权限被用户拒绝后,第二次发起请求时,该函数返回false(按文档应返回true),但其他Android设备此步骤返回true。
  • 符合预期的场景:首次授权相机权限后,进入系统设置手动拒绝权限,此时调用该函数返回true。

原因分析

华为HarmonyOS的权限管控逻辑与原生Android存在差异:首次拒绝权限时,系统内部直接将该操作判定为用户"明确拒绝",等同于原生Android中勾选"不再询问"后的拒绝行为,因此shouldShowRequestPermissionRationale()返回false;而原生Android中首次拒绝不会触发这个标记,所以函数返回true。

解决方案

不能单纯依赖shouldShowRequestPermissionRationale()的返回值判断是否需要显示权限说明弹窗,需要自行维护权限拒绝的状态记录,结合函数返回值做综合判断:

  1. 使用SharedPreferences记录权限是否被拒绝过一次的状态。
  2. 发起权限请求前,判断以下任一条件成立则显示权限说明弹窗:
    • shouldShowRequestPermissionRationale()返回true
    • 权限未授权,且已经被拒绝过一次
  3. 权限请求回调中,若权限被拒绝则更新状态记录。
  4. 当用户从应用设置页面返回时,重置状态记录(避免设置中修改权限后状态不匹配)。

修改后的示例代码

package com.example.huaweipermissions

import android.Manifest
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import androidx.appcompat.app.AppCompatActivity
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import com.example.huaweipermissions.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var prefs: SharedPreferences
    private val CAMERA_PERMISSION_DENIED_KEY = "camera_permission_denied"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        prefs = getSharedPreferences("permission_prefs", MODE_PRIVATE)

        binding.button.setOnClickListener {
            launchPermission()
        }
    }

    private fun askForPermissionsDialog() {
        androidx.appcompat.app.AlertDialog.Builder(this)
            .setCancelable(true)
            .setMessage("需要相机权限来完成相关功能,请前往设置开启权限")
            .setPositiveButton("去设置") { dialog, _ ->
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                val uri = Uri.fromParts("package", this.packageName, null)
                intent.data = uri
                settingsLauncher.launch(intent)
                dialog.dismiss()
            }
            .setNegativeButton("取消") { dialog, _ -> dialog.dismiss() }
            .create()
            .show()
    }

    private fun launchPermission() {
        val isPermissionGranted = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == android.content.pm.PackageManager.PERMISSION_GRANTED
        val shouldShowRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
        val isDeniedBefore = prefs.getBoolean(CAMERA_PERMISSION_DENIED_KEY, false)

        // 更新UI显示
        binding.editTextRationale.setText(shouldShowRationale.toString())
        binding.editTextPermission.setText(if (isPermissionGranted) "GRANTED" else "")

        if (shouldShowRationale || (!isPermissionGranted && isDeniedBefore)) {
            askForPermissionsDialog()
        } else {
            requestPermissionLauncher.launch(Manifest.permission.CAMERA)
        }
    }

    // 权限请求回调
    private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
        binding.editTextPermission.setText(if (isGranted) "GRANTED" else "DENIED")
        if (!isGranted) {
            // 标记权限已被拒绝过一次
            prefs.edit().putBoolean(CAMERA_PERMISSION_DENIED_KEY, true).apply()
        } else {
            // 授权成功,重置拒绝标记
            prefs.edit().putBoolean(CAMERA_PERMISSION_DENIED_KEY, false).apply()
        }
    }

    // 设置页面返回后的回调,重置拒绝标记
    private val settingsLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        // 返回后重新检查权限状态
        launchPermission()
        // 重置拒绝标记,避免设置中修改权限后状态不匹配
        prefs.edit().putBoolean(CAMERA_PERMISSION_DENIED_KEY, false).apply()
    }
}

说明

  • 新增的SharedPreferences用于记录权限是否被拒绝过,避免依赖系统函数的异常行为。
  • 从设置页面返回后重置状态,确保后续权限判断的准确性。
  • 权限说明弹窗的文案可以根据实际业务场景调整,明确告知用户权限的用途。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 08:34:54