【鸿蒙心迹】HarmonyOS preview 预览文件 Kit 的入门讲解(配套后端代码)
HarmonyOS preview 预览文件 Kit 的入门讲解(配套后端代码)
本文以实际工程为例,快速上手 HarmonyOS 元服务 的文件预览能力(PreviewKit),并配套一个后端用于提供示例文件。示例工程路径:
- 客户端(HarmonyOS 端):
client - 后端(Node.js):
server

上图是将 1个pdf文件和3个图片一起预览,那么就只会现实第1个预览窗口。
下图是移除pdf文件,将3个同类型的图片放在一起预览

为了方便演示功能,需要先将一些可以预览的文件下载到元服务的沙箱内,是基于这个原因我们才需要引入后端来模拟这个下载的环境,所以元服务内需要先实现下载文件,存储到沙箱,然后再使用预览API filePreview.openPreview预览沙箱内的文件。
1. 工程结构与目标
client/entry/src/main/ets/pages/Index.ets:演示并发下载 4 个文件(1.pdf、1.png、2.png、3.png)并一次性预览。server/index.js与server/public/:提供静态文件下载接口/file/:filename。
目标:
- 点击“下载”按钮,并发下载上述 4 个文件到应用沙箱目录。
- 下载成功后点击“预览”,一次性打开最多 4 个文件的预览窗口。
2. PreviewKit 的核心:filePreview.openPreview
HarmonyOS 提供了预览能力包 @kit.PreviewKit。在 ETS 代码中引入:
import{ filePreview }from'@kit.PreviewKit';import{ fileUri }from'@kit.CoreFileKit';核心调用是:
// 先准备多个文件的预览信息const prewList: filePreview.PreviewInfo[]=[]for(let i =0; i < count; i++){const item =this.lastDownloadedList[i];const fileInfo: filePreview.PreviewInfo ={ title: item.name,// 预览标题 uri: fileUri.getUriFromPath(item.path),// 将沙箱路径转成 Uri mimeType: item.mime ||'application/octet-stream',// MIME 类型}; prewList.push(fileInfo)}// 一次性打开多个预览窗口 filePreview.openPreview(uiContext, prewList).then(()=>{// 打开成功}).catch((err: BusinessError)=>{// 打开失败处理});说明:
PreviewInfo至少需要title、uri、mimeType。uri使用fileUri.getUriFromPath(沙箱文件路径)构造。- 支持一次性传入一个
PreviewInfo[],实现多文件预览。
图片占位:请补充一次性预览 4 个文件的窗口布局截图,标注窗口标题与 MIME 类型展示位置。
3. 并发下载与状态反馈(客户端)
示例使用 Promise.allSettled 并发下载 4 个后端文件,并按项展示“成功/失败”状态:
// 计划 + 状态@Localprivate plannedFiles: DownloadPlan[]=[];@Localprivate itemStatuses:string[]=[];@Localprivate isDownloading:boolean=false;@Localprivate statusMessage:string='';// 初始化计划(aboutToAppear)this.plannedFiles =[newDownloadPlan('1.pdf',`${this.serverBase}/1.pdf`),newDownloadPlan('1.png',`${this.serverBase}/1.png`),newDownloadPlan('2.png',`${this.serverBase}/2.png`),newDownloadPlan('3.png',`${this.serverBase}/3.png`)];this.itemStatuses =['未下载','未下载','未下载','未下载'];// 点击“下载”this.isDownloading =true;this.statusMessage ='下载中...';this.itemStatuses =newArray(this.plannedFiles.length).fill('下载中...');const promises:Promise<DownloadInfo>[]=this.plannedFiles.map(p =>this.downloadFile(p.url));const settled =awaitPromise.allSettled(promises);// 汇总结果并一次性触发 UI 刷新const successes: DownloadInfo[]=[];const nextStatuses:string[]=newArray(this.plannedFiles.length).fill('未下载');for(let i =0; i < settled.length; i++){const name =this.plannedFiles[i].name;const r = settled[i];if(r.status ==='fulfilled'){ successes.push(r.value); nextStatuses[i]=`✓ 下载成功:${name}`;}else{ nextStatuses[i]=`✗ 下载失败:${name}(${this.errorToString(r.reason as Object)})`;}}this.itemStatuses = nextStatuses;// 重新赋值以触发 UI 刷新this.lastDownloadedList = successes;this.isDownloading =false;UI 渲染建议:
- 使用
ForEach(this.plannedFiles, ...)动态渲染状态行,避免硬编码索引。 - 将与 UI 绑定的字段用
@Local或@State修饰,并“重新赋值数组”以触发刷新(不要在原数组上就地修改元素)。
图片占位:请补充“下载中→成功/失败”逐项状态变化的截图,便于读者理解响应式刷新。
4. HTTP 下载的细节与 ArkTS 限制规避
- MIME 与扩展名:示例通过扩展名推断 MIME,若扩展名缺失则从响应头的
Content-Type推断。 - ArkTS 限制:不建议直接
data.header['Content-Type']索引;示例使用序列化 + 正则方式提取避免 ArkTS 索引限制。
// 通过序列化响应头并用正则提取 Content-TypeprivatetryGetContentTypeHeader(headerObj: Object |null):string{if(!headerObj)return'';try{const json =JSON.stringify(headerObj);if(!json)return'';const match = json.match(/"content-type"\s*:\s*"([^"]+)"/i);return match && match.length >1? match[1]:'';}catch(_){return'';}}保存文件:
const filePath =`${this.filesDir}/${fileName}`;if(fileIo.accessSync(filePath)){ fileIo.unlinkSync(filePath);}const file = fileIo.openSync(filePath, fileIo.OpenMode.CREATE| fileIo.OpenMode.WRITE_ONLY);const bytesWritten = fileIo.writeSync(file.fd, fileBuffer); fileIo.closeSync(file);权限:
- 客户端需要在
entry/src/main/module.json5声明ohos.permission.INTERNET才能进行网络请求。
5. 后端:简单的静态文件下载接口
示例后端路径:d:\code\atoStudy\server,目录 public/ 放置 4 个演示文件。
核心路由:GET /file/:filename
后端的简单目录结构:

