HarmonyOS 6.0 照相机拍照实战—— 从拍照到保存一步到位
本文介绍了在HarmonyOS 6.0中使用ArkUI和ArkTS实现相机拍照功能的完整流程。文章首先强调了相机权限配置的重要性,详细说明了如何在配置文件中声明相机和存储权限。接着提供了基础版拍照功能的实现代码,包括相机预览、拍照按钮和照片显示功能,并解释了核心逻辑如权限申请、Camera组件绑定和拍照方法调用。最后还介绍了进阶功能,包括保存照片到相册和切换前后摄像头。整个教程采用通俗易懂的方式,
日常开发中,拍照功能是很多HarmonyOS App的核心需求(比如相册、扫码、证件照App)。
今天就用最易懂的方式,教你用ArkUI+ArkTS在HarmonyOS 6.0里实现“打开相机→预览→拍照→显示/保存照片”的完整流程,新手也能一看就会!
核心知识点先理清
不用记复杂概念,先搞懂3个核心“工具”:
- Camera组件:ArkUI官方封装的相机组件,负责实时预览相机画面、触发拍照,是实现拍照的核心;
- CameraController:相机控制器,用来手动触发拍照、切换前后摄像头、调整拍摄参数;
- 权限配置:相机是敏感权限,必须先在配置文件里声明,运行时还要用户授权,否则相机打不开。
第一步:准备环境
- 确保DevEco Studio升级到支持HarmonyOS 6.0的版本(建议4.1及以上);
- 新建一个Stage模型的ArkTS工程(新手优先选这个,兼容性最好);
- 准备一台HarmonyOS 6.0真机(模拟器没有相机功能,必须用真机测试!)。
第二步:配置核心权限
相机和照片存储都需要权限,先在module.json5文件里声明:
{
"module": {
// 其他默认配置...
"requestPermissions": [
{
"name": "ohos.permission.CAMERA", // 相机权限(必须)
"reason": "需要使用相机拍照", // 授权说明(给用户看)
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.WRITE_MEDIA_PHOTOS", // 写入照片权限(保存用)
"reason": "需要保存拍摄的照片到相册",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.READ_MEDIA_PHOTOS", // 读取照片权限(可选)
"reason": "需要读取相册照片",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
]
}
}
第三步:基础版拍照(预览+拍照+显示照片)
先实现最核心的功能:打开相机预览→点击按钮拍照→在页面上显示拍好的照片。
完整代码
// index.ets
@Entry
@Component
struct CameraPage {
// 1. 定义相机控制器
private cameraController: CameraController = new CameraController()
// 2. 存储拍摄的照片数据(用于显示)
@State photoData: PixelMap | null = null
// 3. 标记是否授权成功
@State isCameraAuthorized: boolean = false
build() {
Column() {
// 第一步:先申请相机权限
if (!this.isCameraAuthorized) {
Button('点击授权相机权限')
.onClick(() => {
this.requestCameraPermission()
})
.margin(20)
} else {
// 第二步:相机预览区域(核心)
Camera({
controller: this.cameraController // 绑定控制器
})
.width('100%') // 预览区域宽度占满屏幕
.height(400) // 预览区域高度400vp
.marginBottom(20)
// 第三步:拍照按钮
Button('点击拍照')
.onClick(() => {
this.takePhoto()
})
.marginBottom(20)
// 第四步:显示拍摄的照片
if (this.photoData) {
Image(this.photoData)
.width('100%')
.height(200)
.borderRadius(10)
.marginTop(10)
Text('拍摄的照片预览')
.fontSize(14)
.marginTop(5)
}
}
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#f5f5f5')
.justifyContent(FlexAlign.Center)
}
// 【辅助方法1】申请相机权限
async requestCameraPermission() {
try {
// 申请相机权限
const result = await requestPermissionsFromUser(['ohos.permission.CAMERA'])
// 判断授权结果(授权成功返回true)
this.isCameraAuthorized = result[0] === 0
if (this.isCameraAuthorized) {
console.log('相机权限授权成功!')
} else {
console.log('相机权限授权失败,无法使用相机')
}
} catch (e) {
console.log('申请权限出错:', e)
}
}
// 【辅助方法2】触发拍照
async takePhoto() {
try {
// 调用控制器的拍照方法,获取照片数据
const photoResult = await this.cameraController.capturePhoto({
quality: CameraPhotoQuality.NORMAL // 拍摄质量:普通(可选HIGH/LOW)
})
// 将照片数据转换成PixelMap(用于Image组件显示)
this.photoData = photoResult.pixelMap
console.log('拍照成功!')
} catch (e) {
console.log('拍照失败:', e)
}
}
}
代码逐行解释(重点)
- 权限申请:
requestCameraPermission方法通过requestPermissionsFromUser向用户申请相机权限,只有授权成功才能显示相机预览; - Camera组件:绑定控制器后,就能实时显示相机画面,宽高可以根据需求调整;
- 拍照逻辑:
capturePhoto方法触发拍照,指定拍摄质量(NORMAL/LOW/HIGH),返回的photoResult包含照片的PixelMap数据; - 照片显示:把PixelMap数据传给Image组件,就能在页面上看到拍好的照片。
运行效果
- 打开App,点击“授权相机权限”,在弹窗里选择“允许”;
- 页面显示相机实时预览画面;
- 点击“拍照”按钮,下方立刻显示刚拍的照片。
第四步:进阶玩法(保存照片到相册+切换前后摄像头)
基础版只能临时显示照片,退出App就没了;还想切换前后摄像头?这部分教你实现!
完整进阶代码
// index.ets
import image from '@ohos.multimedia.image'; // 导入图片处理库
import photoAccessHelper from '@ohos.file.photoAccessHelper'; // 导入相册操作库
@Entry
@Component
struct AdvancedCameraPage {
private cameraController: CameraController = new CameraController()
@State photoData: PixelMap | null = null
@State isCameraAuthorized: boolean = false
@State currentCamera: string = 'back' // 当前摄像头:back(后置)/front(前置)
build() {
Column() {
if (!this.isCameraAuthorized) {
Button('点击授权相机+存储权限')
.onClick(() => {
this.requestAllPermissions()
})
.margin(20)
} else {
// 相机预览
Camera({
controller: this.cameraController,
position: this.currentCamera === 'back' ? CameraPosition.BACK : CameraPosition.FRONT
})
.width('100%')
.height(400)
.marginBottom(20)
// 控制按钮区域
Row() {
// 切换摄像头按钮
Button(`切换${this.currentCamera === 'back' ? '前置' : '后置'}摄像头`)
.onClick(() => {
this.switchCamera()
})
.margin(10)
// 拍照按钮
Button('拍照')
.onClick(() => {
this.takePhotoAndSave()
})
.margin(10)
}
.justifyContent(FlexAlign.Center)
// 照片预览
if (this.photoData) {
Image(this.photoData)
.width('100%')
.height(200)
.borderRadius(10)
.marginTop(20)
Text('拍摄的照片(已保存到相册)')
.fontSize(14)
.marginTop(5)
}
}
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#f5f5f5')
.justifyContent(FlexAlign.Center)
}
// 申请相机+存储权限
async requestAllPermissions() {
try {
const permissions = ['ohos.permission.CAMERA', 'ohos.permission.WRITE_MEDIA_PHOTOS']
const result = await requestPermissionsFromUser(permissions)
this.isCameraAuthorized = result[0] === 0 && result[1] === 0
if (this.isCameraAuthorized) {
console.log('相机+存储权限授权成功!')
} else {
console.log('权限授权失败')
}
} catch (e) {
console.log('申请权限出错:', e)
}
}
// 切换前后摄像头
switchCamera() {
try {
this.currentCamera = this.currentCamera === 'back' ? 'front' : 'back'
// 调用控制器切换摄像头
this.cameraController.switchCamera(this.currentCamera === 'back' ? CameraPosition.BACK : CameraPosition.FRONT)
console.log(`切换到${this.currentCamera}摄像头成功`)
} catch (e) {
console.log('切换摄像头失败:', e)
}
}
// 拍照并保存到相册
async takePhotoAndSave() {
try {
// 1. 拍照获取照片数据
const photoResult = await this.cameraController.capturePhoto({
quality: CameraPhotoQuality.HIGH // 高质量拍摄
})
this.photoData = photoResult.pixelMap
// 2. 将PixelMap转换成文件流,保存到相册
const context = getContext(this) as any
const helper = photoAccessHelper.getPhotoAccessHelper(context)
// 创建照片保存的参数
const photoSaveOptions = {
title: `IMG_${new Date().getTime()}.jpg`, // 照片命名(时间戳避免重复)
tags: ['camera_photo'], // 标签(可选)
mimeType: 'image/jpeg' // 格式
}
// 创建保存的文件
const photoUri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, photoSaveOptions)
// 获取文件写入流
const file = await helper.openAsset(photoUri, 'w')
// 将PixelMap编码成JPEG格式并写入文件
const encodeOptions = { format: image.ImageFormat.JPEG, quality: 100 }
const buffer = await photoResult.pixelMap.encodeToBuffer(encodeOptions)
await file.write(buffer)
// 关闭文件流
await file.close()
console.log('照片保存到相册成功!')
} catch (e) {
console.log('拍照/保存失败:', e)
}
}
}
核心进阶功能解释
- 切换前后摄像头:
- 通过
CameraPosition.BACK/FRONT指定摄像头; - 调用
cameraController.switchCamera方法切换,简单又高效;
- 通过
- 保存照片到相册:
- 导入
photoAccessHelper库操作相册; - 用时间戳给照片命名,避免重复;
- 将拍照得到的PixelMap编码成JPEG格式,写入相册文件中;
- 导入
- 高质量拍摄:把
quality设为CameraPhotoQuality.HIGH,拍出来的照片更清晰(代价是文件更大)。
避坑指南(新手必看)
- 模拟器无法测试:HarmonyOS模拟器没有相机硬件,必须用真机!
- 权限授权失败:
- 一定要在
module.json5里声明权限,且reason不能空; - 运行时用户如果拒绝授权,要提示用户去设置里开启;
- 一定要在
- 保存照片失败:
- 必须申请
WRITE_MEDIA_PHOTOS权限,否则无法写入相册; - 照片命名不能有特殊字符,建议用时间戳;
- 必须申请
- 切换摄像头失败:
- 部分设备没有前置摄像头,要加异常处理;
- 切换前确保相机已经正常预览(权限已授权)。
总结
HarmonyOS 6.0实现拍照功能的核心流程就3步:
- 配置并申请相机/存储权限;
- 用Camera组件显示预览,CameraController控制拍摄/切换摄像头;
- 处理照片数据(显示/保存到相册)。
如果大家想考取鸿蒙开发者认证的,欢迎加入我的专属考试链接中:https://developer.huawei.com/consumer/cn/training/classDetail/6ce9d5a998724a849ec634f318107d37?type=1?ha_source=hmosclass&ha_sourceId=89000248
新手先从基础版跑通“拍照+显示”,再逐步加保存、切换摄像头的功能,一步步来,很快就能掌握!
如果想实现扫码、美颜拍照等进阶功能,评论区说,咱们再补充~
更多推荐



所有评论(0)