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

本次实操验证 HarmonyOS AR Engine 开发的基础链路,完成一个可在真机运行的"AR Engine 能力检测"应用。
实验范围包括:
- 检测设备支持的 AR 能力;
- 申请并复核相机权限;
- 创建 WORLD 类型 AR 会话,显示真实相机画面;
- 验证 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 会话初始化→生命周期管理"的完整链路。当前工程可作为后续平面识别与模型放置实验的基础工程。