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模块中暴露一个申请权限的方法。

// 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侧调用封装:

// 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:异步陷阱

错误代码:

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

正确代码:

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 中声明。

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

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

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