ReactNative for OpenHarmony项目鸿蒙化三方库:react-native-pdf — PDF文档查看器
本文详细介绍了在 HarmonyOS 平台的使用方法。通过 Pdf 组件,你可以轻松实现 PDF 文档的加载和展示。核心要点✅ 支持 URL 和本地资源加载✅ 支持缩放控制和页面间距设置✅ 支持密码保护的 PDF✅ 完善的加载进度和页面变化回调适用场景电子书阅读合同文档展示报表预览附件查看希望本文能帮助你在 HarmonyOS 项目中顺利集成 PDF 查看组件!
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
📌 开发环境声明:本文基于 React Native 0.72.90 版本进行开发适配
🚀 一、开篇引言
PDF 文档查看是移动应用中常见的需求,无论是电子书阅读、合同签署还是报表展示,都需要一个稳定高效的 PDF 渲染组件。react-native-pdf 是 React Native 社区广泛使用的 PDF 查看组件,支持从 URL、本地文件等多种来源加载 PDF 文档,并提供丰富的交互功能。本文将带你深入了解如何在 HarmonyOS 平台上集成和使用这个实用的文档组件。
1.1 你将学到什么?
- ✅ react-native-pdf 的核心概念与工作原理
- ✅ HarmonyOS 平台的完整集成流程
- ✅ 多种 PDF 资源加载方式
- ✅ PDF API 的深度解析
- ✅ 实际应用场景的最佳实践
1.2 适用人群
- 正在进行 React Native 鸿蒙化迁移的开发者
- 需要展示 PDF 文档的应用开发者
- 对跨平台文档组件开发感兴趣的技术爱好者
1.3 为什么选择 react-native-pdf?
| 特点 | 说明 |
|---|---|
| 功能丰富 | 支持缩放、翻页、密码保护等多种功能 |
| 跨平台一致 | iOS、Android、HarmonyOS 表现一致 |
| 高性能 | 原生渲染,支持大文件加载 |
| 回调完善 | 支持加载进度、页面变化、错误处理等回调 |
| 灵活配置 | 支持自定义缩放范围、页面间距等 |
📦 二、库概览
2.1 基本信息
| 项目 | 内容 |
|---|---|
| 库名称 | @react-native-ohos/react-native-pdf |
| 原库名称 | react-native-pdf |
| 版本信息 | 6.7.5 (RN 0.72) / 6.8.0 (RN 0.77) |
| 官方仓库 | https://github.com/wonday/react-native-pdf |
| 鸿蒙仓库 | https://gitcode.com/openharmony-sig/rntpc_react-native-pdf |
| 开源协议 | MIT |
2.2 版本兼容性
| 三方库版本 | 支持RN版本 | 是否支持Autolink |
|---|---|---|
| ~6.8.0 | 0.77 | No |
| ~6.7.5 | 0.72 | Yes |
| <=6.7.4-0.3.6@deprecated | 0.72 | No |
2.3 核心能力矩阵
| 能力项 | 描述 | HarmonyOS 支持 |
|---|---|---|
| URL 加载 | 从网络 URL 加载 PDF | ✅ 完全支持 |
| 本地文件加载 | 从本地资源加载 PDF | ✅ 完全支持 |
| 加载进度回调 | onLoadProgress 回调 | ✅ 完全支持 |
| 加载完成回调 | onLoadComplete 回调 | ✅ 部分支持 |
| 错误回调 | onError 回调 | ✅ 完全支持 |
| 页面变化回调 | onPageChanged 回调 | ✅ 完全支持 |
| 缩放控制 | scale/minScale/maxScale | ✅ 完全支持 |
| 密码保护 | password 属性 | ✅ 完全支持 |
| 页面间距 | spacing 属性 | ✅ 完全支持 |
| 适配策略 | fitPolicy 属性 | ✅ 完全支持 |
| 链接点击 | onPressLink 回调 | ✅ 完全支持 |
| 缩放变化回调 | onScaleChanged 回调 | ✅ 完全支持 |
| 设置页码 | setPage 静态方法 | ✅ 完全支持 |
| 横向滚动 | horizontal 属性 | ❌ 不支持 |
| 自适应宽度 | fitWidth 属性 | ❌ 不支持 |
| 双击缩放 | enableDoubleTapZoom 属性 | ❌ 不支持 |
| 分页显示 | enablePaging 属性 | ❌ 不支持 |
2.4 技术架构图
2.5 典型应用场景
| 场景 | 描述 | 示例 |
|---|---|---|
| 电子书阅读 | 在线/离线 PDF 阅读 | 📚 小说、教材 |
| 合同签署 | 展示合同文档 | 📝 电子合同、协议 |
| 报表展示 | 数据报表 PDF 展示 | 📊 财务报表、分析报告 |
| 文档预览 | 附件文档预览 | 📄 邮件附件、通知 |
⚡ 三、快速开始
3.1 环境要求
| 依赖项 | 版本要求 |
|---|---|
| React Native | 0.72.x / 0.77.x |
| RNOH (鸿蒙框架) | 0.72.90 / 0.77.18 |
| HarmonyOS SDK | 6.0.0.47+ (API 20) |
| DevEco Studio | 5.0.3+ / 6.0+ |
| Node.js | 16.18.0+ / 18.x |
3.2 一键安装
创建鸿蒙项目的过程不再进行描述,不懂得看这篇:https://blog.csdn.net/u011178696/article/details/151932277
npm install @react-native-ohos/react-native-pdf@6.7.5rc.1
或使用 yarn:
yarn add @react-native-ohos/react-native-pdf@6.7.5rc.1
3.3 验证安装
安装完成后,检查 package.json 文件:
{
"dependencies": {
"@react-native-ohos/react-native-pdf": "^6.7.5rc.1"
}
}
🔧 四、HarmonyOS 平台配置
4.1 AutoLink 配置
步骤 1:配置 oh-package.json5
在项目根目录的 oh-package.json5 文件中添加(这里要根据自己的实际情况来,你的不一定是0.72.90,也可能是0.72.96啥的):
{
"overrides": {
"@rnoh/react-native-openharmony": "./react_native_openharmony"
}
}
步骤 2:引入 HAR 包
在 entry/oh-package.json5 文件中添加依赖:
"dependencies": {
"@rnoh/react-native-openharmony": "0.72.90",
"@react-native-ohos/react-native-pdf": "file:../../node_modules/@react-native-ohos/react-native-pdf/harmony/pdfview.har"
}
步骤 3:配置 CMakeLists.txt
在 entry/src/main/cpp/CMakeLists.txt 文件中添加:
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-pdf/src/main/cpp" ./pdfview)
+ target_link_libraries(rnoh_app PUBLIC rnoh_pdf_view)
步骤 4:配置 PackageProvider.cpp
在 entry/src/main/cpp/PackageProvider.cpp 文件中添加:
+ #include "PdfViewPackage.h"
std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
return {
+ std::make_shared<PdfViewPackage>(ctx)
};
}
步骤 5:在 ArkTS 侧引入组件
在 entry/src/main/ets/pages/index.ets 或 entry/src/main/ets/rn/LoadBundle.ets 文件中添加:
+ import { RTNPdfView, PDF_VIEW_TYPE } from '@react-native-ohos/react-native-pdf';
@Builder
export function buildCustomRNComponent(ctx: ComponentBuilderContext) {
+ if (ctx.componentName === PDF_VIEW_TYPE) {
+ RTNPdfView({
+ ctx: ctx.rnComponentContext,
+ tag: ctx.tag,
+ })
+ }
}
const arkTsComponentNames: Array<string> = [
+ PDF_VIEW_TYPE
];
📱 五、基础使用
5.1 从 URL 加载 PDF
最基础的 PDF 加载方式:
import Pdf from 'react-native-pdf';
<Pdf
source={{ uri: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' }}
style={{ flex: 1 }}
onLoadComplete={(numberOfPages) => {
console.log(`共 ${numberOfPages} 页`);
}}
onError={(error) => {
console.log('PDF 加载失败', error);
}}
/>
5.2 从本地资源加载 PDF
从本地资源加载 PDF:
const source = require('./test.pdf');
<Pdf
source={source}
style={{ flex: 1 }}
/>
5.3 带密码的 PDF
加载加密的 PDF 文档:
<Pdf
source={{ uri: 'https://example.com/protected.pdf' }}
password="your_password"
style={{ flex: 1 }}
/>
🎨 六、进阶用法
6.1 缩放控制
设置缩放范围和初始缩放比例:
<Pdf
source={{ uri: 'https://example.com/document.pdf' }}
scale={1.0}
minScale={0.5}
maxScale={3.0}
style={{ flex: 1 }}
/>
6.2 页面间距和适配策略
<Pdf
source={{ uri: 'https://example.com/document.pdf' }}
spacing={10}
fitPolicy={2}
style={{ flex: 1 }}
/>
6.3 监听页面变化
<Pdf
source={{ uri: 'https://example.com/document.pdf' }}
onPageChanged={(page, numberOfPages) => {
console.log(`当前第 ${page} 页,共 ${numberOfPages} 页`);
}}
style={{ flex: 1 }}
/>
6.4 监听加载进度
<Pdf
source={{ uri: 'https://example.com/document.pdf' }}
onLoadProgress={(percent) => {
console.log(`加载进度: ${percent * 100}%`);
}}
onLoadComplete={(numberOfPages) => {
console.log('加载完成');
}}
style={{ flex: 1 }}
/>
6.5 使用 ref 设置页码
const pdfRef = useRef(null);
const goToPage = (pageNumber) => {
pdfRef.current?.setPage(pageNumber);
};
<Pdf
ref={pdfRef}
source={{ uri: 'https://example.com/document.pdf' }}
style={{ flex: 1 }}
/>
📚 七、API 详解
7.1 Pdf Props
source
PDF 数据源配置。
<Pdf source={{ uri: 'https://example.com/doc.pdf' }} />
<Pdf source={require('./doc.pdf')} />
page
初始页码索引。
<Pdf source={{ uri: '...' }} page={2} />
scale / minScale / maxScale
缩放比例控制。
<Pdf scale={1.5} minScale={0.5} maxScale={3.0} />
fitPolicy
适配策略:0 按宽度,1 按高度,2 同时适配(默认)。
<Pdf fitPolicy={0} />
spacing
页面间距。
<Pdf spacing={10} />
password
PDF 密码。
<Pdf password="secret" />
onLoadProgress
加载进度回调。
<Pdf onLoadProgress={(percent) => console.log(percent)} />
onLoadComplete
加载完成回调。
<Pdf onLoadComplete={(numberOfPages, path) => {
console.log(`共 ${numberOfPages} 页`);
}} />
onPageChanged
页面变化回调。
<Pdf onPageChanged={(page, numberOfPages) => {
console.log(`第 ${page} 页`);
}} />
onError
错误回调。
<Pdf onError={(error) => console.log(error)} />
onScaleChanged
缩放变化回调。
<Pdf onScaleChanged={(scale) => console.log(scale)} />
onPressLink
链接点击回调。
<Pdf onPressLink={(uri) => console.log(uri)} />
7.2 静态方法
setPage
设置当前页码。
const pdfRef = useRef(null);
pdfRef.current?.setPage(3);
⚠️ 八、注意事项与常见问题
8.1 遗留问题
| 问题 | 说明 |
|---|---|
| horizontal 属性不支持 | 横向滚动功能暂未适配 |
| fitWidth 属性不支持 | 自适应宽度功能暂未适配 |
| enableDoubleTapZoom 不支持 | 双击缩放功能暂未适配 |
| enablePaging 不支持 | 分页显示功能暂未适配 |
| onLoadComplete 参数部分支持 | 仅支持 numberOfPages 和 path 参数 |
8.2 常见问题
Q1: PDF 无法加载?
A: 检查网络权限配置,确保 URL 可访问。
Q2: 如何处理大文件 PDF?
A: 使用 onLoadProgress 监听加载进度,给用户反馈。
Q3: 如何实现翻页功能?
A: 使用 setPage 方法或监听 onPageChanged 回调。
💻 九、完整示例代码
精美 PDF 查看器示例

import React, { useState, useRef } from 'react';
import {
View,
Text,
StyleSheet,
SafeAreaView,
TouchableOpacity,
ActivityIndicator,
} from 'react-native';
import Pdf from 'react-native-pdf';
type PdfRef = InstanceType<typeof Pdf>;
const pdfResources = [
{ label: '测试文档', url: 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' },
{ label: '示例PDF', url: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' },
];
export default function App() {
const [currentUrl, setCurrentUrl] = useState(pdfResources[0].url);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(0);
const pdfRef = useRef<PdfRef>(null);
const handleLoadComplete = (numberOfPages: number, filePath: string) => {
console.log('PDF加载完成,页数:', numberOfPages, '路径:', filePath);
setIsLoading(false);
setError(null);
setTotalPages(numberOfPages);
};
const handleError = (err: any) => {
console.log('PDF加载错误:', err);
setIsLoading(false);
setError(typeof err === 'string' ? err : err?.message || 'PDF 加载失败');
};
const handlePageChanged = (page: number, numberOfPages: number) => {
setCurrentPage(page);
setTotalPages(numberOfPages);
};
const goToPrevPage = () => {
if (currentPage > 1 && pdfRef.current) {
pdfRef.current.setPage(currentPage - 1);
}
};
const goToNextPage = () => {
if (currentPage < totalPages && pdfRef.current) {
pdfRef.current.setPage(currentPage + 1);
}
};
const switchPdf = (url: string) => {
if (url !== currentUrl) {
setCurrentUrl(url);
setIsLoading(true);
setError(null);
setCurrentPage(1);
}
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<Text style={styles.title}>PDF 查看器</Text>
<View style={styles.tabs}>
{pdfResources.map((pdf) => (
<TouchableOpacity
key={pdf.url}
style={[styles.tab, currentUrl === pdf.url && styles.activeTab]}
onPress={() => switchPdf(pdf.url)}
>
<Text style={[styles.tabText, currentUrl === pdf.url && styles.activeTabText]}>
{pdf.label}
</Text>
</TouchableOpacity>
))}
</View>
</View>
<View style={styles.pdfWrapper}>
{error ? (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>{error}</Text>
<TouchableOpacity
style={styles.retryBtn}
onPress={() => {
setError(null);
setIsLoading(true);
}}
>
<Text style={styles.retryBtnText}>重试</Text>
</TouchableOpacity>
</View>
) : (
<>
<Pdf
ref={pdfRef}
source={{ uri: currentUrl, cache: false }}
style={styles.pdf}
onLoadComplete={handleLoadComplete}
onPageChanged={handlePageChanged}
onError={handleError}
enablePaging={false}
horizontal={false}
fitPolicy={2}
spacing={0}
/>
{isLoading && (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#007AFF" />
<Text style={styles.loadingText}>加载中...</Text>
</View>
)}
</>
)}
</View>
<View style={styles.footer}>
<TouchableOpacity
style={[styles.navBtn, currentPage <= 1 && styles.navBtnDisabled]}
onPress={goToPrevPage}
disabled={currentPage <= 1}
>
<Text style={[styles.navBtnText, currentPage <= 1 && styles.navBtnTextDisabled]}>
上一页
</Text>
</TouchableOpacity>
<Text style={styles.pageNum}>
{currentPage} / {totalPages || '-'}
</Text>
<TouchableOpacity
style={[styles.navBtn, currentPage >= totalPages && styles.navBtnDisabled]}
onPress={goToNextPage}
disabled={currentPage >= totalPages}
>
<Text style={[styles.navBtnText, currentPage >= totalPages && styles.navBtnTextDisabled]}>
下一页
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
header: {
backgroundColor: '#fff',
paddingHorizontal: 16,
paddingTop: 12,
paddingBottom: 8,
borderBottomWidth: 1,
borderBottomColor: '#e0e0e0',
},
title: {
fontSize: 18,
fontWeight: '600',
color: '#333',
textAlign: 'center',
marginBottom: 10,
},
tabs: {
flexDirection: 'row',
justifyContent: 'center',
gap: 8,
},
tab: {
paddingHorizontal: 16,
paddingVertical: 6,
borderRadius: 16,
backgroundColor: '#f0f0f0',
},
activeTab: {
backgroundColor: '#007AFF',
},
tabText: {
fontSize: 13,
color: '#666',
},
activeTabText: {
color: '#fff',
fontWeight: '500',
},
pdfWrapper: {
flex: 1,
backgroundColor: '#fff',
},
pdf: {
flex: 1,
},
loadingContainer: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(255, 255, 255, 0.9)',
},
loadingText: {
marginTop: 10,
fontSize: 14,
color: '#666',
},
errorContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
errorText: {
fontSize: 14,
color: '#ff3b30',
textAlign: 'center',
marginBottom: 16,
},
retryBtn: {
paddingHorizontal: 20,
paddingVertical: 10,
backgroundColor: '#007AFF',
borderRadius: 8,
},
retryBtnText: {
fontSize: 14,
color: '#fff',
fontWeight: '500',
},
footer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 16,
paddingVertical: 12,
backgroundColor: '#fff',
borderTopWidth: 1,
borderTopColor: '#e0e0e0',
},
navBtn: {
paddingHorizontal: 16,
paddingVertical: 8,
backgroundColor: '#007AFF',
borderRadius: 6,
minWidth: 70,
alignItems: 'center',
},
navBtnDisabled: {
backgroundColor: '#ccc',
},
navBtnText: {
fontSize: 13,
color: '#fff',
fontWeight: '500',
},
navBtnTextDisabled: {
color: '#999',
},
pageNum: {
fontSize: 14,
color: '#333',
fontWeight: '500',
},
});
🔗 十、相关资源
📝 十一、总结
本文详细介绍了 react-native-pdf 在 HarmonyOS 平台的使用方法。通过 Pdf 组件,你可以轻松实现 PDF 文档的加载和展示。
核心要点:
- ✅ 支持 URL 和本地资源加载
- ✅ 支持缩放控制和页面间距设置
- ✅ 支持密码保护的 PDF
- ✅ 完善的加载进度和页面变化回调
适用场景:
- 电子书阅读
- 合同文档展示
- 报表预览
- 附件查看
希望本文能帮助你在 HarmonyOS 项目中顺利集成 PDF 查看组件!
更多推荐



所有评论(0)