HarmonyOS AR Engine 入门实操:从设备检测到会话管理

HarmonyOS AR Engine 入门实操:从设备检测到会话管理

本次实操验证 HarmonyOS AR Engine 开发的基础链路,完成一个可在真机运行的"AR Engine 能力检测"应用。

实验范围包括:

  1. 检测设备支持的 AR 能力;
  2. 申请并复核相机权限;
  3. 创建 WORLD 类型 AR 会话,显示真实相机画面;
  4. 验证 AR 会话的暂停、恢复和销毁。

平面命中、模型放置、深度与 Mesh 识别不在本次实验范围内。

文中手机界面均来自 Mate 60 Pro 真机。封面和流程图用于说明实验内容,不作为真机运行证据。

一、实验环境与准备

1. 软硬件环境

项目 实验环境
开发语言 ArkTS
工程类型 HarmonyOS Phone
SDK API 26
真机 HUAWEI Mate 60 Pro(ALN-AL80)
系统 HarmonyOS 7.0.0.100
Bundle Name com.example.csdn

通过 HDC 检查真机连接:

powershell 复制代码
& 'D:\Program Files\Huawei\DevEco Studio\sdk\default\openharmony\toolchains\hdc.exe' list targets

本次返回的设备序列号为:

text 复制代码
29Q0223822023064

2. 权限准备

AR 会话使用相机、加速计和陀螺仪。工程在 entry/src/main/module.json5 中声明三项权限:

json5 复制代码
"requestPermissions": [
  {
    "name": "ohos.permission.CAMERA",
    "reason": "$string:permission_reason_camera",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "inuse"
    }
  },
  {
    "name": "ohos.permission.ACCELEROMETER",
    "reason": "$string:permission_reason_accelerometer",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "inuse"
    }
  },
  {
    "name": "ohos.permission.GYROSCOPE",
    "reason": "$string:permission_reason_gyroscope",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "inuse"
    }
  }
]

entry/src/main/resources/base/element/string.json 中配置权限用途说明:

json 复制代码
{
  "string": [
    {
      "name": "permission_reason_camera",
      "value": "用于在 AR 场景中获取相机预览画面"
    },
    {
      "name": "permission_reason_accelerometer",
      "value": "用于 AR 会话感知设备运动状态"
    },
    {
      "name": "permission_reason_gyroscope",
      "value": "用于 AR 会话感知设备姿态变化"
    }
  ]
}

加速计和陀螺仪属于 system_grant;相机属于 user_grant,除了在配置文件中声明,还需运行时授权。

二、实操过程

1. 检测设备 AR 能力

首页通过 arViewController.isARTypeSupported() 检测八类 AR 特性:SLAM、DEPTH、MESH、IMAGE、SEMANTIC_DENSE、SEMANTIC、FACE 和 BODY。

Index.ets 中定义能力数据结构:

ArkTS/ets 复制代码
import { arEngine, arViewController } from '@kit.AREngine';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const DOMAIN: number = 0x0000;
const TAG: string = 'AREngineLab';

interface FeatureItem {
  title: string;
  description: string;
  type: arEngine.ARFeatureType;
  supported: boolean;
  checked: boolean;
  error: string;
}

八类能力使用同一数据结构组织:

ArkTS/ets 复制代码
private createFeatureList(): FeatureItem[] {
  return [
    {
      title: 'SLAM', description: '运动跟踪与平面识别',
      type: arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_SLAM,
      supported: false, checked: false, error: ''
    },
    {
      title: 'DEPTH', description: '深度估计',
      type: arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_DEPTH,
      supported: false, checked: false, error: ''
    },
    {
      title: 'MESH', description: '环境 Mesh 识别',
      type: arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_MESH,
      supported: false, checked: false, error: ''
    },
    {
      title: 'IMAGE', description: '图像跟踪',
      type: arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_IMAGE,
      supported: false, checked: false, error: ''
    },
    {
      title: 'SEMANTIC_DENSE', description: '高精几何重建',
      type: arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_SEMANTIC_DENSE,
      supported: false, checked: false, error: ''
    },
    {
      title: 'SEMANTIC', description: '平面与物体语义',
      type: arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_SEMANTIC,
      supported: false, checked: false, error: ''
    },
    {
      title: 'FACE', description: '人脸识别与跟踪',
      type: arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_FACE,
      supported: false, checked: false, error: ''
    },
    {
      title: 'BODY', description: '人体骨骼点识别与跟踪',
      type: arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_BODY,
      supported: false, checked: false, error: ''
    }
  ];
}

