鸿蒙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 目录,路径拼写无空格 / 错别字 |

相关推荐
2601_9495936515 小时前
基础入门 React Native 鸿蒙跨平台开发:模拟智能音响
react native·react.js·harmonyos
xiaoqi92215 小时前
React Native鸿蒙跨平台如何进行狗狗领养中心,实现基于唯一标识的事件透传方式是移动端列表开发的通用规范
javascript·react native·react.js·ecmascript·harmonyos
jin12332216 小时前
React Native鸿蒙跨平台剧本杀组队消息与快捷入口组件,包含消息列表展示、快捷入口管理、快捷操作触发和消息详情预览四大核心功能
javascript·react native·react.js·ecmascript·harmonyos
烬头882117 小时前
React Native鸿蒙跨平台实现二维码联系人APP(QRCodeContactApp)
javascript·react native·react.js·ecmascript·harmonyos
xiaoqi92220 小时前
React Native鸿蒙跨平台如何实现分类页面组件通过searchQuery状态变量管理搜索输入,实现了分类的实时过滤功能
javascript·react native·react.js·ecmascript·harmonyos
听麟20 小时前
HarmonyOS 6.0+ 智慧出行导航APP开发实战:离线地图与多设备位置协同落地
华为·wpf·harmonyos
qq_1777673720 小时前
React Native鸿蒙跨平台实现应用介绍页,实现了应用信息卡片展示、特色功能网格布局、权限/联系信息陈列、评分展示、模态框详情交互等通用场景
javascript·react native·react.js·ecmascript·交互·harmonyos
jin12332221 小时前
基于React Native鸿蒙跨平台地址管理是许多电商、外卖、物流等应用的重要功能模块,实现了地址的添加、编辑、删除和设置默认等功能
javascript·react native·react.js·ecmascript·harmonyos
2501_920931701 天前
React Native鸿蒙跨平台医疗健康类的血压记录,包括收缩压、舒张压、心率、日期、时间、备注和状态
javascript·react native·react.js·ecmascript·harmonyos
2501_920931701 天前
React Native鸿蒙跨平台使用useState管理健康记录和过滤状态,支持多种健康数据类型(血压、体重等)并实现按类型过滤功能
javascript·react native·react.js·ecmascript·harmonyos