Імплементація просмотру PDF-документів у мобільному застосунку
PDF-вьювер — задача, яка виглядає тривіальною, поки не сталкиваєшся з 200-сторінковим PDF на iPhone SE: скролл дергається, пам'ять зростає, застосунок отримує SIGKILL від iOS. Проблема в рендерингу: кожна сторінка PDF — це векторний документ, вимагаючий растеризації в растрове зображення під конкретний масштаб та розрішення екрана.
Нативний рендеринг vs WebView
<WebView source={{ uri: 'file://...' }} — найшвидший спосіб показати PDF. iOS WebKit рендерить PDF нативно. Мінуси: немає контролю над UI (не додати custom toolbar, аннотації, пошук), PDF відкривається цілком в пам'ять. На 50+ сторінках — ризик OOM.
Нативний рендеринг через PDFKit (iOS) та PdfRenderer (Android) дає повний контроль, але вимагає нативних модулів у React Native.
react-native-pdf: готове рішення
react-native-pdf — React Native обгортка над нативними PDF API обох платформ. Під капотом: PDFKit на iOS, PdfRenderer на Android. Постраничный рендеринг — у пам'яті лише видимі сторінки + 1–2 буферні.
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 }} // кешуємо завантажений файл
onLoadComplete={(numberOfPages) => setTotalPages(numberOfPages)}
onPageChanged={(page) => setCurrentPage(page)}
onError={(error) => console.error(error)}
style={{ flex: 1 }}
enablePaging // листання постранично, а не скролл
horizontal // горизонтальний режим
fitPolicy={0} // 0 = fit width, 1 = fit height, 2 = fit both
scale={1.0}
minScale={0.5}
maxScale={3.0}
/>
);
};
cache: true — перша завантаження зберігає файл в директорію кеша застосунку. Повторне відкриття не робить HTTP-запит. Важливо: кеш не керується автоматично, потрібна очистка по TTL або розміру.
Проблема з великими PDF: ленива завантаження сторінок
При відкритті PDF з URL бібліотека завантажує весь файл перед рендерингом. 50 МБ PDF — користувач чекає. Правильне рішення: HTTP Range requests, якщо сервер підтримує Accept-Ranges: bytes.
Нативна реалізація для iOS через PDFDocument(url:) підтримує progressive rendering при URLSession з Range-запитами. Для React Native — custom native module, який використовує PDFDocument з CGPDFDataProvider для потокової завантаження.
Для більшості проектів простіше: показуємо першу сторінку як placeholder (thumbnail, попередньо згенерований на сервері через pdf2pic або ghostscript), поки завантажується повний файл.
Пошук по тексту та аннотації
react-native-pdf підтримує пошук через pdfRef.current?.startSearch(query) — нативний пошук по тексту документа. Підсвітка збігів вбудована.
Аннотації (виділення, заметки, підписи) — окрема задача. PSPDFKit — комерційний SDK ($199/мес) з повним набором аннотацій. Для open-source: PDFTron (тепер Apryse) з free-тиром.
Безпека: захищені PDF
PDF з паролем: react-native-pdf підтримує password prop. Корпоративні DRM-захищені PDF (Adobe AEPD, Microsoft IRM) — нативні бібліотеки операторів, в RN не реалізовані напрямку.
Flutter: syncfusion_flutter_pdfviewer
Syncfusion надає SfPdfViewer — повнофункціональний PDF вьювер для Flutter з постраничным рендерингом, пошуком і виділенням. Community-ліцензія безплатна при доходе до $1 млн/рік.
SfPdfViewer.network(
'https://cdn.example.com/document.pdf',
onPageChanged: (PdfPageChangedDetails details) {
setState(() => _currentPage = details.newPageNumber);
},
)
Оцінка
PDF вьювер з кешуванням, пошуком та прогресивною завантаженням: 2–3 тижні для однієї платформи. Кросплатформна реалізація з аннотаціями: 4–6 тижнів.







