鸿蒙Qt权限避坑:动态申请与Crash修复

1. 闪退的相机应用

我们编写了一个简单的Qt应用,点击按钮打开摄像头扫描二维码。

在模拟器上运行正常,但在真机上一点击按钮,应用瞬间闪退,没有任何Qt日志输出。

查看系统日志(HiLog),发现了一行关键错误:
SecurityException: Permission denied. req: ohos.permission.CAMERA

2. 鸿蒙的权限模型:ACL与动态申请

OpenHarmony采用了类似于Android 6.0+的动态权限模型。

权限分为:

  1. system_grant (安装时授权):如网络权限。
  2. user_grant (运行时授权):如相机、麦克风、定位。

对于 user_grant 类型的权限,仅仅在 module.json5 中声明是不够的!必须在代码中动态请求用户授权。

权限状态机

API returns 0 API returns -1 Call requestPermissionsFromUser System Popup User Clicks Allow User Clicks Deny Open Camera UI Tip CheckStatus Granted NotGranted RequestPermission UserDialog Denied UseFeature ShowExplanation

3. 解决方案:Qt与ArkTS的配合

Qt本身(截至目前)并没有封装鸿蒙的权限申请API。我们需要通过NAPI调用鸿蒙的 abilityAccessCtrl

第一步:ArkTS侧的桥接

我们在 EntryAbility.ets 或独立的TS模块中暴露一个申请权限的方法。

typescript 复制代码
// PermissionBridge.ts
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';

export async function requestCameraPermission(context: any): Promise<boolean> {
  const atManager = abilityAccessCtrl.createAtManager();
  const result = await atManager.requestPermissionsFromUser(context, ['ohos.permission.CAMERA']);
  
  // 检查授权结果
  if (result.authResults[0] === 0) {
    return true;
  }
  return false;
}

第二步:C++ NAPI封装

我们需要在C++层暴露一个函数给Qt调用,这个函数内部去调用上面的TS方法。

(这里为了简化,假设我们已经通过某种方式(如信号/槽或Native机制)建立好了通信通道)。

Qt侧调用封装:

cpp 复制代码
// PermissionManager.cpp
void PermissionManager::requestCamera(std::function<void(bool)> callback) {
#ifdef Q_OS_OHOS
    // 调用NAPI接口
    // 伪代码:NativeInterface::call("requestCameraPermission", ...)
    // 等待回调...
    bool granted = waitForResult(); 
    callback(granted);
#else
    // Desktop always granted or handled by Qt Multimedia
    callback(true);
#endif
}

第三步:使用 QtAndroidPrivate 的替代品?

在Android Qt开发中,我们有 QtAndroid::requestPermissions

在鸿蒙上,目前没有官方等价类。我们推荐维护一个 HarmonyPermission 单例类,专门处理这些逻辑。

4. 实战Bug:异步陷阱

错误代码:

cpp 复制代码
void onBtnClick() {
    PermissionManager::requestCamera(); 
    // ❌ 错误!请求是异步的,这里直接打开相机依然会崩溃
    camera->start(); 
}

正确代码:

cpp 复制代码
void onBtnClick() {
    PermissionManager::instance()->requestCamera([this](bool granted) {
        if (granted) {
            // ✅ 在回调中启动,且最好切回主线程
            QMetaObject::invokeMethod(this, [this](){
                camera->start();
            });
        } else {
            QMessageBox::warning(this, "Error", "Camera permission denied!");
        }
    });
}

5. 配置文件别忘了

在写代码之前,必须先在 entry/src/main/module.json5 中声明。

json 复制代码
"requestPermissions": [
  {
    "name": "ohos.permission.CAMERA",
    "reason": "$string:camera_reason",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "inuse"
    }
  }
]

注意:reason 字段必须指向一个字符串资源,不能直接写硬编码字符串,否则编译或安装会报错。

6. 总结

鸿蒙的权限管理非常严格。

  1. 查文档 :确定权限是 system_grant 还是 user_grant
  2. 写配置module.json5 必不可少。
  3. 动态申请 :对于敏感权限,必须在运行时调用 requestPermissionsFromUser
  4. 异步处理:等待用户点选后再执行业务逻辑。

处理好权限问题,是应用上架华为应用市场的基本要求。

相关推荐
youtootech8 小时前
HarmonyOS《柚兔学伴》项目实战25-我的页面、Web 嵌入与项目总结
前端·华为·harmonyos
三声三视9 小时前
uni-app 鸿蒙端传参变成 [object Object]?顺着源码追到 ArkTS router 底层才搞明白
人工智能·ai·uni-app·aigc·ai编程·harmonyos
达子6669 小时前
第7章_HarmonyOS 图解 Ability公共事件与通知
华为·harmonyos
爱写代码的阿森9 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
爱写代码的阿森11 小时前
鸿蒙三方库 | harmony-utils之PreferencesUtil用户首选项读写详解
华为·harmonyos·鸿蒙·huawei
达子66612 小时前
第6章_HarmonyOS 图解 Ability任务调度
华为·harmonyos
FrameNotWork12 小时前
HarmonyOS 6.0 分栏布局与折叠适配
华为·harmonyos
爱写代码的阿森12 小时前
鸿蒙三方库 | harmony-utils之PreferencesUtil首选项数据监听详解
服务器·华为·harmonyos·鸿蒙·huawei
爱写代码的森12 小时前
蒙三方库 | harmony-utils之FileUtil文件重命名与属性查询详解
linux·运维·服务器·华为·harmonyos·鸿蒙·huawei
二流小码农13 小时前
鸿蒙开发:以登录案例了解代码架构MVVM
android·ios·harmonyos