// index.js(简版示例)const express =require('express');const path =require('path');const app =express(); app.get('/file/:filename',(req, res)=>{const filename = req.params.filename;const filePath = path.join(__dirname,'public', filename); res.sendFile(filePath);// 或根据需要设置 Content-Type}); app.listen(3000,()=>{ console.log('Server listening on http://localhost:3000');});客户端请求地址示例:
private serverBase:string="http://192.168.5.2:3000/file";// 组合完整 URL 示例:`${this.serverBase}/1.pdf`注意:请按真实局域网 IP 替换 192.168.5.2,并保证手机/模拟器与后端在同一网络。6. 快速运行与验证
后端:
- 安装依赖并启动:
npm install && node index.js - 确认
public/下存在1.pdf、1.png、2.png、3.png
客户端:
- 在
module.json5中确保已声明ohos.permission.INTERNET - 构建并安装到设备/模拟器
- 点击“下载”,观察逐项状态变化
- 下载成功后点击“预览”,验证多窗口预览是否正常
图片占位:请补充上述过程的关键截图(如“权限声明处”、“下载成功状态”、“多窗口预览”)。
7. 常见问题与排查
- 权限错误(如 code=201 / “Permission denied”):检查
ohos.permission.INTERNET是否声明;确认真机/模拟器的网络可达性。 - 404 或下载失败:确认后端路由
/file/:filename存在且文件确实在public/目录内;检查客户端serverBase地址是否正确。 - MIME 与扩展名错配:优先使用后端返回的
Content-Type;如果缺失,则按扩展名推断。 - UI 不刷新:在 ArkUI 中对数组进行“重新赋值”来触发刷新,避免原地修改元素(例如使用
this.itemStatuses = [...nextStatuses])。
8. 小结
filePreview.openPreview 是 HarmonyOS 文件预览能力的核心,支持一次性打开多文件预览。结合简单的后端静态文件服务与并发下载、响应式状态刷新,能够快速搭建一个“下载即预览”的演示工程。本文的示例工程完整覆盖了从后端文件提供、客户端下载与保存、到预览窗口打开的关键路径,适合作为入门教程与二次扩展的基础。
近期活动
最近想要想要考取 HarmonyOS 基础或者高级证书,或者快要获取的同学都可以点击这个链接,加入我的班级,考取成功有机会获得鸿蒙礼盒一份。