逐项检测时单独捕获异常,某一项失败不会中断整个列表:

ArkTS/ets 复制代码
private checkAllFeatures(): void {
  let next: FeatureItem[] = this.createFeatureList();
  let supportedCount: number = 0;

  next.forEach((item: FeatureItem) => {
    try {
      item.supported = arViewController.isARTypeSupported(item.type);
      item.checked = true;
      if (item.supported) {
        supportedCount += 1;
      }
      hilog.info(DOMAIN, TAG,
        'AR_FEATURE %{public}s=%{public}s',
        item.title, `${item.supported}`);
    } catch (error) {
      const err: BusinessError = error as BusinessError;
      item.checked = true;
      item.supported = false;
      item.error = `检测失败:${err.code}`;
    }
  });

  this.features = next;
  this.supportSummary = `${supportedCount}/8 支持`;
}

aboutToAppear(): void {
  this.checkAllFeatures();
}

Mate 60 Pro 首次启动后返回 8/8 支持

本次 WORLD 会话直接依赖 SLAM,其他七项结果作为设备能力记录。

2. 申请并复核相机权限

相机权限由页面按钮触发。授权完成后,程序通过应用 accessTokenId 再次检查实际授权状态。

ArkTS/ets 复制代码
import {
  abilityAccessCtrl,
  bundleManager,
  Permissions
} from '@kit.AbilityKit';

const CAMERA_PERMISSION: Permissions = 'ohos.permission.CAMERA';

private async requestCameraPermission(): Promise<void> {
  try {
    await abilityAccessCtrl.createAtManager()
      .requestPermissionsFromUser(this.context, [CAMERA_PERMISSION]);

    this.cameraGranted = this.hasCameraPermission();
    this.permissionState = this.cameraGranted ?
      'PERMISSION_GRANTED' : '用户未授予相机权限';

    hilog.info(DOMAIN, TAG,
      'CAMERA_PERMISSION granted=%{public}s',
      `${this.cameraGranted}`);
  } catch (error) {
    const err: BusinessError = error as BusinessError;
    this.cameraGranted = false;
    this.permissionState = `申请失败:${err.code}`;
  }
}

private hasCameraPermission(): boolean {
  try {
    const tokenId: number = bundleManager.getBundleInfoForSelfSync(
      bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION
    ).appInfo.accessTokenId;

    return abilityAccessCtrl.createAtManager()
      .checkAccessTokenSync(tokenId, CAMERA_PERMISSION) ===
      abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
  } catch (error) {
    return false;
  }
}

执行权限申请后,HarmonyOS 显示系统相机授权弹窗:

授权后页面状态变为 PERMISSION_GRANTED,AR 会话入口同时激活:

3. 增加 AR 会话入口门禁

WORLD 会话启动前同时检查相机权限和 SLAM 支持状态:

ArkTS/ets 复制代码
private canStartAR(): boolean {
  const slam: FeatureItem | undefined = this.features.find(
    (item: FeatureItem) =>
      item.type === arEngine.ARFeatureType.ARENGINE_FEATURE_TYPE_SLAM
  );

  return this.cameraGranted &&
    slam !== undefined &&
    slam.supported;
}

private startARSession(): void {
  if (!this.cameraGranted) {
    this.latestMessage =
      '拦截成功:未获得相机权限,不初始化 AR 会话。';
    return;
  }

  if (!this.canStartAR()) {
    this.latestMessage =
      '拦截成功:当前设备不支持 SLAM,不初始化 AR 会话。';
    return;
  }

  this.showARSession = true;
}

反向实验中重置相机权限,再直接进入 AR 会话。页面停留在首页并输出拦截信息,Hilog 中没有出现 AR_SESSION_INIT

4. 创建 WORLD 类型 AR 会话

entry/src/main/ets/features/arengine/ARSessionPage.ets 负责 AR 会话创建与显示。

ArkTS/ets 复制代码
import {
  arEngine,
  ARView,
  arViewController
} from '@kit.AREngine';
import { Scene } from '@kit.ArkGraphics3D';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

会话配置使用 WORLD 类型,检测水平面和垂直面,使用重力坐标和自动对焦。深度、Mesh 与语义能力在本实验中关闭。

