@meedwire/react-native-pdf-api
v0.1.1
Published
Native PDF rendering, search and text extraction API for React Native (iOS & Android), built on TurboModules + Fabric.
Maintainers
Readme
@meedwire/react-native-pdf-api
Native PDF rendering, text extraction and search for React Native (iOS &
Android), built on TurboModules + Fabric. Ships a native PdfView
component for displaying documents plus an imperative API for metadata, page
rendering, thumbnails, text extraction and search.
- 📄 Native viewer with vertical scroll, pinch‑zoom and initial page
- 🔎 Text search with page coordinates to highlight / focus results
- 🖼️ Render any page to a PNG/JPEG file (full size or thumbnail)
- 📝 Extract text per page or for the whole document
- 🌐 Built‑in native download + cache for remote (
http/https) PDFs — no extra file‑system dependency required - ⚡ New Architecture only (TurboModule + Fabric), iOS in Swift, Android in Kotlin — no hand‑written C++
Platform support
| Feature | iOS | Android | Web |
| ----------------- | -------------------- | ------------------------------- | ------------------- |
| Viewer (PdfView)| ✅ PDFKit | ✅ PdfRenderer | ⛔ falls back to View |
| Render page | ✅ | ✅ | ⛔ |
| Extract text | ✅ | ✅ Android 15 / API 35+ | returns null |
| Search text | ✅ | ✅ Android 15 / API 35+ | returns [] |
| Metadata | ✅ | Page count only | ⛔ |
| Password‑protected| ⛔ (planned) | ⛔ (planned) | ⛔ |
Use document.capabilities (from openDocumentAsync()) to check, at runtime,
whether text/search are available on the current platform/OS.
Requirements
- React Native 0.79+ with the New Architecture enabled
(
newArchEnabled=true). This package does not support the legacy architecture (Paper). - iOS 15+ with PDFKit. Android
minSdkVersion 24(text/search require API 35+).
Installation
yarn add @meedwire/react-native-pdf-api
# or
npm install @meedwire/react-native-pdf-apiiOS:
cd ios && pod installThen rebuild the native app (yarn ios / yarn android). This package contains
native code, so it does not work in Expo Go — use a development build
(npx expo prebuild + npx expo run:ios|android).
Quick start — PdfView
import { useRef } from 'react';
import { Button, StyleSheet, View } from 'react-native';
import { PdfView, type IPdfViewRef } from '@meedwire/react-native-pdf-api';
export function PdfScreen() {
const pdfRef = useRef<IPdfViewRef>(null);
return (
<View style={styles.container}>
<PdfView
ref={pdfRef}
source="https://example.com/document.pdf"
style={styles.pdf}
initialPage={0}
maxZoom={5}
pageSpacing={16}
backgroundColor="#f4f4f1"
onLoad={({ nativeEvent }) => console.log('pages', nativeEvent.pageCount)}
onPageChange={({ nativeEvent }) => console.log('page', nativeEvent.currentPage)}
onError={({ nativeEvent }) => console.warn(nativeEvent.code, nativeEvent.message)}
/>
<Button
title="Find"
onPress={() => pdfRef.current?.searchTextAsync('contract', { focus: true })}
/>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
pdf: { flex: 1 },
});
currentPage,initialPage,pageIndexandresultIndexare zero‑based.
Sources
type TypePdfSource =
| string
| { uri: string; headers?: Record<string, string>; cacheKey?: string; fileName?: string };http/https sources are downloaded to the native cache before rendering;
headers are sent with that request. Local file://, absolute paths and (on
Android) content:// URIs are passed straight through.
Imperative API
import { openDocumentAsync, clearPdfCacheAsync } from '@meedwire/react-native-pdf-api';
const document = await openDocumentAsync({
uri: 'https://example.com/document.pdf',
headers: { Authorization: `Bearer ${token}` },
cacheKey: 'document-v1.pdf',
});
try {
const metadata = await document.getMetadataAsync();
const page0 = await document.getPageInfoAsync(0);
const rendered = await document.renderPageAsync(0, { format: 'png', width: 1200 });
const thumb = await document.getThumbnailAsync(0);
const text = await document.getTextAsync();
const matches = await document.searchTextAsync('client', { maxResults: 10 });
} finally {
await document.closeAsync();
}
await clearPdfCacheAsync();API reference
PdfView props
| Prop | Type | Default | Description |
| --------------------- | ---------------- | ----------- | --------------------------------------------- |
| source | TypePdfSource | required | Local or remote PDF. |
| style | ViewStyle | – | Give it real dimensions (e.g. flex: 1). |
| backgroundColor | string | #f4f4f1 | Viewer background. |
| initialPage | number | 0 | Zero‑based initial page. |
| pageSpacing | number | 16 | Spacing between pages. |
| maxZoom | number | 5 | Maximum zoom factor. |
| maxPageResolution | number | 2048 | Android: largest rendered bitmap side. |
| singlePage | boolean | false | Render only the initial page. |
| onLoad | (e) => void | – | { documentId, pageCount, sourceUri, capabilities } |
| onPageChange | (e) => void | – | { currentPage, pageCount } |
| onError | (e) => void | – | { code, message } |
Handlers can be inline arrow functions — the component keeps the latest callbacks in refs, so passing new identities each render does not reload the document.
onPageChangefires when the current page changes during scroll.
PdfView ref (IPdfViewRef)
openDocumentAsync()→IPdfDocumentgetTextAsync(pageIndex?)→string | nullsearchTextAsync(query, options?)→IPdfSearchResult[](also highlights/focuses)clearSearchAsync()closeDocumentAsync()
IPdfDocument
documentId, pageCount, sourceUri, capabilities, plus
getMetadataAsync(), getPageInfoAsync(pageIndex),
renderPageAsync(pageIndex, options?), getThumbnailAsync(pageIndex, options?),
getTextAsync(pageIndex?), searchTextAsync(query, options?), closeAsync().
Render options
type IPdfRenderOptions = {
format?: 'png' | 'jpeg'; // default png
quality?: number; // 0..1, default 0.9
width?: number; // keeps aspect ratio if only one is set
height?: number;
scale?: number; // used when width/height absent
backgroundColor?: string;
maxPixels?: number; // default 16_777_216, else ERR_PDF_RENDER_TOO_LARGE
};Error codes (onError / rejected promises)
ERR_PDF_SOURCE, ERR_PDF_OPEN, ERR_PDF_LOCKED, ERR_PDF_PAGE_OUT_OF_BOUNDS,
ERR_PDF_PAGE, ERR_PDF_DOCUMENT_NOT_FOUND, ERR_PDF_RENDER_TOO_LARGE,
ERR_PDF_RENDER, ERR_PDF_TEXT_UNSUPPORTED, ERR_PDF_SEARCH_UNSUPPORTED.
Screenshots
The example app (example/) demonstrates the viewer, search highlight/focus and
page navigation. To capture screenshots, run it on a simulator/emulator and save
the images under docs/screenshots/ — see the
capture guide.
# iOS
cd example/ios && pod install && cd -
npx react-native run-ios --simulator "iPhone 16"
# Android (with an emulator running)
npx react-native run-androidContributing
This is a create-react-native-library project.
yarn # install
yarn typecheck # TypeScript
yarn lint # ESLint + Prettier
yarn test # Jest
yarn prepare # build with react-native-builder-bobThe example app under example/ is the development harness. After changing
native code, rebuild it (pod install for iOS, a fresh Gradle build for
Android).
License
MIT © Meedwire
