HarmonyOS鸿蒙Next中Cannot read property appId of null
HarmonyOS鸿蒙Next中Cannot read property appId of null 我将相机拍摄生成的照片存储到相册里面,准备使用弹窗来存储照片,但是无法调出弹窗,并且控制台有一个error提示:Cannot read property appId of null
下面是保存图片的代码:
async savePhoto(buffer: ArrayBuffer): Promise<void> {
const phHelper = this.photoAccessHelper;
const context = getContext(this) as common.UIAbilityContext;
if (!phHelper || !context) {
console.error('PhotoAccessHelper or UIContext is not available.');
return;
}
const tempFilePath = `${context.filesDir}/temp_${new Date().getTime()}.jpg`;
let srcFile: fs.File | undefined = undefined;
try {
srcFile = await fs.open(tempFilePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
await fs.write(srcFile.fd, buffer);
} catch (err) {
console.error(`创建或写入临时文件失败: ${JSON.stringify(err)}`);
if (srcFile) await fs.close(srcFile);
return;
} finally {
if (srcFile) await fs.close(srcFile);
}
let desFile: fs.File | undefined = undefined;
try {
const srcFileUri = `file://${tempFilePath}`;
const photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [{
title: `IMG_${new Date().getTime()}`,
fileNameExtension: 'jpg',
photoType: photoAccessHelper.PhotoType.IMAGE
}];
const desFileUris = await phHelper.showAssetsCreationDialog([srcFileUri], photoCreationConfigs);
if (desFileUris && desFileUris.length > 0) {
srcFile = await fs.open(tempFilePath, fs.OpenMode.READ_ONLY);
desFile = await fs.open(desFileUris[0], fs.OpenMode.WRITE_ONLY);
await fs.copyFile(srcFile.fd, desFile.fd);
console.info('照片成功保存到相册, URI:', desFileUris[0]);
} else {
console.info('用户取消了保存操作。');
}
} catch (err) {
const error = err as BusinessError;
console.error(`通过弹窗保存照片失败, code: ${error.code}, message: ${error.message}`);
} finally {
if (srcFile) await fs.close(srcFile);
if (desFile) await fs.close(desFile);
await fs.unlink(tempFilePath);
}
}
页面完整代码:
@Entry
@Component
struct CameraPage {
private xcomponentController: XComponentController = new XComponentController();
private surfaceId: string = '';
private cameraManager?: camera.CameraManager;
private cameraInput?: camera.CameraInput;
private previewOutput?: camera.PreviewOutput;
private session?: camera.Session;
private photoOutput?: camera.PhotoOutput;
private photoAccessHelper?: photoAccessHelper.PhotoAccessHelper;
private isCameraInitialized: boolean = false;
async aboutToAppear() {
const abilityContext = getContext(this) as common.UIAbilityContext;
this.photoAccessHelper = photoAccessHelper.getPhotoAccessHelper(abilityContext);
await this.checkAndRequestPermissions();
}
async aboutToDisappear() {
await this.releaseCamera();
}
async checkAndRequestPermissions(): Promise<void> {
const permissionList: Array<Permissions> = ['ohos.permission.CAMERA', 'ohos.permission.WRITE_MEDIA'];
const context = getContext(this) as common.UIAbilityContext;
const atManager = abilityAccessCtrl.createAtManager();
try {
const data = await atManager.requestPermissionsFromUser(context, permissionList);
let allGranted = true;
for (let i = 0; i < data.authResults.length; i++) {
if (data.authResults[i] !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
console.info('所有权限已授予,准备初始化相机。');
this.cameraManager = camera.getCameraManager(context);
if (this.surfaceId) {
await this.initCamera();
}
} else {
console.error('相机或存储权限被拒绝。');
}
} catch (error) {
console.error(`申请权限时发生异常: ${JSON.stringify(error)}`);
}
}
async initCamera() {
if (this.isCameraInitialized || !this.surfaceId || !this.cameraManager) {
console.warn('初始化条件不满足或已初始化,跳过。');
return;
}
this.isCameraInitialized = true;
console.info('开始初始化相机...');
try {
const cameras = this.cameraManager.getSupportedCameras();
if (cameras.length === 0) {
console.error('No camera device supported.');
return;
}
const cameraDevice = cameras.find(cam => cam.cameraPosition === camera.CameraPosition.CAMERA_POSITION_BACK) ?? cameras[0];
this.cameraInput = this.cameraManager.createCameraInput(cameraDevice);
await this.cameraInput.open();
console.info('相机输入已打开');
const outputCapability = this.cameraManager.getSupportedOutputCapability(cameraDevice, camera.SceneMode.NORMAL_PHOTO);
const previewProfile = outputCapability.previewProfiles[0];
this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, this.surfaceId);
console.info('预览输出已创建');
const photoProfiles = outputCapability.photoProfiles;
if (!photoProfiles) {
console.error("设备不支持拍照输出");
return;
}
this.photoOutput = this.cameraManager.createPhotoOutput(photoProfiles[0]);
console.info('拍照输出已创建');
this.setupPhotoCallbacks();
this.session = this.cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO);
if(this.session === undefined) {
console.error("创建会话失败");
return;
}
this.session.beginConfig();
this.session.addInput(this.cameraInput);
this.session.addOutput(this.previewOutput);
this.session.addOutput(this.photoOutput);
await this.session.commitConfig();
console.info('会话配置已提交');
this.configureCameraSettings(this.session as camera.PhotoSession);
await this.session.start();
console.info('会话已启动,预览应该可见了!');
} catch (error) {
const err = error as BusinessError;
console.error(`相机初始化失败,错误码: ${err.code}, 信息: ${err.message}`);
this.isCameraInitialized = false;
}
}
setupPhotoCallbacks(): void {
if (!this.photoOutput) return;
this.photoOutput.on('photoAvailable', (err, photo) => {
console.info('photoAvailable 回调触发');
if (err || photo === undefined) {
console.error('获取照片数据失败', JSON.stringify(err));
return;
}
let imageObj: image.Image = photo.main;
imageObj.getComponent(image.ComponentType.JPEG, (err, component) => {
if (err || component === undefined) {
console.error('获取照片JPEG组件失败');
imageObj.release(); // 释放资源
return;
}
let buffer: ArrayBuffer = component.byteBuffer;
if (!buffer) {
console.error('照片 buffer 为空');
imageObj.release();
return;
}
this.savePhoto(buffer).finally(() => {
imageObj.release();
console.log('Image资源已释放');
});
});
});
this.photoOutput.on('captureStartWithInfo', (err, captureStartInfo) => {
if (err) return;
console.info(`拍照开始, captureId: ${captureStartInfo.captureId}`);
});
this.photoOutput.on('captureEnd', (err, captureEndInfo) => {
if (err) return;
console.info(`拍照结束, captureId: ${captureEndInfo.captureId}`);
});
this.photoOutput.on('captureReady', (err) => {
if(err) return;
console.info(`可以进行下一次拍照 (captureReady)`);
});
this.photoOutput.on('error', (error) => {
console.error(`拍照输出流错误, code: ${error.code}`);
});
}
async releaseCamera() {
console.info('开始释放相机资源...');
this.isCameraInitialized = false;
try {
if (this.session) {
await this.session.stop();
this.session.release();
this.session = undefined;
}
if (this.cameraInput) {
await this.cameraInput.close();
this.cameraInput = undefined;
}
if (this.previewOutput) {
await this.previewOutput.release();
this.previewOutput = undefined;
}
if (this.photoOutput) {
await this.photoOutput.release();
this.photoOutput = undefined;
}
} catch (error) {
console.error(`释放相机资源失败: ${JSON.stringify(error)}`);
}
}
build() {
Stack({ alignContent: Alignment.Bottom }) {
XComponent({
id: 'camera_preview_xcomponent',
type: 'surface',
controller: this.xcomponentController
})
.onLoad(async () => {
this.surfaceId = this.xcomponentController.getXComponentSurfaceId();
console.info(`成功获取 SurfaceId: ${this.surfaceId}`);
if (this.cameraManager) {
await this.initCamera();
}
})
.width('100%')
.height('100%')
Row() {
Button() {
Text('拍照').fontSize(20).fontColor(Color.White)
}
.width(80)
.height(80)
.type(ButtonType.Circle)
.backgroundColor(Color.Gray)
.opacity(0.8)
.onClick(() => {
this.triggerCapture(); // 点击按钮,执行拍照
})
}
.width('100%')
.justifyContent(FlexAlign.Center)
.padding({ bottom: 40 })
}
.width('100%')
.height('100%')
.backgroundColor(Color.Black)
}
}
更多关于HarmonyOS鸿蒙Next中Cannot read property appId of null的实战教程也可以访问 https://www.itying.com/category-93-b0.html
当前不支持用showAssetsCreationDialog保存图片
更多关于HarmonyOS鸿蒙Next中Cannot read property appId of null的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中出现"Cannot read property appId of null"错误,通常是由于未正确初始化应用上下文或访问了未定义的对象。检查以下方面:
- 确保Ability或Page的onInit()方法中已正确初始化context
- 验证app.json配置文件中appId字段是否存在且格式正确
- 检查调用getAbilityContext()时是否返回有效对象
- 确认使用@StorageLink或@Prop装饰器时变量已正确定义,
这个错误通常是因为在调用showAssetsCreationDialog
时,photoAccessHelper
没有正确初始化或上下文获取失败导致的。检查以下几点:
- 确保在
aboutToAppear
中正确获取了photoAccessHelper
实例:
this.photoAccessHelper = photoAccessHelper.getPhotoAccessHelper(abilityContext);
- 确认
abilityContext
获取成功,建议在调用savePhoto
方法前添加日志:
console.info('Context:', context);
console.info('PhotoAccessHelper:', phHelper);
-
检查权限是否已正确授予
ohos.permission.WRITE_MEDIA
,可以在checkAndRequestPermissions
方法中添加权限检查日志。 -
确保在调用
savePhoto
时photoAccessHelper
实例仍然有效,没有被意外释放。 -
临时文件路径生成后,可以添加日志确认文件是否创建成功:
console.info('Temp file path:', tempFilePath);