当前位置: 首页 > news >正文

HarmonyOS ArkWeb 系列之网页秒变PDF:createPdf 完整指南

文章目录

      • createPdf 是什么
      • 配置参数说清楚
      • Callback 方式
      • Promise 方式
      • 完整流程图
      • 那个最容易忽略的坑
      • 权限配置
      • 写在最后

能把一张网页直接转成 PDF,保存到本地——这个需求在报表、电子凭证、文档生成场景里非常常见。HarmonyOS 的 Web 组件内置了createPdf接口,不需要引入任何第三方库,直接调用就行。
今天把 Callback 和 Promise 两种写法都讲清楚,并且重点说清楚那个最容易忽略的坑。

createPdf 是什么

WebviewController.createPdf()是 Web 组件控制器上的一个方法,它把当前 Web 组件渲染的页面内容截取成 PDF 格式,以二进制数据流的形式返回给你。

你拿到这个数据流之后,可以用fileIo把它写成.pdf文件,存到应用沙箱目录里,或者分享给用户下载。

配置参数说清楚

调用createPdf前,需要传一个PdfConfiguration对象:

// PdfConfiguration 的完整字段(单位:英寸)constpdfConfig:webview.PdfConfiguration={width:8.27,// 页面宽度,8.27 英寸 ≈ A4 纸宽度height:11.69,// 页面高度,11.69 英寸 ≈ A4 纸高度marginTop:0,// 上边距marginBottom:0,// 下边距marginRight:0,// 右边距marginLeft:0,// 左边距shouldPrintBackground:true// 是否打印背景色/背景图};

注意单位是英寸,不是毫米也不是像素。A4 纸尺寸换算:

  • 宽:210mm ÷ 25.4 ≈8.27 英寸
  • 高:297mm ÷ 25.4 ≈11.69 英寸

shouldPrintBackground: true建议开启,否则有背景色的页面导出来是白底,效果很差。

Callback 方式

