📖

HarmonyOS運動開発:ファイルプレビューの正しい実装方法を深く解析する

に公開

鴻蒙核心技术##運動開発##Core File Kit(ファイル基本サービス)##Preview Kit(ファイルプレビュー サービス)#

前言

HarmonyOS開発において、ファイルプレビュー機能は一般的なニーズです。特にユーザーがアップロードする画像、ドキュメント、オーディオ、ビデオなどのリソースを処理する際です。しかし、ファイルプレビューの実装は常にスムーズとは限りません。特にファイル権限やプレビュー ウィンドウの管理が関わる場合です。この記事では、「適切なファイルを選んでプレビューする」というテーマを基に、HarmonyOSにおけるファイルプレビューの核心ポイントを深く解析し、実際の開発で得た経験やコツを共有し、開発者がよく陥る落とし穴を回避するお手伝いをします。

前言:ファイルプレビューの痛みと挑戦

HarmonyOSにおいて、ファイルプレビュー機能は表面上は簡単そうに見えますが、実際には多くの詳細が潜んでいます。開発者は、ファイル権限が不足していたり、プレビュー ウィンドウが正常に開かなかったり、繰り返し開いたりするなどの問題に遭遇することがよくあります。これらの問題は、ユーザー体験に影響を及ぼすだけでなく、アプリがクラッシュしたり、データが失われたりする原因にもなります。したがって、正しいファイルプレビューの実装方法を掌握することは非常に重要です。

核心要点:ファイル URI 権限の永続化

HarmonyOSにおいて、DocumentViewPickerから取得したファイル URIは、一時的な権限しか持たず、この権限は直接ファイルプレビューには使用できません。さもないと、プレビューが失敗します。したがって、ファイル URIの権限を永続化する処理を行う必要があります。

権限永続化コード解析

await fileShare.persistPermission([
  {
    uri: uri,
    operationMode: fileShare.OperationMode.READ_MODE
  }
]);

fileShare.persistPermission:これは重要な永続化メソッドで、ファイル URIの権限を一時的から永続的なものに変更し、プレビュー機能がファイルに正常にアクセスできるようにします。

uri:これはファイルのパスで、その形式が正しいことを確認する必要があります。

operationMode:ここではREAD_MODEを指定し、読み取り権限のみを付与します。これはプレビュー機能が要求する最低限の権限です。

また、persistPermissionメソッドを使用するには、アプリのconfig.jsonファイルに以下の権限を宣言する必要があります。

{
  "name": "ohos.permission.FILE_ACCESS_PERSIST"
}

ファイルのMIMEタイプを取得する

ファイルをプレビューする前に、そのMIMEタイプを明確にすることが重要です。これは、プレビュー機能の正確性にとって非常に重要です。以下はMIMEタイプを取得するためのコードの実装です。

private getMimeType(filePath: string): string {
  const extension = filePath.split('.').pop()?.toLowerCase() || '';

  switch (extension) {
    case 'jpg':
    case 'jpeg':
      return 'image/jpeg';
    case 'png':
      return 'image/png';
    case 'gif':
      return 'image/gif';
    case 'bmp':
      return 'image/bmp';
    case 'webp':
      return 'image/webp';

    case 'mp4':
      return 'video/mp4';
    case 'mov':
      return 'video/quicktime';
    case 'avi':
      return 'video/x-msvideo';

    case 'mp3':
      return 'audio/mpeg';
    case 'wav':
      return 'audio/wav';
    case 'ogg':
      return 'audio/ogg';

    case 'txt':
    case 'log':
      return 'text/plain';

    case 'html':
    case 'htm':
      return 'text/html';

    default:
      return 'application/octet-stream';
  }
}

コード解析

filePath.split('.').pop():ファイルパスからファイル拡張子を取得し、これはMIMEタイプを判断するための鍵です。

switch文:拡張子に応じて対応するMIMEタイプを返します。ここでは一般的な画像、ビデオ、オーディオ、テキスト、HTMLファイルタイプをカバーしています。