ArkTS/ets 复制代码
private async initARView(): Promise<void> {
  let pendingContext:
    arViewController.ARViewContext | undefined = undefined;

  try {
    const startTime: number = Date.now();
    const scene: Scene = await Scene.load();

    pendingContext = new arViewController.ARViewContext();
    pendingContext.scene = scene;
    pendingContext.config = {
      type: arEngine.ARType.WORLD,
      planeFindingMode:
        arEngine.ARPlaneFindingMode.HORIZONTAL_AND_VERTICAL,
      powerMode: arEngine.ARPowerMode.NORMAL,
      semanticMode: arEngine.ARSemanticMode.NONE,
      poseMode: arEngine.ARPoseMode.GRAVITY,
      depthMode: arEngine.ARDepthMode.DISABLED,
      meshMode: arEngine.ARMeshMode.DISABLED,
      focusMode: arEngine.ARFocusMode.AUTO
    };

    await pendingContext.init();

    this.arContext = pendingContext;
    this.sessionState = '初始化成功';
    this.detail =
      `AR 会话已建立,耗时 ${Date.now() - startTime} ms。`;

    hilog.info(DOMAIN, TAG,
      'AR_SESSION_INIT success costMs=%{public}d',
      Date.now() - startTime);
  } catch (error) {
    const err: BusinessError = error as BusinessError;
    this.sessionState = '初始化失败';
    this.detail = `错误码 ${err.code}:${err.message}`;

    if (pendingContext) {
      await pendingContext.destroy();
    }
  }
}

aboutToAppear(): void {
  this.initARView();
}

init() 成功后,ARViewContext 交给 ARView 渲染:

ArkTS/ets 复制代码
if (this.arContext) {
  ARView({ context: this.arContext })
    .width('100%')
    .height('100%')
}

真机进入 AR 页后出现真实相机预览,页面状态为"运行中",本次初始化耗时 26 ms:

5. 管理 AR 会话生命周期

AR 页提供暂停、恢复和销毁操作。

暂停会话:

ArkTS/ets 复制代码
private pauseARView(): void {
  if (!this.arContext || this.isDestroyed || this.isPaused) {
    return;
  }

  try {
    this.arContext.pause();
    this.isPaused = true;
    this.sessionState = '已暂停';
    this.detail =
      '已调用 ARViewContext.pause(),相机跟踪与 AR 场景渲染暂停。';
    hilog.info(DOMAIN, TAG, 'AR_SESSION_PAUSE success');
  } catch (error) {
    this.recordLifecycleError('pause', error as BusinessError);
  }
}

恢复会话:

ArkTS/ets 复制代码
private resumeARView(): void {
  if (!this.arContext || this.isDestroyed || !this.isPaused) {
    return;
  }

  try {
    this.arContext.resume();
    this.isPaused = false;
    this.sessionState = '运行中';
    this.detail =
      '已调用 ARViewContext.resume(),相机跟踪与 AR 场景渲染恢复。';
    hilog.info(DOMAIN, TAG, 'AR_SESSION_RESUME success');
  } catch (error) {
    this.recordLifecycleError('resume', error as BusinessError);
  }
}

销毁会话:

ArkTS/ets 复制代码
private async destroyARView(): Promise<void> {
  if (!this.arContext || this.isDestroyed) {
    return;
  }

  const context: arViewController.ARViewContext = this.arContext;
  this.isDestroyed = true;

  try {
    await context.destroy();
    this.arContext = undefined;
    this.sessionState = '已销毁';
    this.detail =
      '已调用 ARViewContext.destroy(),相机与 AR 场景资源已释放。';
    hilog.info(DOMAIN, TAG, 'AR_SESSION_DESTROY success');
  } catch (error) {
    this.recordLifecycleError('destroy', error as BusinessError);
  }
}

aboutToDisappear(): void {
  this.destroyARView();
}

执行销毁后页面返回能力检测首页,系统相机占用指示消失:

三、构建与真机运行

项目在 DevEco Studio Terminal 中执行 clean 签名构建:

powershell 复制代码
$env:JAVA_HOME='D:\Program Files\Huawei\DevEco Studio\jbr'
$env:DEVECO_SDK_HOME='D:\Program Files\Huawei\DevEco Studio\sdk'
$env:Path="$env:JAVA_HOME\bin;$env:Path"

$hvigor='D:\Program Files\Huawei\DevEco Studio\tools\hvigor\bin\hvigorw.bat'

& $hvigor clean --no-daemon
& $hvigor assembleHap --mode module `
  -p product=default `
  -p module=entry@default `
  -p buildMode=debug `
  --no-daemon

构建结果:

text 复制代码
CompileArkTS success
PackageHap success
SignHap success
BUILD SUCCESSFUL

签名包位置:

text 复制代码
entry/build/default/outputs/default/entry-default-signed.hap

通过 HDC 安装并启动:

