鸿蒙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. 异步处理:等待用户点选后再执行业务逻辑。

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

相关推荐
Quz1 小时前
QML SwipeDelegate 滑动委托
qt
Quz2 小时前
QML 列表中的四种委托:ItemDelegate、CheckDelegate、RadioDelegate、SwitchDelegate
qt
云运维笔记2 小时前
华为设备IP地址配置全攻略
运维·网络·计算机网络·华为
实心儿儿2 小时前
Qt — 显示类控件
qt
威哥爱编程3 小时前
HarmonyOS 7 星盾机密风控实战:设备风险因子端侧融合计算,可用不可见
harmonyos·arkts
威哥爱编程3 小时前
HarmonyOS 7 应用快启实战:关键资源预加载进内存,冷启告别白屏
华为·harmonyos·arkts
马剑威(威哥爱编程)3 小时前
【共创稿事节】HarmonyOS 7 视觉 AI 进阶实战:人脸检测 + 通用文字识别(OCR)两步接入
华为·harmonyos·arkts
HMS Core16 小时前
HarmonyOS智慧多窗,让应用在任意窗口都“恰到好处”
harmonyos
梦想不只是梦与想16 小时前
鸿蒙 应用发布准备工作(一)
harmonyos·鸿蒙上架·鸿蒙应用发布