鸿蒙next 文档类型文件预览

492 阅读3分钟

鸿蒙next 系统中 ,我们在app 里如何预览各种文件?别急,先找找官网上的资料,核心还是调用 filePreview.openPreview api ,看是否支持?其实在早些时候,已经想做这个功能了,但是看到官网文档类型只支持pdf ,同时提工单问过,回答说套件正在开发中,想着等它支持了一起做。具体更新在上个月2025.1月不知哪天,文档中突然多出了很多类型文件格式都可以预览了。先贴个链吧: developer.huawei.com/consumer/cn…

废话不多说,具体实现

import { BusinessError } from '@kit.BasicServicesKit';
import { filePreview } from '@kit.PreviewKit';

let uiContext = getContext(this);
let displayInfo: filePreview.DisplayInfo = {
  x: 100,
  y: 100,
  width: 800,
  height: 800
};
let fileInfo: filePreview.PreviewInfo = {
  title: '1.txt',
  // 该uri仅为参考,需要根据实际业务传入真实uri
  uri: 'file://com.example.myapplication/data/storage/el2/base/haps/entry/files/1.txt',
  mimeType: 'text/plain'
};
filePreview.openPreview(uiContext, fileInfo, displayInfo).then(() => {
  console.info('Succeeded in opening preview');
}).catch((err: BusinessError) => {
  console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
});

这是官网给的例子, 传3个参数,context, file, info。咋们第一个参数就不讲了。从第二个讲起。fileInfo 里三个参数: title, uri ,mimeType。最重要的就是uri ,大家看到上面官网的例子,看到这个格式想起了什么???它可以是一个沙盒里的路径,那么问题来了,我们项目中使用的不都是一个线上的下载地址么???怎么转化,当然是下载到沙盒里了。具体代码:

import LoadingDialog from '@lyb/loading-dialog'; 
// "@lyb/loading-dialog": "^2.1.5"
export const downLoadFileAndPreview =(context: Context, filePath: string, fileInfo: filePreview.PreviewInfo ) => {
  LoadingDialog.showLoading("下载中...");
  request.downloadFile(context, {
    url: fileInfo.uri,
    filePath: filePath
  }).then((downloadTask: request.DownloadTask) => {
    let progressCallback = (receivedSize: number, totalSize: number) => {
      console.info("download receivedSize:" + receivedSize + " totalSize:" + totalSize);
    };
    downloadTask.on('progress', progressCallback);
    downloadTask.on('complete', () => {
      LoadingDialog.hide();
      console.info('download complete');
      let fileInfos: filePreview.PreviewInfo = {
        title: fileInfo.title,
        uri: "file://com.xxx.example" + filePath,
        mimeType: fileInfo.mimeType
      };
      filePreviewFunc(context, fileInfos)
    })
  }).catch((err: BusinessError) => {
    LoadingDialog.hide()
    console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
  });
}

export const filePreviewFunc = (uiContext:Context, fileInfo: filePreview.PreviewInfo ) => {
  let displayInfo: filePreview.DisplayInfo = {
    x: 100,
    y: 100,
    width: 800,
    height: 800
  };
 filePreview.openPreview(uiContext, fileInfo, displayInfo, (err) => {
      if (err && err.code) {
        console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
        return;
      }
        console.info('Succeeded in opening preview');
  });}


// downLoadFileAndPreview 的参数 context,filesDir ,fileInfos,mimeTypes最下面完整代码有


let context = getContext(this) as common.UIAbilityContext;
let filesDir = context.filesDir + ‘/’ + ‘带后缀完整的文件名称’;
let fileInfos: filePreview.PreviewInfo = {  
      title: ‘预览时上方显示文件名’,  
      uri: "file://com.xiangshu.xsharmonyos" + filesDir,  
      mimeType: mimeTypes.get(__file.fileType) || ''
};

这个核心功能点就完事了!!!

下面直接贴完整代码吧: 

utils.ets

import { BusinessError, request } from "@kit.BasicServicesKit";
import LoadingDialog from '@lyb/loading-dialog';
import { fileIo, picker } from "@kit.CoreFileKit";
import { filePreview } from "@kit.PreviewKit";
import { promptAction } from "@kit.ArkUI";

