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

3 回复

当前不支持用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"错误,通常是由于未正确初始化应用上下文或访问了未定义的对象。检查以下方面:

  1. 确保Ability或Page的onInit()方法中已正确初始化context
  2. 验证app.json配置文件中appId字段是否存在且格式正确
  3. 检查调用getAbilityContext()时是否返回有效对象
  4. 确认使用@StorageLink@Prop装饰器时变量已正确定义,

这个错误通常是因为在调用showAssetsCreationDialog时,photoAccessHelper没有正确初始化或上下文获取失败导致的。检查以下几点:

  1. 确保在aboutToAppear中正确获取了photoAccessHelper实例:
this.photoAccessHelper = photoAccessHelper.getPhotoAccessHelper(abilityContext);
  1. 确认abilityContext获取成功,建议在调用savePhoto方法前添加日志:
console.info('Context:', context);
console.info('PhotoAccessHelper:', phHelper);
  1. 检查权限是否已正确授予ohos.permission.WRITE_MEDIA,可以在checkAndRequestPermissions方法中添加权限检查日志。

  2. 确保在调用savePhotophotoAccessHelper实例仍然有效,没有被意外释放。

  3. 临时文件路径生成后,可以添加日志确认文件是否创建成功:

console.info('Temp file path:', tempFilePath);
回到顶部