华为HarmonyOS设备中shouldShowRequestPermissionRationale函数异常问题
华为HarmonyOS设备上
shouldShowRequestPermissionRationale行为异常的解决方法 问题描述
开发需申请相机权限的应用时,在华为HarmonyOS设备上发现shouldShowRequestPermissionRationale()函数行为不符合Android官方文档预期:
- 异常场景:首次请求相机权限被用户拒绝后,第二次发起请求时,该函数返回
false(按文档应返回true),但其他Android设备此步骤返回true。 - 符合预期的场景:首次授权相机权限后,进入系统设置手动拒绝权限,此时调用该函数返回
true。
原因分析
华为HarmonyOS的权限管控逻辑与原生Android存在差异:首次拒绝权限时,系统内部直接将该操作判定为用户"明确拒绝",等同于原生Android中勾选"不再询问"后的拒绝行为,因此shouldShowRequestPermissionRationale()返回false;而原生Android中首次拒绝不会触发这个标记,所以函数返回true。
解决方案
不能单纯依赖shouldShowRequestPermissionRationale()的返回值判断是否需要显示权限说明弹窗,需要自行维护权限拒绝的状态记录,结合函数返回值做综合判断:
- 使用
SharedPreferences记录权限是否被拒绝过一次的状态。 - 发起权限请求前,判断以下任一条件成立则显示权限说明弹窗:
shouldShowRequestPermissionRationale()返回true- 权限未授权,且已经被拒绝过一次
- 权限请求回调中,若权限被拒绝则更新状态记录。
- 当用户从应用设置页面返回时,重置状态记录(避免设置中修改权限后状态不匹配)。
修改后的示例代码
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
相关产品推荐
相关产品推荐

