Implementing PDF Document Viewer in Mobile Application
PDF viewer is a task that looks trivial until you encounter a 200-page PDF on iPhone SE: scrolling stutters, memory grows, app gets SIGKILL from iOS. The problem is in rendering: each PDF page is a vector document requiring rasterization into raster image at specific scale and screen resolution.
Native Rendering vs WebView
<WebView source={{ uri: 'file://...' }} is the fastest way to show PDF. iOS WebKit renders PDF natively. Drawbacks: no UI control (can't add custom toolbar, annotations, search), entire PDF loads into memory. On 50+ pages — OOM risk.
Native rendering via PDFKit (iOS) and PdfRenderer (Android) provides full control but requires native modules in React Native.
react-native-pdf: Ready Solution
react-native-pdf is React Native wrapper over native PDF APIs of both platforms. Under the hood: PDFKit on iOS, PdfRenderer on Android. Page-by-page rendering — only visible pages + 1–2 buffer in memory.
import Pdf from 'react-native-pdf';
const PDFViewer = ({ uri }: { uri: string }) => {
const [totalPages, setTotalPages] = useState(0);
const [currentPage, setCurrentPage] = useState(1);
return (
<Pdf
source={{ uri, cache: true }} // cache downloaded file
onLoadComplete={(numberOfPages) => setTotalPages(numberOfPages)}
onPageChanged={(page) => setCurrentPage(page)}
onError={(error) => console.error(error)}
style={{ flex: 1 }}
enablePaging // page-by-page navigation, not scroll
horizontal // horizontal mode
fitPolicy={0} // 0 = fit width, 1 = fit height, 2 = fit both
scale={1.0}
minScale={0.5}
maxScale={3.0}
/>
);
};
cache: true — first load saves file to app cache directory. Reopening doesn't make HTTP request. Important: cache isn't managed automatically; cleanup by TTL or size needed.
Problem with Large PDFs: Lazy Page Loading
Opening PDF from URL, library downloads entire file before rendering. 50 MB PDF — user waits. Correct solution: HTTP Range requests if server supports Accept-Ranges: bytes.
Native iOS implementation via PDFDocument(url:) supports progressive rendering with URLSession Range requests. For React Native — custom native module using PDFDocument with CGPDFDataProvider for streaming loading.
For most projects simpler: show first page as placeholder (thumbnail, pre-generated on server via pdf2pic or ghostscript) while full file downloads.
Text Search and Annotations
react-native-pdf supports search via pdfRef.current?.startSearch(query) — native text search in document. Match highlighting built-in.
Annotations (highlighting, notes, signatures) — separate task. PSPDFKit — commercial SDK ($199/month) with full annotation set. For open-source: PDFTron (now Apryse) with free tier.
Security: Protected PDFs
Password-protected PDF: react-native-pdf supports password prop. Corporate DRM-protected PDF (Adobe AEPD, Microsoft IRM) — operator native libraries, not directly implemented in RN.
Flutter: syncfusion_flutter_pdfviewer
Syncfusion provides SfPdfViewer — full-featured PDF viewer for Flutter with page-by-page rendering, search and highlighting. Community license free up to $1M/year revenue.
SfPdfViewer.network(
'https://cdn.example.com/document.pdf',
onPageChanged: (PdfPageChangedDetails details) {
setState(() => _currentPage = details.newPageNumber);
},
)
Assessment
PDF viewer with caching, search and progressive loading: 2–3 weeks for one platform. Cross-platform with annotations: 4–6 weeks.







