
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
react-native-pdf-jsi
Advanced tools
š Ultra-fast React Native PDF viewer with JSI (JavaScript Interface) integration for maximum performance. Features lazy loading, smart caching, progressive loading, and zero-bridge overhead operations. Perfect for large PDF files with 30-day persistent c
ā¶ļø Watch on YouTube Shorts
High-performance React Native PDF viewer with JSI (JavaScript Interface) acceleration. A drop-in replacement for react-native-pdf with enhanced performance, Google Play compliance, and advanced features.
searchTextDirect(pdfId, term, startPage, endPage) with bounding rects, and highlight rendering via pdfId + highlightRects props (Android & iOS)| Operation | Time | Throughput | Memory | vs Competition |
|---|---|---|---|---|
| 88MB PDF Compression | 13-16ms | 6,382 MB/s | 2 MB | 20-380x faster |
| Image Export (JPEG) | 37ms | N/A | 2 MB | 5.2x faster than PNG |
| Image Export (PNG) | 194ms | N/A | 2 MB | Baseline |
| File I/O Operations | <2ms | N/A | Minimal | Instant |
| Page Navigation | 0-3ms | N/A | Constant | Instant |
Key Achievements:
# Using npm
npm install react-native-pdf-jsi react-native-blob-util --save
# or using yarn
yarn add react-native-pdf-jsi react-native-blob-util
React Native 0.60 and above:
cd ios && pod install
React Native 0.59 and below:
react-native link react-native-blob-util
react-native link react-native-pdf-jsi
React Native 0.59.0 and above:
Add the following to your android/app/build.gradle:
android {
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
pickFirst 'lib/x86_64/libjsc.so'
pickFirst 'lib/arm64-v8a/libjsc.so'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
pickFirst 'lib/x86_64/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
}
}
React Native 0.59.0 and below:
react-native link react-native-blob-util
react-native link react-native-pdf-jsi
This package works with Expo development builds (not Expo Go, as it requires native code).
1. Install the package and peer dependencies:
npx expo install react-native-pdf-jsi react-native-blob-util @react-native-async-storage/async-storage
2. Add the config plugin to your app.json or app.config.js:
{
"expo": {
"plugins": ["react-native-pdf-jsi"]
}
}
3. Rebuild your development build:
# Generate native projects
npx expo prebuild
# Run on iOS
npx expo run:ios
# Run on Android
npx expo run:android
Note: The config plugin automatically configures:
- Android: Adds Jitpack repository for PDF rendering dependencies
- iOS: Ensures PDFKit framework is properly linked
For EAS Build users:
# Build development client
eas build --profile development --platform ios
eas build --profile development --platform android
windows\yourapp.sln)node_modules\react-native-pdf-jsi\windows\RCTPdf\RCTPdf.vcxprojnode_modules\react-native-blob-util\windows\ReactNativeBlobUtil\ReactNativeBlobUtil.vcxprojRCTPdf and ReactNativeBlobUtil in Solution Projectspch.h add:
#include "winrt/RCTPdf.h"
#include "winrt/ReactNativeBlobUtil.h"
App.cpp add before InitializeComponent();:
PackageProviders().Append(winrt::RCTPdf::ReactPackageProvider());
PackageProviders().Append(winrt::ReactNativeBlobUtil::ReactPackageProvider());
import React, { useState } from 'react';
import { View, StyleSheet } from 'react-native';
const PdfModule = require('react-native-pdf-jsi');
const Pdf = PdfModule.default;
export default function PDFExample() {
const [totalPages, setTotalPages] = useState(0);
const [currentPage, setCurrentPage] = useState(1);
const source = {
uri: 'https://example.com/document.pdf',
cache: true
};
return (
<View style={styles.container}>
<Pdf
source={source}
style={styles.pdf}
onLoadComplete={(numberOfPages, filePath, size) => {
console.log(`PDF loaded: ${numberOfPages} pages`);
setTotalPages(numberOfPages);
}}
onPageChanged={(page, numberOfPages) => {
console.log(`Current page: ${page} of ${numberOfPages}`);
setCurrentPage(page);
}}
onError={(error) => {
console.error('PDF Error:', error);
}}
trustAllCerts={false}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
pdf: {
flex: 1,
width: '100%',
height: '100%',
},
});
Complete documentation is available at: https://euphonious-faun-24f4bc.netlify.app/
The documentation includes:
| Property | Type | Default | Description |
|---|---|---|---|
source | object | required | PDF source like {uri: '...', cache: false} |
page | number | 1 | Initial page index |
scale | number | 1.0 | Scale factor (must be between minScale and maxScale) |
minScale | number | 1.0 | Minimum scale |
maxScale | number | 3.0 | Maximum scale |
horizontal | boolean | false | Draw pages horizontally |
fitPolicy | number | 2 | 0: fit width, 1: fit height, 2: fit both |
spacing | number | 10 | Spacing between pages |
password | string | "" | PDF password if required |
enablePaging | boolean | false | Show only one page at a time |
enableRTL | boolean | false | Right-to-left page order |
enableAntialiasing | boolean | true | Enable antialiasing (Android only) |
enableAnnotationRendering | boolean | true | Enable annotation rendering |
enableDoubleTapZoom | boolean | true | Enable double tap to zoom |
singlePage | boolean | false | Show only first page (thumbnail mode) |
pdfId | string | undefined | Stable ID for this PDF (e.g. "main-pdf"); required for searchTextDirect() so native code can resolve the document path |
highlightRects | array | undefined | Array of { page: number, rect: string } (rect: "left,top,right,bottom" in PDF points) to draw yellow highlights; use with searchTextDirect() results |
trustAllCerts | boolean | true | Allow self-signed certificates |
onLoadProgress | function(percent) | null | Loading progress callback (0-1) |
onLoadComplete | function(pages, path, size, tableContents) | null | Called when PDF loads |
onPageChanged | function(page, numberOfPages) | null | Called when page changes |
onError | function(error) | null | Called on error |
onPageSingleTap | function(page) | null | Called on single tap |
onScaleChanged | function(scale) | null | Called when scale changes |
onPressLink | function(uri) | null | Called when link is tapped |
| Parameter | Description | Default |
|---|---|---|
uri | PDF source (URL, file path, base64, etc.) | required |
cache | Use cache or not | false |
cacheFileName | Specific file name for cached PDF | SHA1(uri) |
expiration | Cache expiration in seconds (0 = never) | 0 |
method | HTTP method for URL sources | "GET" |
headers | HTTP headers for URL sources | {} |
{uri: "http://xxx/xxx.pdf"} - Load from URL{uri: "file:///absolute/path/to/xxx.pdf"} - Load from local file{uri: "data:application/pdf;base64,JVBERi0xLjcKJc..."} - Load from base64{uri: "bundle-assets://xxx.pdf"} - Load from app bundle/assets{require("./test.pdf")} - Load from bundled asset (iOS only)Programmatically navigate to a specific page.
const pdfRef = useRef(null);
<Pdf ref={pdfRef} source={source} />
// Navigate to page 42
pdfRef.current?.setPage(42);
Programmatic PDF text search. Returns a promise that resolves to an array of { page, text, rect } (rect is "left,top,right,bottom" in PDF coordinates). Use with pdfId and highlightRects to show highlights.
import Pdf, { searchTextDirect } from 'react-native-pdf-jsi';
const PDF_ID = 'main-pdf';
const [highlights, setHighlights] = useState([]);
<Pdf
pdfId={PDF_ID}
source={source}
highlightRects={highlights.filter(r => r.rect).map(r => ({ page: r.page, rect: r.rect }))}
onLoadComplete={(pages, path) => { /* path is registered for search */ }}
/>
// After PDF has loaded, e.g. on button press:
const results = await searchTextDirect(PDF_ID, 'Lorem', 1, 999);
setHighlights(results);
On iOS, the path is registered when the document loads (local file only); you can also call NativeModules.PDFJSIManager.registerPathForSearch(pdfId, path) after onLoadComplete if needed. Highlights stay aligned when zooming and scrolling on both Android and iOS.
IMPORTANT: If you're using ProGuard or R8 code shrinking in your release builds, you must add the following rules to prevent crashes. These rules preserve JSI classes and native module interfaces that are required at runtime.
Add to your android/app/proguard-rules.pro file:
# react-native-pdf-jsi ProGuard Rules
# Keep all JSI-related classes
-keep class org.wonday.pdf.PDFJSIManager { *; }
-keep class org.wonday.pdf.PDFJSIModule { *; }
-keep class org.wonday.pdf.EnhancedPdfJSIBridge { *; }
-keep class org.wonday.pdf.RNPDFJSIPackage { *; }
# Keep PDF view classes
-keep class org.wonday.pdf.PdfView { *; }
-keep class org.wonday.pdf.PdfManager { *; }
-keep class org.wonday.pdf.RNPDFPackage { *; }
# Keep native methods (JNI)
-keepclasseswithmembernames class * {
native <methods>;
}
# Keep JSI interface methods
-keepclassmembers class * {
@com.facebook.react.bridge.ReactMethod *;
}
# Keep React Native bridge classes
-keep @com.facebook.react.bridge.ReactModule class * { *; }
-keep class com.facebook.react.bridge.** { *; }
# Keep Gson classes (used for serialization)
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.google.gson.** { *; }
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Keep PdfiumAndroid classes
-keep class io.legere.pdfiumandroid.** { *; }
-keep class com.github.barteksc.pdfviewer.** { *; }
# Keep file downloader and manager classes
-keep class org.wonday.pdf.FileDownloader { *; }
-keep class org.wonday.pdf.FileManager { *; }
# Preserve line numbers for crash reporting
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
Without these ProGuard rules, your release builds may experience:
After adding these rules, always test your release build:
# Build release APK
cd android && ./gradlew assembleRelease
# Test on device
adb install app/build/outputs/apk/release/app-release.apk
If you encounter crashes, check the stack trace and add additional -keep rules for any classes mentioned in the error logs.
Starting November 1, 2025, Google Play requires apps to support 16KB page sizes for Android 15+ devices. react-native-pdf-jsi is fully compliant with this requirement.
| Library | 16KB Support | Google Play Status | Migration Needed |
|---|---|---|---|
react-native-pdf | Not Supported | Will be blocked | Required |
react-native-pdf-lib | Unknown | Likely blocked | Required |
react-native-pdf-jsi | Fully Supported | Compliant | None |
This package is a drop-in replacement for react-native-pdf. Simply change your import:
// Before
import Pdf from 'react-native-pdf';
// After
const PdfModule = require('react-native-pdf-jsi');
const Pdf = PdfModule.default;
All existing props and callbacks work identically. No other code changes required.
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
npm installcd android/src/main/cpp
mkdir build && cd build
cmake ..
make
MIT License - see LICENSE file for details.
Fixed iOS pinch-to-zoom not working when the scroll view delegate was set to the view itself or when the delegate proxy's primary didn't implement viewForZoomingInScrollView. Implemented the missing viewForZoomingInScrollView: in RNPDFPdfView so the scroll view receives the correct zoomable view. Fixes #23 (PR #22).
Fixed issue where the PDF instance was destroyed on Android when navigating away and returning to the screen (#20). The PDF is now preserved in memory during navigation (matching iOS behavior) and only recycled when the component unmounts.
Added Expo config plugin for seamless integration with Expo development builds. The package now works with npx expo prebuild and npx expo run:ios/android.
Installation:
npx expo install react-native-pdf-jsi react-native-blob-util @react-native-async-storage/async-storage
Configuration (app.json):
{
"expo": {
"plugins": ["react-native-pdf-jsi"]
}
}
Note: Expo Go is NOT supported (requires native code). Use Expo development builds.
Fixed "Unable to resolve module react-native-pdf-jsi/src/PDFCompressor" error (#17). The PDFCompressor module is now properly exported and accessible. Also fixed iOS compilation error for missing RCTLogInfo import. The compression feature now works correctly with accurate size estimates (~15-18% compression using native zlib deflate).
Usage:
import { PDFCompressor, CompressionPreset } from 'react-native-pdf-jsi';
// Compress a PDF
const result = await PDFCompressor.compressWithPreset(pdfPath, CompressionPreset.WEB);
console.log(`Compressed: ${result.originalSizeMB}MB ā ${result.compressedSizeMB}MB`);
Use v4.2.1 it contains stable fixes for IOS with unwanted debug logs removed
Fixed performance issue where path-related handlers were running unnecessarily when the path value hadn't actually changed. The fix filters out "path" from effectiveChangedProps when pathActuallyChanged=NO, preventing unnecessary reconfigurations of spacing, display direction, scroll views, usePageViewController, and other path-dependent handlers. This reduces unnecessary rerenders and improves performance, especially when navigating between pages. Addresses issue #7 (Page Prop Causes Full Rerender).
Fixed critical issue where pinch-to-zoom gestures were not working on iOS. The fix removes interfering custom gesture recognizers and enables PDFView's native pinch-to-zoom functionality, which now works smoothly on both iOS and Android.
See CHANGELOG.md for a complete list of changes and version history.
FAQs
š Ultra-fast React Native PDF viewer with JSI (JavaScript Interface) integration for maximum performance. Features lazy loading, smart caching, progressive loading, and zero-bridge overhead operations. Perfect for large PDF files with 30-day persistent c
The npm package react-native-pdf-jsi receives a total of 1,764 weekly downloads. As such, react-native-pdf-jsi popularity was classified as popular.
We found that react-native-pdf-jsi demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Ā It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.