鸿蒙Preview预览文件失败原因

特别注意:关键避坑点

要在鸿蒙应用中预览沙箱路径下的 .docx 文件,核心是使用 PreviewKit 并严格遵循 URI 格式、权限配置和 MIME 类型规范,以下是可直接运行的完整代码和避坑指南(适配 API 10+,HarmonyOS 5.0+)

一、前置配置(必须完成)

1. 权限声明(module.json5

需要申请文件读写权限,并引入 PreviewKit 模块:

复制代码
{
  "module": {
    // 权限声明
    "requestPermissions": [
      { "name": "ohos.permission.READ_USER_STORAGE" },
      { "name": "ohos.permission.WRITE_USER_STORAGE" }
    ],
    // 引入预览工具包
    "usesModules": [
      { "name": "@kit.PreviewKit" }
    ]
  }
}
2. 动态申请权限(可选,高版本鸿蒙需动态授权)

在页面初始化时申请存储权限,避免预览时因权限不足失败:

复制代码
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';

// 权限申请函数
async requestStoragePermission() {
  const atManager = abilityAccessCtrl.createAtManager();
  const permissions = ['ohos.permission.READ_USER_STORAGE'];
  try {
    const grantStatus = await atManager.checkAccessToken(
      abilityAccessCtrl.createTokenID(
        this.uiContext.abilityInfo.bundleName,
        this.uiContext.abilityInfo.applicationInfo.uid
      ),
      permissions[0]
    );
    if (grantStatus !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      // 申请权限
      await atManager.requestPermissionsFromUser(this.uiContext, permissions);
    }
  } catch (err) {
    console.error('权限申请失败:', err);
  }
}

二、完整 ArkTS 实现代码

复制代码
import { filePreview } from '@kit.PreviewKit';
import fs from '@ohos.file.fs';
import common from '@ohos.app.ability.common';
import { BusinessError } from '@ohos.base';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';

@Entry
@Component
struct DocxPreviewPage {
  // 获取 UI 上下文
  private uiContext = getContext(this) as common.UIAbilityContext;
  // 目标文件名称
  private docFileName = '关于 2023 年元旦及春节假期安排的预通知.docx';
  // 沙箱内文件绝对路径
  private docFilePath = `/data/storage/el2/base/haps/entry/files/${this.docFileName}`;

  build() {
    Column({ space: 20, alignItems: ItemAlign.Center })
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center) {
        Button('预览 Word 文档')
          .width(200)
          .height(50)
          .onClick(async () => {
            // 先申请权限
            await this.requestStoragePermission();
            // 执行预览
            this.previewDocxFile();
          })
      }
  }

  // 核心预览方法
  private previewDocxFile() {
    // 1. 校验文件是否存在
    if (!fs.accessSync(this.docFilePath)) {
      console.error(`文件不存在:${this.docFilePath}`);
      return;
    }

    // 2. 构造 标准 URI(关键!必须带应用包名)
    const appBundleName = this.uiContext.abilityInfo.bundleName;
    const fileUri = `file://${appBundleName}${this.docFilePath}`;

    // 3. 配置预览参数
    const previewParam: filePreview.PreviewInfo = {
      title: this.docFileName, // 预览窗口标题
      uri: fileUri,            // 带包名的文件 URI
      // docx 格式的标准 MIME 类型(不可写错)
      mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    };

    // 4. 调用系统预览接口
    filePreview.openPreview(this.uiContext, previewParam)
      .then(() => console.info('预览启动成功'))
      .catch((err: BusinessError) => {
        console.error(`预览失败:错误码=${err.code},原因=${err.message}`);
      });
  }

  // 动态申请存储权限
  private async requestStoragePermission() {
    const atManager = abilityAccessCtrl.createAtManager();
    const permissions = ['ohos.permission.READ_USER_STORAGE'];
    try {
      const tokenId = abilityAccessCtrl.createTokenID(
        this.uiContext.abilityInfo.bundleName,
        this.uiContext.abilityInfo.applicationInfo.uid
      );
      const grantStatus = await atManager.checkAccessToken(tokenId, permissions[0]);
      if (grantStatus !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
        await atManager.requestPermissionsFromUser(this.uiContext, permissions);
      }
    } catch (err) {
      console.error('权限申请异常:', err);
    }
  }
}

三、关键避坑点(90% 失败原因在这里)

1.URI 格式必须正确
  • ❌ 错误写法:file:///data/storage/el2/...(缺少应用包名)
  • ✅ 正确写法:file://{应用包名}/data/storage/el2/...
  • 动态获取包名:this.uiContext.abilityInfo.bundleName,避免硬编码。
2.MIME 类型不能混淆

|-------|-------------------------------------------------------------------------|----------------------------------|
| 文件类型 | 正确 MIME 类型 | 错误 MIME 类型 |
| .docx | application/vnd.openxmlformats-officedocument.wordprocessingml.document | application/msword(这是 .doc 格式) |

3.文件路径校验
  • fs.accessSync(filePath) 提前判断文件是否存在,避免因文件未拷贝到沙箱路径导致失败。
  • 若文件是从外部导入,需先通过 fileIo 将文件写入 entry/files 目录。
4.低版本兼容(API < 10)

低版本鸿蒙无 PreviewKit,需通过 隐式 Want 调用 WPS 等第三方应用打开:

复制代码
private openByThirdApp() {
  const want = {
    action: 'ohos.want.action.viewData',
    uri: this.fileUri,
    type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
  };
  this.uiContext.startAbility(want).catch(err => console.error('调用第三方失败:', err));
}

四、常见问题排查

|---------------|----------------------------------------|
| 问题现象 | 排查方向 |
| 预览无响应,错误码 -1 | 检查 URI 是否带应用包名 |
| 提示 "不支持的文件格式" | 核对 MIME 类型是否为 docx 专属 |
| 提示 "权限不足" | 检查 module.json5 权限声明 + 动态申请权限 |
| 提示 "文件不存在" | 确认文件已放入 entry/files 目录,路径拼写无空格 / 错别字 |

相关推荐
sam.li11 小时前
鸿蒙HAR对外发布安全流程
安全·华为·harmonyos
sam.li12 小时前
鸿蒙APP安全体系
安全·华为·harmonyos
ChinaDragon14 小时前
HarmonyOS:通过组件导航设置自定义区域
harmonyos
人工智能知识库15 小时前
华为HCIP-HarmonyOS Application Developer题库 H14-231 (26年最新带解析)
华为·harmonyos·hcip-harmonyos·h14-231
C雨后彩虹15 小时前
亲子游戏问题
java·数据结构·算法·华为·面试
以太浮标15 小时前
华为eNSP模拟器综合实验之- 端口镜像(Port Mirroring)配置解析
运维·服务器·网络·华为
搬砖的kk15 小时前
鸿蒙 PC 版 DevEco Studio 使用 OHPM 下载三方库教程
华为·harmonyos
以太浮标1 天前
华为eNSP模拟器综合实验之-DHCP服务中继配置案例
网络·华为·智能路由器·信息与通信
游戏技术分享1 天前
【鸿蒙游戏技术分享 第75期】AGC后台批量导入商品失败,提示“参数错误”
游戏·华为·harmonyos
No Silver Bullet1 天前
HarmonyOS NEXT开发进阶(十七):WebView 拉起 H5 页面
华为·harmonyos