🚀 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
npm install react-native-pdf-jsi
---







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.
| 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:
- O(1) Memory Complexity - Constant 2MB usage for files from 10MB to 10GB+
- 5.2x Faster Image Export - JPEG format with 90% quality (visually identical)
- 6+ GB/s Throughput - Industry-leading PDF compression speed
- Zero Crashes - Handles files other libraries can't (tested up to 10GB)
``bashUsing npm
npm install react-native-pdf-jsi react-native-blob-util --save
$3
React Native 0.60 and above:
`bash
cd ios && pod install
`React Native 0.59 and below:
`bash
react-native link react-native-blob-util
react-native link react-native-pdf-jsi
`$3
React Native 0.59.0 and above:
Add the following to your
android/app/build.gradle:`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:
`bash
react-native link react-native-blob-util
react-native link react-native-pdf-jsi
`$3
This package works with Expo development builds (not Expo Go, as it requires native code).
1. Install the package and peer dependencies:
`bash
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:`json
{
"expo": {
"plugins": ["react-native-pdf-jsi"]
}
}
`3. Rebuild your development build:
`bash
Generate native projects
npx expo prebuildRun on iOS
npx expo run:iosRun 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:
`bash
Build development client
eas build --profile development --platform ios
eas build --profile development --platform android
`$3
1. Open your solution in Visual Studio 2019 (e.g.,
windows\yourapp.sln)
2. Right-click Solution icon in Solution Explorer > Add > Existing Project...
3. Add node_modules\react-native-pdf-jsi\windows\RCTPdf\RCTPdf.vcxproj
4. Add node_modules\react-native-blob-util\windows\ReactNativeBlobUtil\ReactNativeBlobUtil.vcxproj
5. Right-click main application project > Add > Reference...
6. Select RCTPdf and ReactNativeBlobUtil in Solution Projects
7. In app pch.h add:
`cpp
#include "winrt/RCTPdf.h"
#include "winrt/ReactNativeBlobUtil.h"
`
8. In App.cpp add before InitializeComponent();:
`cpp
PackageProviders().Append(winrt::RCTPdf::ReactPackageProvider());
PackageProviders().Append(winrt::ReactNativeBlobUtil::ReactPackageProvider());
`Quick Start
`jsx
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 (
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}
/>
);
}const styles = StyleSheet.create({
container: {
flex: 1,
},
pdf: {
flex: 1,
width: '100%',
height: '100%',
},
});
`Documentation
Complete documentation is available at: https://euphonious-faun-24f4bc.netlify.app/
The documentation includes:
- API Reference
- Usage Guides
- Performance Optimization Tips
- Advanced Features Documentation
- Migration Guide from react-native-pdf
API Reference
$3
| 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) |
| 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 |$3
| 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 | {} |$3
-
{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)$3
#### setPage(pageNumber)
Programmatically navigate to a specific page.
`jsx
const pdfRef = useRef(null);
// Navigate to page 42
pdfRef.current?.setPage(42);
`ProGuard / R8 Configuration (Android Release Builds)
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:`proguard
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 ;
}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.JsonDeserializerKeep 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
`$3
Without these ProGuard rules, your release builds may experience:
- JSI initialization failures - Native methods won't be accessible
- PDF rendering crashes - Required classes may be obfuscated
- Event handler failures - React Native bridge methods may be removed
- Serialization errors - Gson classes needed for data conversion
$3
After adding these rules, always test your release build:
`bash
Build release APK
cd android && ./gradlew assembleReleaseTest 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.Google Play 16KB Compliance
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.
$3
| 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 |$3
- NDK r28.2 - Latest Android development toolchain
- 16KB Page Size Support - Fully compliant with Google policy
- Android 15+ Ready - Future-proof architecture
- Google Play Approved - Meets all current and future requirementsPerformance Characteristics
$3
- Base Memory: ~2MB for JSI runtime
- Per PDF: ~500KB average
- Cache Overhead: ~100KB per cached page
- Automatic Cleanup: Memory optimized every 30 seconds$3
- Zero Bridge Overhead: Direct memory access between JavaScript and native code
- Sub-millisecond Operations: Critical PDF operations execute in microseconds
- Enhanced Caching: Intelligent multi-level caching system
- Batch Operations: Process multiple operations efficiently
- Progressive Loading: Background preloading queue with smart schedulingMigration from react-native-pdf
This package is a drop-in replacement for
react-native-pdf. Simply change your import:`jsx
// 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.
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
$3
1. Clone the repository
2. Install dependencies:
npm install
3. Build native libraries (Android):
`bash
cd android/src/main/cpp
mkdir build && cd build
cmake ..
make
`License
MIT License - see LICENSE file for details.
Support
- Documentation: https://euphonious-faun-24f4bc.netlify.app/
- Issues: GitHub Issues
- Author: Punith M (@126punith)
Recent Fixes
$3
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.$3
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:
`bash
npx expo install react-native-pdf-jsi react-native-blob-util @react-native-async-storage/async-storage
`Configuration (app.json):
`json
{
"expo": {
"plugins": ["react-native-pdf-jsi"]
}
}
`Note: Expo Go is NOT supported (requires native code). Use Expo development builds.
$3
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:
`jsx
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);
``See CHANGELOG.md for a complete list of changes and version history.