如何在Expo Go项目中无需原生模块显示PDF文件?
在Expo Go中内联显示PDF的可行方案
如果你不想依赖需要原生代码的库,同时要在应用内完成PDF查看,以下几个方案完全兼容Expo Go,无需自定义原生模块:
方案1:expo-web-view + PDF.js CDN(推荐)
这是兼容性最好的方案,利用WebView加载PDF.js的官方在线查看器,在应用内渲染PDF,支持缩放、搜索、页码跳转等完整功能,体验接近原生。
步骤:
- 安装依赖:
npx expo install expo-web-view expo-file-system
- 远程PDF渲染代码:
import { WebView } from 'expo-web-view'; export default function RemotePDFViewer() { const pdfUrl = 'https://example.com/your-document.pdf'; // 用PDF.js查看器包裹PDF链接 const viewerUrl = `https://mozilla.github.io/pdf.js/web/viewer.html?file=${encodeURIComponent(pdfUrl)}`; return ( <WebView source={{ uri: viewerUrl }} style={{ flex: 1 }} javaScriptEnabled={true} allowsInlineMediaPlayback={true} /> ); }
- 本地PDF渲染(结合文件选择):
import { WebView } from 'expo-web-view'; import * as DocumentPicker from 'expo-document-picker'; import * as FileSystem from 'expo-file-system'; import { useState, Button } from 'react'; import { View } from 'react-native'; export default function LocalPDFViewer() { const [pdfDataUri, setPdfDataUri] = useState(null); const pickLocalPDF = async () => { const pickResult = await DocumentPicker.getDocumentAsync({ type: 'application/pdf' }); if (pickResult.canceled) return; const fileUri = pickResult.assets[0].uri; // 将本地PDF转为base64 Data URI,避免跨域问题 const base64Content = await FileSystem.readAsStringAsync(fileUri, { encoding: 'base64' }); setPdfDataUri(`data:application/pdf;base64,${base64Content}`); }; return ( <View style={{ flex: 1 }}> <Button title="选择本地PDF" onPress={pickLocalPDF} /> {pdfDataUri && ( <WebView source={{ uri: `https://mozilla.github.io/pdf.js/web/viewer.html?file=${encodeURIComponent(pdfDataUri)}` }} style={{ flex: 1, marginTop: 10 }} javaScriptEnabled={true} /> )} </View> ); }
如果需要离线使用,可以把PDF.js的静态资源(viewer.html、js文件等)下载到项目的assets目录,通过expo-file-system获取本地路径加载,摆脱网络依赖。
方案2:纯JS渲染库react-native-pdf-js
这个库完全用JavaScript实现PDF渲染,没有原生依赖,适合小型PDF文件,渲染性能略逊于PDF.js WebView方案,但更轻量化。
步骤:
- 安装依赖:
npm install react-native-pdf-js
- 代码示例:
import PDFJS from 'react-native-pdf-js'; import { View } from 'react-native'; export default function PDFJSViewer() { return ( <View style={{ flex: 1 }}> <PDFJS source={{ uri: 'https://example.com/your-document.pdf' }} style={{ flex: 1 }} onLoadComplete={(pageCount) => console.log(`共${pageCount}页`)} /> </View> ); }
方案3:expo-print转图片(仅适用于单页PDF)
如果你的PDF都是单页的,可以用expo-print把PDF转成图片,再用Image组件显示,不过多页PDF需要额外处理分页,灵活性较差。
代码示例:
import * as Print from 'expo-print'; import { Image, Button, View } from 'react-native'; import { useState } from 'react'; export default function SinglePagePDFViewer() { const [pdfImageUri, setPdfImageUri] = useState(null); const loadSinglePagePDF = async () => { const pdfUrl = 'https://example.com/single-page.pdf'; const printResult = await Print.printToFileAsync({ uri: pdfUrl, width: 600, height: 800 }); setPdfImageUri(printResult.uri); }; return ( <View style={{ flex: 1 }}> <Button title="加载单页PDF" onPress={loadSinglePagePDF} /> {pdfImageUri && ( <Image source={{ uri: pdfImageUri }} style={{ flex: 1, marginTop: 10 }} resizeMode="contain" /> )} </View> ); }
总结
- 优先选方案1,功能完整、兼容性强,适合绝大多数场景;
- 小体积PDF可以考虑方案2,更轻量化;
- 仅单页PDF时才考虑方案3。
内容的提问来源于stack exchange,提问作者Bruno Pintos
相关产品推荐
相关产品推荐