import{fileIo}from'@kit.CoreFileKit';import{webview}from'@kit.ArkWeb';import{BusinessError}from'@kit.BasicServicesKit';import{common}from'@kit.AbilityKit';@Entry@Componentstruct Index{controller:webview.WebviewController=newwebview.WebviewController();pdfConfig:webview.PdfConfiguration={width:8.27,height:11.69,marginTop:0,marginBottom:0,marginRight:0,marginLeft:0,shouldPrintBackground:true};build(){Column(){Button('保存为 PDF(Callback 方式)').onClick(()=>{this.controller.createPdf(this.pdfConfig,(error,result:webview.PdfData)=>{if(error){console.error(`生成PDF失败:${(errorasBusinessError).message}`);return;}try{letcontext=this.getUIContext().getHostContext()ascommon.UIAbilityContext;letfilePath=context.filesDir+'/output.pdf';letfile=fileIo.openSync(filePath,fileIo.OpenMode.READ_WRITE|fileIo.OpenMode.CREATE);// result.pdfArrayBuffer() 返回 Uint8Array,.buffer 取得背后的 ArrayBufferfileIo.write(file.fd,result.pdfArrayBuffer().buffer).then((writeLen:number)=>{console.info(`PDF写入成功,文件大小:${writeLen}bytes`);}).catch((err:BusinessError)=>{console.error(`写入失败:${err.message}, code:${err.code}`);}).finally(()=>{fileIo.closeSync(file);// 无论成功失败都要关闭文件句柄});}catch(resError){console.error(`处理PDF数据时出错:${(resErrorasBusinessError).message}`);}});})Web({src:'https://www.example.com',controller:this.controller}).width('100%').layoutWeight(1)}.height('100%').width('100%')}}

Promise 方式

import{fileIo}from'@kit.CoreFileKit';import{webview}from'@kit.ArkWeb';import{BusinessError}from'@kit.BasicServicesKit';import{common}from'@kit.AbilityKit';@Entry@Componentstruct Index{controller:webview.WebviewController=newwebview.WebviewController();pdfConfig:webview.PdfConfiguration={width:8.27,height:11.69,marginTop:0,marginBottom:0,marginRight:0,marginLeft:0,shouldPrintBackground:true};build(){Column(){Button('保存为 PDF(Promise 方式)').onClick(()=>{this.controller.createPdf(this.pdfConfig).then((result:webview.PdfData)=>{letcontext=this.getUIContext().getHostContext()ascommon.UIAbilityContext;letfilePath=context.filesDir+'/output.pdf';letfile=fileIo.openSync(filePath,fileIo.OpenMode.READ_WRITE|fileIo.OpenMode.CREATE);returnfileIo.write(file.fd,result.pdfArrayBuffer().buffer).then((writeLen:number)=>{console.info(`PDF写入成功,文件大小:${writeLen}bytes`);returnfile;}).catch((err:BusinessError)=>{console.error(`写入失败:${err.message}`);returnfile;}).then((file)=>{fileIo.closeSync(file);});}).catch((err:BusinessError)=>{console.error(`生成PDF失败:${err.message}, code:${err.code}`);});})Web({src:'https://www.example.com',controller:this.controller}).width('100%').layoutWeight(1)}.height('100%').width('100%')}}

两种方式功能完全一样,Promise 方式更现代,链式调用更清晰。如果你的项目支持async/await,可以进一步简化:

asyncfunctionsavePdf(controller:webview.WebviewController,context:common.UIAbilityContext){try{constresult=awaitcontroller.createPdf({width:8.27,height:11.69,marginTop:0,marginBottom:0,marginRight:0,marginLeft:0,shouldPrintBackground:true});constfilePath=context.filesDir+'/output.pdf';constfile=fileIo.openSync(filePath,fileIo.OpenMode.READ_WRITE|fileIo.OpenMode.CREATE);try{constwriteLen=awaitfileIo.write(file.fd,result.pdfArrayBuffer().buffer);console.info(`PDF生成成功,大小:${writeLen}bytes,路径:${filePath}`);}finally{fileIo.closeSync(file);}}catch(err){console.error(`PDF生成失败:${(errasBusinessError).message}`);}}

完整流程图

那个最容易忽略的坑

必须等页面渲染完成再调用createPdf

如果页面还在加载中就调用createPdf,生成的 PDF 可能是空白的,或者只有部分内容。

正确做法是监听onPageEnd事件,在页面加载完成后再允许用户触发 PDF 生成:

@Entry@Componentstruct Index{controller:webview.WebviewController=newwebview.WebviewController();@StatepageReady:boolean=false;build(){Column(){Button('保存为 PDF').enabled(this.pageReady)// 页面未加载完时按钮禁用.onClick(()=>{if(!this.pageReady)return;// 调用 createPdf...})Web({src:'https://www.example.com',controller:this.controller}).onPageEnd(()=>{this.pageReady=true;// 页面加载完成后才开放}).width('100%').layoutWeight(1)}}}

权限配置

生成 PDF 不需要额外权限,但如果 Web 组件加载的是网络地址(https://),需要在module.json5里声明网络权限:

{"module":{"requestPermissions":[{"name":"ohos.permission.INTERNET"}]}}

加载本地$rawfile()文件则不需要。

写在最后

createPdf这个接口用法并不复杂,难点在于:

  1. 参数单位是英寸,要换算好
  2. pdfArrayBuffer()返回的是Uint8Array,写文件时要取.buffer
  3. 页面必须加载完成才能调用,否则生成空白 PDF
http://www.jsqmd.com/news/848402/

相关文章:

  • A-59F所有应用模式说明
  • 告别黑终端:用PyQt5给ROS机器人做个带地图交互的GUI控制界面(附A*算法可视化)
  • 2026硅酮胶OEM标杆名录:硅酮平面密封胶/硅酮玻璃胶/硅酮耐侯胶/硅酮胶OEM厂家/硅酮胶大桶料/硅酮胶粘剂/选择指南 - 优质品牌商家
  • 全网最全端口映射位置汇总:一张表搞定所有设备设置
  • 为什么你的内存池写得不够快?来看 Linux SLUB 分配器教科书级的 O(1) 路径
  • D2DX:让经典《暗黑破坏神2》焕发新生的终极解决方案
  • OpenClaw用户如何通过CLI子命令快速完成Taotoken接入配置
  • 2026年4月可靠驾驶式扫地机推荐指南:1000公斤高压清洗机、工业吸尘器、扫地机厂家、疏通机厂家、管道疏通机选择指南 - 优质品牌商家
  • 一套高级程序员的训练系统工程:llm.c 优化器与 ZeRO-1 源码剖析
  • ARM9老开发板救星:用BusyBox 1.7.0和4.3.2工具链构建根文件系统(避坑实录)
  • 端口映射检测完全教程:telnet/nc/在线工具/Nmap四层测试体系
  • 大牛直播SDK(SmartMediaKit)Android平台Unity3D RTSP/RTMP播放器集成实践
  • CanMV K230 家用电器电流识别 预告
  • MIPS汇编入门:手把手教你用QtSpim搭建第一个‘Hello World’程序(附调试技巧)
  • 遗传算法组卷效果总是不理想?可能是你的‘适应度函数’没调好(Java实战避坑)
  • Perplexity引用格式设置全链路解析(含BibTeX/CSL/DOI自动映射底层逻辑)
  • Unpaywall:3分钟打破学术付费墙,免费获取90%科研论文的智能解决方案
  • HarmonyOS ArkWeb 系列之手机识别网页里的电话号码、邮箱、日期
  • 关键字[Static]
  • AD5933模块开箱测评与内部电路解析:拆开屏蔽罩,看看188元到底买了啥?
  • Nodejs项目如何配置环境变量调用Taotoken的OpenAI兼容接口
  • 大熊来访,三大板块影响分析
  • 未来十年软件工程专业就业前景
  • 告别手动评分!用ImageJ的IHC Profiler插件,5分钟搞定免疫组化定量分析(附避坑指南)
  • 使用Taotoken聚合API一周后的延迟与稳定性实际体验分享
  • ONNX 部署
  • 快速原型开发首选:Trae 在小型项目与低配设备上的 3 类落地场景
  • 压接 vs 焊接:高速连接器组装工艺的选型指南与实战对比
  • 【独家逆向工程报告】:从API调用频次、引用溯源深度、多跳推理准确率三维度,锁定Perplexity最危险的2个隐形对手
  • KLayout 0.30.0 macOS版本深度解析:EDA工具的多架构部署策略与技术演进