export const mimeTypes = new Map([
  ['txt', 'text/plain'],
// cpp、c、h、java、xhtml、xml
  ['cpp', 'text/x-c++src'],
  ['c', 'text/x-csrc'],
  ['h', 'text/x-chdr'],
  ['java', 'text/x-java'],
  ['xhtml', 'application/xhtml+xml'],
  ['xml', 'text/xml'],
  // html、htm
  ['html', 'text/html'],
  ['htm', 'text/html'],
  // m4a、aac、mp3、ogg、wav
  ['m4a', 'audio/mp4a-latm'],
  ['aac', 'audio/aac'],
  ['mp3', 'audio/mpeg'],
  ['ogg', 'audio/ogg'],
  ['wav', 'audio/x-wav'],
  // mp4、mkv、ts
  ['mp4', 'video/mp4'],
  ['mkv', 'video/x-matroska'],
  ['ts', 'video/mp2ts'],
  ['pdf', 'application/pdf'],
  // doc、docx、xls、xlsx、ppt、pptx、csv
  ['doc', 'application/msword'],
  ['docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
  ['xls', 'application/vnd.ms-excel'],
  ['xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
  ['ppt', 'application/vnd.ms-powerpoint'],
  ['pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
  ['csv', 'text/comma-separated-values'],
]);


/**
 * 下载文件
 * @param filePath  下载保存路径
 * @param fileInfo  uri: 传进来的下载链接url,调用此方法转化为uri, fileName, mimeType
 */
export const downLoadFileAndPreview =(context: Context, filePath: string, fileInfo: filePreview.PreviewInfo ) => {
  LoadingDialog.showLoading("下载中...");
  request.downloadFile(context, {
    url: fileInfo.uri,
    filePath: filePath
  }).then((downloadTask: request.DownloadTask) => {
    let progressCallback = (receivedSize: number, totalSize: number) => {
      console.info("download receivedSize:" + receivedSize + " totalSize:" + totalSize);
    };
    downloadTask.on('progress', progressCallback);
    downloadTask.on('complete', () => {
      LoadingDialog.hide();
      console.info('download complete');
      let fileInfos: filePreview.PreviewInfo = {
        title: fileInfo.title,
        uri: "file://com.xiangshu.xsharmonyos" + filePath,
        mimeType: fileInfo.mimeType
      };
      filePreviewFunc(context, fileInfos)
    })
  }).catch((err: BusinessError) => {
    LoadingDialog.hide()
    console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
  });
}

export const filePreviewFunc = (uiContext:Context, fileInfo: filePreview.PreviewInfo ) => {
  let displayInfo: filePreview.DisplayInfo = {
    x: 100,
    y: 100,
    width: 800,
    height: 800
  };
  filePreview.canPreview(uiContext, fileInfo.uri).then((result) => {
    if (result) {
      console.info('文件可预览');
      // displayInfo 模态窗口的窗口展示信息,手机和平板设备填写无效。
      filePreview.openPreview(uiContext, fileInfo, displayInfo, (err) => {
        if (err && err.code) {
          console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
          return;
        }
        console.info('Succeeded in opening preview');
      });
    } else {
      promptAction.showToast({
        message: 'online file not preview!',
        duration: 2000,
        alignment:Alignment.Center
      });
      console.warn('文件不可预览');
    }
  }).catch((err: BusinessError) => {
    console.error(`检查失败,错误码:${err.code},错误信息:${err.message}`);
  });
}

在页面中调用: 

openPreview() {
    let __file:IFileParams = { //  // IFileParams 类型自己定义就行
        fileName:"我是一个pdf",
        fileNetUrl:"https:axxxxxx.com",
        fileType:"pdf" // 截取最后一个.后缀,映射类型
    };
    
      let fileInfo: filePreview.PreviewInfo = {
        title: __file.fileName || '',
        uri: __file.fileNetUrl,
        mimeType: mimeTypes.get(__file.fileType) || ''
      };
      if(!mimeTypes.has(__file.fileType)) {
        promptAction.showToast({
          message: '暂不支持的文件类型',
          duration: 2000,
          alignment:Alignment.Center
        });
        return ;
      }
      //先下载到本地 再用documentViewPicker 构建uri
      let filesDir = context.filesDir + '/' +  fileInfo.title;
      try {
        fs.access(filesDir).then((res: boolean) => {
          if (res) {
            console.info("文件存在直接调用预览")
            let fileInfos: filePreview.PreviewInfo = {
              title: fileInfo.title,
              uri: "file://com.xiangshu.xsharmonyos" + filesDir,
              mimeType: fileInfo.mimeType
            };
            filePreviewFunc(context, fileInfos)
          } else {// 存在下载完成后调用预览
            downLoadFileAndPreview(context, filesDir, fileInfo);
          }
        }).catch((err: BusinessError) => {
          console.error("access failed with error message: " + err.message + ", error code: " + err.code);
        });

      } catch (error) {
        let err: BusinessError = error as BusinessError;
        console.error("startDownFile:"+err.message)
      }
}