powershell 复制代码
$hdc='D:\Program Files\Huawei\DevEco Studio\sdk\default\openharmony\toolchains\hdc.exe'
$hap='entry\build\default\outputs\default\entry-default-signed.hap'

& $hdc install -r $hap
& $hdc shell aa start -a EntryAbility -b com.example.csdn

四、实操中出现的情况与处理

1. 已声明 CAMERA,首次启动仍为未授权

module.json5 中声明 CAMERA 只表示应用需要该权限,不会直接完成用户授权。

处理方式是由按钮调用 requestPermissionsFromUser(),并在弹窗结束后通过 checkAccessTokenSync() 复核,最终页面状态为 PERMISSION_GRANTED

2. 未授权时直接进入 AR 页

在反向实验中,使用以下命令重置应用权限:

powershell 复制代码
$hdc='D:\Program Files\Huawei\DevEco Studio\sdk\default\openharmony\toolchains\hdc.exe'
& $hdc shell atm perm -r -b com.example.csdn

直接执行 AR 入口后,权限门禁在 init() 前停止流程,页面输出"未获得相机权限",Hilog 中没有 AR 会话初始化记录。

3. 设备 AR 能力存在型号差异

AR 能力不使用固定预设结果,而是在运行时逐项调用 isARTypeSupported()。WORLD 会话只在 SLAM 返回 true 时启动;对于错误码 801 或不支持结果,页面保留检测结果并终止初始化。

4. AR 页按钮与状态卡发生重叠

首轮真机截图中,生命周期按钮和顶部状态卡使用了同一叠加区域。处理时将按钮容器改为全高 Column,并使用 justifyContent(FlexAlign.End) 固定在页面底部。重新构建后,状态卡、相机预览和底部按钮显示正常。

5. 离开 AR 页时需要释放相机

仅依赖"销毁并退出"按钮会遗漏系统返回等页面离开路径。项目同时在 aboutToDisappear() 调用 destroyARView(),并使用 isDestroyed 防止重复销毁。返回首页后,系统相机占用指示消失。

五、最终效果与验证结果

实验最终形成两个页面:

  • 首页展示设备信息、相机权限、八类 AR 能力和最新实验状态;
  • AR 页显示真实相机预览、会话状态以及暂停、恢复、销毁操作。

最终真机验证结果:

验证项 结果
HDC 连接 Mate 60 Pro 设备在线
clean 签名构建 成功,CompileArkTS、PackageHap、SignHap 全部通过,零告警
AR 能力检测 SLAM、DEPTH、MESH、IMAGE、SEMANTIC_DENSE、SEMANTIC、FACE、BODY 均为 true
未授权入口 init() 前拦截,无 AR 会话初始化日志
相机权限 系统弹窗正常,授权复核为 PERMISSION_GRANTED
AR 会话 初始化成功,显示真实相机预览,耗时 26 ms
暂停与恢复 页面状态和 Hilog 记录一致
销毁 返回首页,相机资源释放

生命周期 Hilog 记录:

text 复制代码
AR_SESSION_INIT success costMs=26
AR_SESSION_PAUSE success
AR_SESSION_RESUME success
AR_SESSION_DESTROY success
CAMERA_PERMISSION granted=true

本次实操完成了"能力检测→权限申请→启动门禁→AR 会话初始化→生命周期管理"的完整链路。当前工程可作为后续平面识别与模型放置实验的基础工程。

官方参考资料

相关推荐
YM52e1 小时前
语言地区选择器-鸿蒙ArkTS国际化页面设计
学习·华为·harmonyos
旭日猎鹰2 小时前
鸿蒙日志采集命令
华为·harmonyos
OH_TPC2 小时前
HarmonyOS APP开发---"商品秀"电商App,需要用到这个库
harmonyos
特立独行的猫A3 小时前
Rust+Tauri 调用系统原生能力完全指南:桌面 / Android / iOS / HarmonyOS
harmonyos
柠落少女24405 小时前
HarmonyOS ArKTS API 24深度
react native·华为·harmonyos
yuqinyunliu6 小时前
AR远程协助公司发展现状-差异化竞争与未来趋势
ar
思维新观察6 小时前
装机突破8000万台!鸿蒙有望冲刺年度1亿台目标
华为·harmonyos
见山是山-见水是水7 小时前
鸿蒙Panel 滑动面板完全指南:半屏/全屏切换、拖拽交互与地图应用
华为·交互·harmonyos
丁常彦-自媒体-常言道8 小时前
工业强桂深化AI与制造业融合,华为助力广西共筑新型工业化高地
人工智能·华为