• デフォルト値:ファイルタイプが特定できない場合は、application/octet-streamを返します。これは一般的なバイナリストリームタイプです。

ファイルプレビューの実装詳細

ファイルをプレビューするための実装には、ファイルの存在確認、プレビューの可否、プレビュー パラメーターの準備、プレビュー ウィンドウの管理など、複数の手順が含まれます。以下が完整的なコードの実装です。

async previewFile(): Promise<void> {
  if (!this.selectedFilePath) {
    promptAction.showToast({ message: 'ファイルを選択してください', duration: 2000 });
    return;
  }

  try {
    let uiContext = this.getUIContext().getHostContext() as Context;

    // 1. ファイルの存在を確認する
    try {
      await fs.access(this.selectedFilePath);
    } catch {
      promptAction.showToast({ message: 'ファイルが存在しないかアクセスできません', duration: 2000 });
      return;
    }

    // 2. プレビューできるかどうかを確認する
    const uri = this.selectedFilePath.startsWith('file://') ?
      this.selectedFilePath :
      `file://${this.selectedFilePath}`;

    await fileShare.persistPermission([
      {
        uri: uri,
        operationMode: fileShare.OperationMode.READ_MODE
      }
    ]);

    const canPreview = await filePreview.canPreview(uiContext, uri);
    if (!canPreview) {
      promptAction.showToast({ message: 'このファイルタイプのプレビューはサポートされていません', duration: 2000 });
      return;
    }

    // 3. プレビュー パラメーターを準備する
    const fileInfo: filePreview.PreviewInfo = {
      title: this.fileName,
      uri: uri,
      mimeType: this.getMimeType(this.selectedFilePath)
    };

    // 4. プレビュー ウィンドウの有無を確認する
    const hasDisplayed = await filePreview.hasDisplayed(uiContext);

    if (hasDisplayed) {
        // もしウィンドウが既に存在する場合は閉じる
        await filePreview.closePreview(uiContext)
    } else {
      // 新しいプレビュー ウィンドウを開く
      const displayInfo: filePreview.DisplayInfo = {
        x: 100,  // ウィンドウの開始X座標
        y: 100,  // ウィンドウの開始Y座標
        width: 800, // ウィンドウの幅
        height: 800 // ウィンドウの高さ
      };

      await filePreview.openPreview(uiContext, fileInfo, displayInfo);
    }

    console.info('ファイルのプレビューに成功しました');
  } catch (err) {
    const error = err as BusinessError;
    console.error(`プレビューに失敗しました、エラーコード: ${error.code}, エラー情報: ${error.message}`);
    promptAction.showToast({
      message: `プレビューに失敗しました: ${error.message}`,
      duration: 2000
    });
  }
}

コード解析

• ファイルの存在を確認する:fs.accessメソッドを使用してファイル パスが有効かどうかを確認します。

• ファイルの権限を永続化する:fileShare.persistPermissionメソッドを使用して、ファイル URIに永続的な読み取り権限があることを確認します。

• プレビューできるかどうかを確認する:filePreview.canPreviewメソッドを使用して、ファイル タイプがプレビューをサポートしているかどうかを判断します。

• プレビュー パラメーターを準備する:filePreview.PreviewInfoオブジェクトを構築し、ファイルのタイトル、URI、MIMEタイプを含めます。

• プレビュー ウィンドウを管理する:filePreview.hasDisplayedを使用して、既にプレビュー ウィンドウがあるかどうかを確認します。存在する場合は、filePreview.closePreviewを使用してウィンドウを閉じます。存在しない場合は、filePreview.openPreviewを使用して新しいプレビュー ウィンドウを開きます。

总结:ファイルプレビューの正しい実装方法

HarmonyOS開発において、ファイルプレビュー機能を実装するには、ファイル権限、MIMEタイプの取得、プレビュー ウィンドウの管理など、複数の側面に注意する必要があります。

Discussion