UNPKG

react-native-pdf-jsi

Version:

🚀 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

1,330 lines (1,099 loc) 68.5 kB
# react-native-pdf-jsi 🚀 [![npm](https://img.shields.io/npm/v/react-native-pdf-jsi.svg?style=flat-square)](https://www.npmjs.com/package/react-native-pdf-jsi) [![Downloads](https://img.shields.io/npm/dm/react-native-pdf-jsi.svg?style=flat-square)](https://www.npmjs.com/package/react-native-pdf-jsi) [![GitHub stars](https://img.shields.io/github/stars/126punith/react-native-enhanced-pdf.svg?style=flat-square)](https://github.com/126punith/react-native-enhanced-pdf) **The fastest React Native PDF viewer with JSI acceleration - up to 80x faster than traditional bridge!** ### Key Advantages: - ✅ **Google Play 16KB Compliant** - Ready for Android 15+ requirements - ⚡ **High Performance** - JSI integration for faster rendering - 🚀 **Easy Migration** - Drop-in replacement for existing PDF libraries - 📄 **Lazy Loading** - Optimized loading for large PDF files - 🎯 **Smart Caching** - 30-day persistent cache system - 🛡️ **Future-Proof** - Built with latest NDK r27+ and modern toolchain A high-performance React Native PDF viewer component with JSI (JavaScript Interface) integration for enhanced speed and efficiency. Perfect for large PDF files with lazy loading, smart caching, progressive loading, and zero-bridge overhead operations. ## ✅ **Google Play 16KB Page Size Compliance** Starting November 1, 2025, Google Play will require apps to support 16KB page sizes for devices with Android 15+. **react-native-pdf-jsi is built with NDK r27+ and fully supports Android 15+ requirements**, ensuring your app meets Google Play policy requirements. ### **Compliance Status:** | 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 | ### **Technical Implementation:** - ✅ **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 requirements - ✅ **Drop-in Replacement** - Easy migration from existing libraries ## 🎉 Version 2.2.4 - Critical 16KB Bug Fix! **Resolves 16KB page size compatibility issues for Google Play compliance!** ### 🚀 **What's New in v2.2.4:** - **🐛 16KB Page Size Fix** - Resolved critical 16KB page size compatibility issues - **✅ NDK r28.2 Update** - Updated to NDK 28.2.13676358 with proper 16KB page alignment - **✅ CMake Configuration** - Added ANDROID_PAGE_SIZE_AGNOSTIC=ON flag for compliance - **✅ Dependency Updates** - Updated pdfiumandroid to v1.0.32 and gson to v2.11.0 - **✅ Android 15+ Ready** - Full Google Play compliance for Android 15+ requirements ## 🎉 Version 2.2.3 - Bug Fix Release! **Critical bug fix for React Native 0.81 JSI initialization on Android!** ### 🚀 **What's New in v2.2.3:** - **🐛 JSI Initialization Fix** - Resolved crash when calling initializeJSI() on React Native 0.81 Android - **✅ Error Handling** - Added proper error handling for JSI initialization - **✅ RN 0.81 Compatibility** - Full compatibility with React Native 0.81 on Android - **✅ Stability Improvements** - Enhanced stability and error recovery ## 🎉 Version 2.2.2 - Production Ready with Latest NDK! **Includes all the fixes from the GitHub community with the latest NDK r28.2 - tested and verified in production apps!** ### 🚀 **What's New in v2.2.2:** - **✅ Latest NDK r28.2** - Updated to NDK 28.2.13676358 (matches community solution exactly) - **✅ Community Verified Fixes** - Includes all solutions from GitHub issue #970 - **✅ Android SDK 35** - Full support for Android 15+ - **✅ Enhanced 16KB Compliance** - Improved page size alignment with linker flags - **✅ Production Tested** - Verified working in real Android Studio APK analyzer ## 🎉 Version 2.2.0 - Enhanced 16KB Compliance & Documentation! **We've completely rewritten the core architecture with revolutionary performance improvements!** - **🚀 Complete JSI Integration**: Full native C++ implementation for Android and iOS - **📄 Lazy Loading System**: Revolutionary approach to handling large PDF files - **🎯 Smart Caching Engine**: 30-day persistent cache with intelligent management - **📊 Progressive Loading**: Batch-based loading for optimal user experience - **💾 Advanced Memory Management**: Intelligent memory optimization for large documents *This is a drop-in replacement for react-native-pdf with significant performance improvements.* ## 🚀 Performance Breakthrough | Operation | Standard Bridge | JSI Mode | **Improvement** | |-----------|-----------------|----------|-----------------| | Page Render | 45ms | 2ms | **22.5x faster** | | Page Metrics | 12ms | 0.5ms | **24x faster** | | Cache Access | 8ms | 0.1ms | **80x faster** | | Text Search | 120ms | 15ms | **8x faster** | ## 🔥 **Why Choose react-native-pdf-jsi?** ### **Performance Benefits:** - **⚡ High Performance**: Direct JavaScript-to-Native communication via JSI - **📄 Lazy Loading**: Optimized loading for large PDF files - **🎯 Smart Caching**: 30-day persistent cache with intelligent memory management - **🔄 Progressive Loading**: Batch-based loading for better user experience - **💾 Memory Optimized**: Advanced memory management for large documents - **🔍 Advanced Search**: Cached text search with bounds detection - **📊 Performance Metrics**: Real-time performance monitoring ### **Compliance & Compatibility:** - **✅ Google Play Compliant**: 16KB page size support for Android 15+ - **✅ Future-Proof**: Built with latest NDK r27+ and modern toolchain - **✅ Easy Migration**: Drop-in replacement for existing PDF libraries - **✅ Cross-Platform**: Full support for iOS, Android, and Windows - **✅ Production Ready**: Stable and tested in production environments ### **Migration Benefits:** - **Simple Upgrade**: Minimal code changes required - **Better Performance**: Significant speed improvements over bridge-based libraries - **Compliance Ready**: Meets current and future Google Play requirements - **Enhanced Features**: Additional functionality like lazy loading and smart caching ## 🆚 **Alternative to react-native-pdf** **react-native-pdf-jsi** is the enhanced, high-performance alternative to the standard `react-native-pdf` package. If you're experiencing slow loading times with large PDF files or need better performance, this package provides: ### **Comparison with react-native-pdf:** - **Performance**: JSI-based rendering vs bridge-based (significantly faster) - **Google Play Compliance**: 16KB page size support vs not supported - **Lazy Loading**: Built-in support vs manual implementation required - **Caching**: Advanced persistent cache vs basic caching - **Memory Management**: Optimized for large files vs standard approach - **Migration**: Drop-in replacement with minimal code changes ### **When to Consider Migration:** - **Large PDF Files**: Experiencing slow loading times - **Google Play Compliance**: Need to meet Android 15+ requirements - **Performance Issues**: Current PDF rendering is too slow - **Enhanced Features**: Want lazy loading and smart caching - **Future-Proofing**: Preparing for upcoming Android requirements ### **Migration Benefits:** - **Improved Performance**: Faster rendering and loading - **Better User Experience**: Lazy loading and progressive rendering - **Compliance**: Meets current and future Google Play requirements - **Enhanced Features**: Additional functionality out of the box - **Easy Upgrade**: Minimal code changes required ## ✨ Features ### Core Features * Read a PDF from URL, blob, local file or asset and can cache it * Display horizontally or vertically * Drag and zoom * Double tap for zoom * Support password protected PDF * Jump to a specific page in the PDF ### 🚀 JSI Enhanced Features * **Zero Bridge Overhead** - Direct JavaScript-to-Native communication * **Enhanced Caching** - Multi-level intelligent caching system * **Batch Operations** - Process multiple operations efficiently * **Memory Optimization** - Automatic memory management and cleanup * **Real-time Performance Metrics** - Monitor and optimize PDF operations * **Graceful Fallback** - Seamless bridge mode when JSI unavailable * **Progressive Loading** - Smart preloading with background queue processing * **Lazy Loading** - Optimized loading for large PDF files with configurable preload radius * **Advanced Search** - Cached text search with bounds detection * **React Hooks** - Easy integration with `usePDFJSI` hook * **Enhanced Components** - Drop-in replacement with automatic JSI detection ## 📱 Supported Platforms - ✅ **Android** (with full JSI acceleration - up to 80x faster) - ✅ **iOS** (enhanced bridge mode with smart caching and progressive loading) - ✅ **Windows** (standard bridge mode) ## 🛠 Installation ```bash # 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 ``` ## 🚀 **Quick Start** ```jsx // Import the Pdf component from react-native-pdf-jsi const PdfModule = require('react-native-pdf-jsi'); const Pdf = PdfModule.default; // Use the component with the same API as react-native-pdf <Pdf source={{ uri: 'https://example.com/document.pdf' }} style={{ flex: 1 }} onLoadComplete={(numberOfPages, filePath) => { console.log(`PDF loaded: ${numberOfPages} pages`); }} onPageChanged={(page, numberOfPages) => { console.log(`Current page: ${page} of ${numberOfPages}`); }} trustAllCerts={false} /> ``` **Drop-in replacement for react-native-pdf with enhanced performance and Google Play compliance.** Then follow the instructions for your platform to link react-native-pdf-jsi into your project: ### iOS installation <details> <summary>iOS details</summary> **React Native 0.60 and above** Run `pod install` in the `ios` directory. Linking is not required in React Native 0.60 and above. **React Native 0.59 and below** ```bash react-native link react-native-blob-util react-native link react-native-pdf-jsi ``` </details> ### Android installation <details> <summary>Android details</summary> **If you use RN 0.59.0 and above**, please add following to your android/app/build.gradle** ```diff 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 ``` </details> ### Windows installation <details> <sumary>Windows details</summary> - Open your solution in Visual Studio 2019 (eg. `windows\yourapp.sln`) - Right-click Solution icon in Solution Explorer > Add > Existing Project... - If running RNW 0.62: add `node_modules\react-native-pdf\windows\RCTPdf\RCTPdf.vcxproj` - If running RNW 0.62: add `node_modules\react-native-blob-util\windows\ReactNativeBlobUtil\ReactNativeBlobUtil.vcxproj` - Right-click main application project > Add > Reference... - Select `progress-view` and in Solution Projects - If running 0.62, also select `RCTPdf` and `ReactNativeBlobUtil` - In app `pch.h` add `#include "winrt/RCTPdf.h"` - If running 0.62, also select `#include "winrt/ReactNativeBlobUtil.h"` - In `App.cpp` add `PackageProviders().Append(winrt::progress_view::ReactPackageProvider());` before `InitializeComponent();` - If running RNW 0.62, also add `PackageProviders().Append(winrt::RCTPdf::ReactPackageProvider());` and `PackageProviders().Append(winrt::ReactNativeBlobUtil::ReactPackageProvider());` #### Bundling PDFs with the app To add a `test.pdf` like in the example add: ``` <None Include="..\..\test.pdf"> <DeploymentContent>true</DeploymentContent> </None> ``` in the app `.vcxproj` file, before `<None Include="packages.config" />`. </details> ## 🚀 JSI Installation (Android) ### Prerequisites - Android NDK - CMake 3.13+ - C++17 support ### Build Configuration Add to your `android/build.gradle`: ```gradle android { externalNativeBuild { cmake { path "node_modules/react-native-pdf-jsi/android/src/main/cpp/CMakeLists.txt" version "3.22.1" } } } ``` ### Package Registration Register the JSI package in your React Native application: ```java // MainApplication.java import org.wonday.pdf.RNPDFPackage; @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new RNPDFPackage() // This includes JSI modules ); } ``` ## 📖 Usage ### Basic Usage ```jsx import React, { useState } from 'react'; import { StyleSheet, Dimensions, View, Modal, TouchableOpacity, Text } from 'react-native'; // Import the Pdf component from react-native-pdf-jsi const PdfModule = require('react-native-pdf-jsi'); const Pdf = PdfModule.default; export default function PDFExample() { const [visible, setVisible] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(0); const source = { uri: 'http://samples.leanpub.com/thereactnativebook-sample.pdf', cache: true }; return ( <View style={styles.container}> <TouchableOpacity style={styles.button} onPress={() => setVisible(true)} > <Text style={styles.buttonText}>Open PDF</Text> </TouchableOpacity> <Modal visible={visible} animationType="slide" onRequestClose={() => setVisible(false)} > <View style={styles.modalContainer}> <View style={styles.header}> <Text style={styles.pageInfo}> Page {currentPage} of {totalPages} </Text> <TouchableOpacity style={styles.closeButton} onPress={() => setVisible(false)} > <Text style={styles.closeButtonText}>Close</Text> </TouchableOpacity> </View> <Pdf source={source} style={styles.pdf} onLoadComplete={(numberOfPages, filePath) => { console.log(`📄 PDF loaded: ${numberOfPages} pages`); setTotalPages(numberOfPages); }} onPageChanged={(page, numberOfPages) => { console.log(`📄 Current page: ${page}`); setCurrentPage(page); }} onError={(error) => { console.error('📄 PDF Error:', error); }} trustAllCerts={false} /> </View> </Modal> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, button: { backgroundColor: '#007AFF', paddingHorizontal: 20, paddingVertical: 10, borderRadius: 8, }, buttonText: { color: 'white', fontSize: 16, fontWeight: 'bold', }, modalContainer: { flex: 1, backgroundColor: '#fff', }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 15, backgroundColor: '#f5f5f5', borderBottomWidth: 1, borderBottomColor: '#ddd', }, pageInfo: { fontSize: 16, fontWeight: 'bold', }, closeButton: { backgroundColor: '#FF3B30', paddingHorizontal: 15, paddingVertical: 8, borderRadius: 6, }, closeButtonText: { color: 'white', fontSize: 14, fontWeight: 'bold', }, pdf: { flex: 1, width: Dimensions.get('window').width, height: Dimensions.get('window').height - 100, } }); ``` ### 🚀 JSI Enhanced Usage #### Real-World JSI Integration Pattern ```jsx import React, { useState, useEffect } from 'react'; import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; // Import JSI modules with proper error handling let PDFJSI = null; let usePDFJSI = null; try { // Import JSI functionality with dynamic imports for release mode compatibility const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI'); const usePDFJSIModule = require('react-native-pdf-jsi/src/hooks/usePDFJSI'); PDFJSI = PDFJSIModule.default; usePDFJSI = usePDFJSIModule.default; console.log(`🔍 PDFJSI found: ${PDFJSI ? '✅' : '❌'} (type: ${typeof PDFJSI})`); console.log(`🔍 usePDFJSI found: ${usePDFJSI ? '✅' : '❌'} (type: ${typeof usePDFJSI})`); } catch (error) { console.log('📱 JSI: PDFJSI not available, using fallback - Error:', error.message); } // Create fallback functions for release builds if (!PDFJSI || !usePDFJSI) { console.log('🛡️ Creating JSI fallback functions for stability'); PDFJSI = { checkJSIAvailability: async () => false, getJSIStats: async () => ({ jsiEnabled: false }), // ... other fallback methods }; usePDFJSI = (options) => ({ isJSIAvailable: false, isInitialized: true, renderPage: () => Promise.resolve({ success: false, error: 'JSI not available' }), // ... other fallback methods }); } export default function EnhancedPDFExample() { const [isJSIAvailable, setIsJSIAvailable] = useState(false); const [jsiStats, setJsiStats] = useState(null); const [isInitialized, setIsInitialized] = useState(false); // 🚀 JSI Hook Integration with Fallback const jsiHookResult = usePDFJSI({ autoInitialize: true, enablePerformanceTracking: true, enableCaching: true, maxCacheSize: 200, }); useEffect(() => { initializeJSI(); }, []); const initializeJSI = async () => { try { if (PDFJSI && typeof PDFJSI.checkJSIAvailability === 'function') { const isAvailable = await PDFJSI.checkJSIAvailability(); setIsJSIAvailable(isAvailable); if (isAvailable) { const stats = await PDFJSI.getJSIStats(); setJsiStats(stats); console.log('🚀 JSI Stats:', stats); } } } catch (error) { console.log('📱 JSI initialization failed:', error); } }; const handleJSIOperations = async () => { try { if (jsiHookResult.isJSIAvailable) { // High-performance page rendering const result = await jsiHookResult.renderPage('pdf_123', 1, 2.0, 'base64data'); console.log('🚀 JSI Render result:', result); // Preload pages for faster access const preloadSuccess = await jsiHookResult.preloadPages('pdf_123', 1, 5); console.log('🚀 Preload success:', preloadSuccess); // Get performance metrics const metrics = await jsiHookResult.getPerformanceMetrics('pdf_123'); console.log('🚀 Performance metrics:', metrics); } else { console.log('📱 JSI not available, using standard methods'); } } catch (error) { console.log('JSI operations failed:', error); } }; return ( <View style={styles.container}> <View style={styles.statusContainer}> <Text style={styles.statusText}> JSI Status: {isJSIAvailable ? '✅ Available' : '❌ Not Available'} </Text> {jsiStats && ( <Text style={styles.statsText}> Performance Level: {jsiStats.performanceLevel} </Text> )} </View> <TouchableOpacity style={styles.button} onPress={handleJSIOperations} > <Text style={styles.buttonText}> Test JSI Operations </Text> </TouchableOpacity> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 20, justifyContent: 'center', }, statusContainer: { backgroundColor: '#f5f5f5', padding: 15, borderRadius: 8, marginBottom: 20, }, statusText: { fontSize: 16, fontWeight: 'bold', marginBottom: 5, }, statsText: { fontSize: 14, color: '#666', }, button: { backgroundColor: '#007AFF', padding: 15, borderRadius: 8, alignItems: 'center', }, buttonText: { color: 'white', fontSize: 16, fontWeight: 'bold', }, }); ``` #### Advanced JSI Operations ```js import React, { useRef, useEffect } from 'react'; import { View } from 'react-native'; import Pdf from 'react-native-pdf-enhanced'; export default function AdvancedJSIExample() { const pdfRef = useRef(null); useEffect(() => { // Check JSI availability and performance if (pdfRef.current) { pdfRef.current.getJSIStats().then(stats => { console.log('🚀 JSI Stats:', stats); console.log('Performance Level:', stats.performanceLevel); console.log('Direct Memory Access:', stats.directMemoryAccess); }); } }, []); const handleAdvancedOperations = async () => { if (pdfRef.current) { try { // Batch operations for better performance const operations = [ { type: 'renderPage', page: 1, scale: 1.5 }, { type: 'preloadPages', start: 2, end: 5 }, { type: 'getMetrics', page: 1 } ]; // Execute operations for (const op of operations) { switch (op.type) { case 'renderPage': await pdfRef.current.renderPageWithJSI(op.page, op.scale); break; case 'preloadPages': await pdfRef.current.preloadPagesWithJSI(op.start, op.end); break; case 'getMetrics': const metrics = await pdfRef.current.getJSIPerformanceMetrics(); console.log('📊 Performance:', metrics); break; } } } catch (error) { console.log('Advanced operations failed:', error); } } }; return ( <View style={{ flex: 1 }}> <Pdf ref={pdfRef} source={{ uri: 'http://example.com/document.pdf' }} onLoadComplete={(pages) => { console.log(`Loaded ${pages} pages`); handleAdvancedOperations(); }} style={{ flex: 1 }} /> </View> ); } ``` ## 🛡️ **ProGuard Configuration (Required for Production)** **IMPORTANT**: For production builds, you MUST add ProGuard rules to prevent obfuscation of JSI classes. Without these rules, your app will crash in release mode. ### **Add to `android/app/proguard-rules.pro`:** ```proguard # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # 🚀 JSI Module ProGuard Rules - Prevent obfuscation of JSI classes # react-native-pdf-jsi package classes -keep class org.wonday.pdf.PDFJSIManager { *; } -keep class org.wonday.pdf.PDFJSIModule { *; } -keep class org.wonday.pdf.EnhancedPdfJSIBridge { *; } -keep class org.wonday.pdf.RNPDFPackage { *; } -keep class org.wonday.pdf.PdfManager { *; } -keep class org.wonday.pdf.PDFNativeCacheManager { *; } -keep class org.wonday.pdf.PdfView { *; } -keep class org.wonday.pdf.events.TopChangeEvent { *; } # Keep all JSI native methods -keepclasseswithmembernames class * { native <methods>; } # Keep JSI bridge methods -keepclassmembers class * { @com.facebook.react.bridge.ReactMethod <methods>; } # Keep React Native bridge classes -keep class com.facebook.react.bridge.** { *; } -keep class com.facebook.react.turbomodule.** { *; } # Keep native library loading -keep class com.facebook.soloader.** { *; } # Keep JSI related classes -keep class com.facebook.jni.** { *; } # Prevent obfuscation of PDF JSI native methods -keepclassmembers class org.wonday.pdf.PDFJSIManager { native void nativeInitializeJSI(java.lang.Object); native boolean nativeIsJSIAvailable(); native com.facebook.react.bridge.WritableMap nativeRenderPageDirect(java.lang.String, int, float, java.lang.String); native com.facebook.react.bridge.WritableMap nativeGetPageMetrics(java.lang.String, int); native boolean nativePreloadPagesDirect(java.lang.String, int, int); native com.facebook.react.bridge.WritableMap nativeGetCacheMetrics(java.lang.String); native boolean nativeClearCacheDirect(java.lang.String, java.lang.String); native boolean nativeOptimizeMemory(java.lang.String); native com.facebook.react.bridge.ReadableArray nativeSearchTextDirect(java.lang.String, java.lang.String, int, int); native com.facebook.react.bridge.WritableMap nativeGetPerformanceMetrics(java.lang.String); native boolean nativeSetRenderQuality(java.lang.String, int); native void nativeCleanupJSI(); } # Keep all PDF related classes -keep class org.wonday.pdf.** { *; } # Keep React Native modules -keep class * extends com.facebook.react.bridge.ReactContextBaseJavaModule { *; } -keep class * extends com.facebook.react.ReactPackage { *; } # Keep native library names -keepnames class * { native <methods>; } # Keep crypto-js classes (dependency of react-native-pdf-jsi) -keep class com.google.crypto.** { *; } -keep class javax.crypto.** { *; } # Keep JSI specific classes and methods -keepclassmembers class org.wonday.pdf.** { public <methods>; protected <methods>; } # Keep all event classes -keep class org.wonday.pdf.events.** { *; } # Keep React Native JSI specific classes -keep class com.facebook.jsi.** { *; } -keep class com.facebook.hermes.** { *; } ``` ### **Why These Rules Are Essential:** 1. **JSI Class Protection**: Prevents ProGuard from obfuscating JSI-related classes 2. **Native Method Preservation**: Keeps native method signatures intact 3. **Bridge Method Safety**: Protects React Native bridge methods 4. **Event System**: Maintains event handling functionality 5. **Crypto Dependencies**: Preserves cryptographic functionality ### **Build Configuration:** Make sure your `android/app/build.gradle` has ProGuard enabled: ```gradle android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // ... other release config } } } ``` ## 🚨 Expo Support This package is not available in the [Expo Go](https://expo.dev/client) app. Learn how you can use this package in [Custom Dev Clients](https://docs.expo.dev/development/getting-started/) via the out-of-tree [Expo Config Plugin](https://github.com/expo/config-plugins/tree/master/packages/react-native-pdf). Example: [`with-pdf`](https://github.com/expo/examples/tree/master/with-pdf). ### FAQ <details> <summary>FAQ details</summary> Q1. After installation and running, I can not see the pdf file. A1: maybe you forgot to excute ```react-native link``` or it does not run correctly. You can add it manually. For detail you can see the issue [`#24`](https://github.com/wonday/react-native-pdf/issues/24) and [`#2`](https://github.com/wonday/react-native-pdf/issues/2) Q2. When running, it shows ```'Pdf' has no propType for native prop RCTPdf.acessibilityLabel of native type 'String'``` A2. Your react-native version is too old, please upgrade it to 0.47.0+ see also [`#39`](https://github.com/wonday/react-native-pdf/issues/39) Q3. When I run the example app I get a white/gray screen / the loading bar isn't progressing . A3. Check your uri, if you hit a pdf that is hosted on a `http` you will need to do the following: **iOS:** add an exception for the server hosting the pdf in the ios `info.plist`. Here is an example : ``` <key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>yourserver.com</key> <dict> <!--Include to allow subdomains--> <key>NSIncludesSubdomains</key> <true/> <!--Include to allow HTTP requests--> <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> <true/> <!--Include to specify minimum TLS version--> <key>NSTemporaryExceptionMinimumTLSVersion</key> <string>TLSv1.1</string> </dict> </dict> </dict> ``` **Android:** [`see here`](https://stackoverflow.com/questions/54818098/cleartext-http-traffic-not-permitted) Q4. why doesn't it work with react native expo?. A4. Expo does not support native module. you can read more expo caveats [`here`](https://facebook.github.io/react-native/docs/getting-started.html#caveats) Q5. Why can't I run the iOS example? `'Failed to build iOS project. We ran "xcodebuild" command but it exited with error code 65.'` A5. Run the following commands in the project folder (e.g. `react-native-pdf/example`) to ensure that all dependencies are available: ``` yarn install (or npm install) cd ios pod install cd .. react-native run-ios ``` **Q6. How do I enable JSI mode?** A6: JSI mode is automatically enabled on Android. Check JSI availability with: ```jsx // Import JSI modules let PDFJSI = null; try { const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI'); PDFJSI = PDFJSIModule.default; } catch (error) { console.log('JSI not available'); } // Check availability const isAvailable = await PDFJSI?.checkJSIAvailability(); console.log('JSI Available:', isAvailable); ``` **Q7. What if JSI is not available?** A7: The package automatically falls back to standard bridge mode. Always implement fallbacks: ```jsx // Import with fallback let PDFJSI = null; let usePDFJSI = null; try { const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI'); const usePDFJSIModule = require('react-native-pdf-jsi/src/hooks/usePDFJSI'); PDFJSI = PDFJSIModule.default; usePDFJSI = usePDFJSIModule.default; } catch (error) { console.log('JSI not available, using fallback'); } // Use with fallback const jsiHookResult = usePDFJSI ? usePDFJSI({ autoInitialize: true, enablePerformanceTracking: true, }) : { isJSIAvailable: false, isInitialized: true }; ``` **Q8. My app crashes in release mode with JSI errors** A8: You need to add ProGuard rules. Add the complete ProGuard configuration from the documentation to your `android/app/proguard-rules.pro` file. **Q9. How do I migrate from react-native-pdf?** A9: Follow the migration steps in the documentation: 1. Update package: `npm install react-native-pdf-jsi` 2. Update imports: Use `require('react-native-pdf-jsi')` 3. Add ProGuard rules 4. Update component usage (same API) 5. Optionally add JSI integration **Q10. The shimmer loader gets stuck and documents don't load** A10: This usually means JSI initialization is failing. Ensure: - ProGuard rules are properly configured - JSI modules are imported correctly with error handling - Fallback mechanisms are in place - Check console logs for JSI availability status **Q11. TypeError: constructor is not callable** A11: This error occurs when the Pdf component is not imported correctly. Use: ```jsx const PdfModule = require('react-native-pdf-jsi'); const Pdf = PdfModule.default; // NOT: const Pdf = require('react-native-pdf-jsi'); ``` </details> ## 📝 Changelog ### v2.2.4 (2025) - Latest ✅ CRITICAL 16KB BUG FIX #### 🐛 **16KB Page Size Compatibility Fix** - **Critical Bug Fix**: Resolved 16KB page size compatibility issues for Google Play compliance - **NDK r28.2 Update**: Updated to NDK 28.2.13676358 with proper 16KB page alignment toolchain - **CMake Configuration**: Added ANDROID_PAGE_SIZE_AGNOSTIC=ON flag for full compliance - **Linker Flags**: Added 16KB page size alignment flags (-Wl,-z,max-page-size=16384) - **Dependency Updates**: Updated pdfiumandroid to v1.0.32 and gson to v2.11.0 #### 📊 **Google Play Compliance** - **Full Compliance**: Meets all Google Play 16KB page size requirements - **Android 15+ Ready**: Built with SDK 35 for Android 15+ compatibility - **Policy Aligned**: Ensures app updates won't be blocked after November 1, 2025 - **Production Tested**: Verified working in Android Studio APK analyzer #### 🚀 **Technical Improvements** - **Build Configuration**: Updated compileSdkVersion and targetSdkVersion to 35 - **Native Library Support**: Enhanced native library compatibility with 16KB pages - **Memory Alignment**: Proper memory page alignment for optimal performance ### v2.2.3 (2025) - ✅ BUG FIX RELEASE #### 🐛 **Critical Bug Fixes** - **JSI Initialization Fix**: Resolved crash when calling `initializeJSI()` on React Native 0.81 Android - **Error Handling**: Added comprehensive error handling for JSI initialization process - **Stability**: Enhanced error recovery and graceful fallback mechanisms - **Compatibility**: Full compatibility with React Native 0.81 on Android platform #### 📊 **Issue Resolution** - **GitHub Issue Fix**: Addressed user-reported crash on PDF opening in RN 0.81 - **Android Stability**: Improved Android JSI initialization reliability - **Error Messages**: Better error messages for debugging JSI issues ### v2.2.2 (2025) - ✅ PRODUCTION READY WITH LATEST NDK #### 🚀 **Latest NDK Integration** - **NDK r28.2 Update**: Updated to NDK 28.2.13676358 (matches @IsengardZA's exact solution) - **Community Alignment**: Uses the exact NDK version recommended by community developers - **Latest Toolchain**: Ensures compatibility with newest Android development tools #### 🚀 **Community Verified Solutions** - **GitHub Issue #970 Fixes**: Integrated all solutions from @IsengardZA's successful resolution - **Production Testing**: Verified working in Android Studio APK analyzer by real users - **NDK r28.2 Support**: Confirmed compatibility with latest Android development toolchain - **Dependency Updates**: All required dependency versions tested and working - **16KB Compliance**: Full Google Play policy compliance verified in production apps #### 📊 **Real-World Validation** - **APK Analyzer Compatible**: Confirmed working in Android Studio's APK analyzer - **Build System Verified**: All build configurations tested in production environments - **Release Build Ready**: Verified compatibility with both debug and release builds - **Community Approved**: Solutions tested and confirmed by multiple developers ### v2.2.0 (2025) - ✅ ENHANCED 16KB COMPLIANCE & DOCUMENTATION #### 🚀 **16KB Page Alignment Enhancements** - **Dependency Updates**: Updated `io.legere:pdfiumandroid` from v1.0.24 to v1.0.32 for optimal 16KB support - **Gson Update**: Updated `com.google.code.gson:gson` from v2.8.5 to v2.11.0 for compatibility - **Build Configuration**: Updated `compileSdkVersion` and `targetSdkVersion` from 34 to 35 for Android 15+ compatibility - **CMakeLists Enhancement**: Added missing executable linker flag `-Wl,-z,max-page-size=16384` for complete 16KB page alignment - **Dependency Management**: Added exclusion for bundled PdfiumAndroid to prevent conflicts with specific version #### 📚 **Documentation Overhaul** - **README Rewrite**: Complete rewrite of README with real-world usage examples from production projects - **Import Patterns**: Updated all examples to show correct import patterns using `require('react-native-pdf-jsi')` - **Error Handling**: Added comprehensive error handling and fallback mechanisms in all examples - **Modal Implementation**: Added complete modal-based PDF viewer example matching production usage - **JSI Integration**: Updated JSI usage examples with proper initialization and error handling patterns #### 🛡️ **Production Safety & ProGuard** - **ProGuard Rules**: Added comprehensive ProGuard configuration documentation with complete rule set - **Release Build Safety**: Added critical warnings about ProGuard rules preventing production crashes - **JSI Class Protection**: Documented all necessary ProGuard rules for JSI class preservation - **Native Method Safety**: Added rules for preserving native method signatures and React Native bridge methods #### 📖 **Migration & FAQ Enhancement** - **Step-by-Step Migration**: Complete migration guide from react-native-pdf with 5 clear steps - **Common Issues**: Added solutions for shimmer loader stuck, constructor errors, and JSI initialization failures - **Production Troubleshooting**: Added FAQ entries for release build crashes and ProGuard configuration - **Error Solutions**: Documented solutions for "TypeError: constructor is not callable" and other common errors #### ⚡ **Performance & Reliability** - **JSI Fallback Patterns**: Enhanced JSI integration with robust fallback mechanisms for production stability - **Error Handling**: Added comprehensive try-catch patterns for JSI module loading - **Release Build Compatibility**: Ensured compatibility with both debug and release builds - **Memory Management**: Enhanced memory optimization patterns for large PDF files #### 📊 **Google Play Compliance** - **16KB Verification**: Complete implementation of Google Play 16KB page size requirements - **Android 15+ Ready**: Full compatibility with Android 15+ requirements - **Future-Proof**: Ensures long-term compatibility with Google Play policy changes - **Compliance Testing**: Added verification methods for 16KB page size support ### v2.0.1 (2025) - ✅ GOOGLE PLAY COMPLIANT - 🚨 **Google Play 16KB Compliance**: Added full support for Google Play's 16KB page size requirement - 🔧 **NDK r27+ Support**: Updated to NDK version 27.0.12077973 for Android 15+ compatibility - 📱 **16KB Page Size Check**: Added `check16KBSupport()` method to verify compliance - 🛠️ **Build Configuration**: Updated Gradle and CMakeLists for 16KB page support - 📊 **Compliance Verification**: Added example code to check Google Play compliance - 🎯 **Future-Proof**: Ensures your app won't be blocked by Google Play policy changes ### v2.0.0 (2025) 🚀 MAJOR RELEASE - 🎉 **Major Version Release**: Significant performance improvements and new features - 🚀 **Complete JSI Integration**: Full Android and iOS JSI implementation with native C++ optimizations - 📄 **Lazy Loading System**: Revolutionary lazy loading for large PDF files with configurable preload radius - 🎯 **Smart Caching Engine**: 30-day persistent cache with LRU eviction and background cleanup - 📊 **Progressive Loading**: Batch-based progressive loading with configurable batch sizes - 💾 **Advanced Memory Management**: Intelligent memory optimization for large documents - 🔍 **Enhanced Search**: Cached text search with bounds detection and performance tracking - 📱 **Native Cache Managers**: Complete Android and iOS native cache implementations - 🔧 **Performance Monitoring**: Real-time performance metrics and analytics - 📚 **Comprehensive Examples**: Updated examples with lazy loading and advanced features - 🏷️ **SEO Optimization**: Enhanced discoverability with 40+ keywords and better descriptions - 📈 **Better Documentation**: Improved README with performance comparisons and usage examples ### v1.0.3 (2025) - 🔗 **GitHub URL Fix**: Corrected repository URLs to point to the actual GitHub repository - 📚 **Documentation Fix**: Updated README with correct package name and installation instructions - 🔧 **Package Clarity**: Clear distinction between npm package name (`react-native-pdf-jsi`) and import names (`react-native-pdf-enhanced`) ### v1.0.2 (2025) - 📚 **Documentation Fix**: Updated README with correct package name and installation instructions - 🔧 **Package Clarity**: Clear distinction between npm package name (`react-native-pdf-jsi`) and import names (`react-native-pdf-enhanced`) ### v1.0.1 (2025) - 🔧 **Enhanced JSI Integration**: Comprehensive Android and iOS JSI enhancements - 📱 **iOS Progressive Loading**: Smart caching, preloading queue, and performance tracking - 🤖 **Android JSI Optimization**: Complete native C++ implementation with batch operations - 📦 **JavaScript Components**: Enhanced PDF view, React hooks, and utility functions - 🚀 **Performance Monitoring**: Real-time metrics, memory optimization, and cache management - 🛠 **Developer Tools**: Complete example implementation and benchmarking utilities - 📊 **Cross-Platform**: Seamless JSI detection with graceful fallback mechanisms ### v1.0.0 (2025) - 🚀 **Major Release**: First stable version with JSI integration - ⚡ **Performance**: Up to 80x faster operations on Android - 🔧 **JSI Integration**: Zero-bridge overhead for critical operations - 💾 **Enhanced Caching**: Multi-level intelligent caching system - 📊 **Performance Monitoring**: Real-time metrics and optimization - 🔄 **Graceful Fallback**: Automatic fallback to bridge mode - 📱 **Cross-Platform**: Full iOS, Android, and Windows support - 🛠 **Developer Experience**: Comprehensive documentation and examples ### Based on react-native-pdf v6.7.7 - All original features and bug fixes included - Backward compatible with existing implementations ## 🔄 Migration from react-native-pdf ### **Step 1: Update Package** ```bash # Remove old package npm uninstall react-native-pdf # Install new package npm install react-native-pdf-jsi react-native-blob-util ``` ### **Step 2: Update Imports** ```jsx // ❌ Old import import Pdf from 'react-native-pdf'; // ✅ New import const PdfModule = require('react-native-pdf-jsi'); const Pdf = PdfModule.default; ``` ### **Step 3: Add ProGuard Rules** Add the ProGuard rules from the section above to your `android/app/proguard-rules.pro`. ### **Step 4: Update Component Usage** ```jsx // ❌ Old usage <Pdf source={{ uri: 'https://example.com/document.pdf' }} /> // ✅ New usage (same API, enhanced performance) <Pdf source={{ uri: 'https://example.com/document.pdf' }} style={{ flex: 1 }} onLoadComplete={(numberOfPages, filePath) => { console.log(`📄 PDF loaded: ${numberOfPages} pages`); }} onPageChanged={(page, numberOfPages) => { console.log(`📄 Current page: ${page}`); }} trustAllCerts={false} /> ``` ### **Step 5: Add JSI Integration (Optional)** For enhanced performance, add JSI integration: ```jsx // Import JSI modules with error handling let PDFJSI = null; let usePDFJSI = null; try { const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI'); const usePDFJSIModule = require('react-native-pdf-jsi/src/hooks/usePDFJSI'); PDFJSI = PDFJSIModule.default; usePDFJSI = usePDFJSIModule.default; } catch (error) { console.log('JSI not available, using fallback'); } // Use JSI hook const jsiHookResult = usePDFJSI ? usePDFJSI({ autoInitialize: true, enablePerformanceTracking: true, }) : { isJSIAvailable: false }; ``` ### **Migration Benefits:** - ✅ **Same API**: No code changes required for basic usage - ✅ **Enhanced Performance**: Up to 80x faster on Android - ✅ **Google Play Compliant**: 16KB page size support - ✅ **Future-Proof**: Built with latest NDK and modern toolchain - ✅ **Better Caching**: Advanced persistent cache system ## 📦 Available Exports ### **Core Components** ```jsx // Standard PDF component (enhanced with JSI) const PdfModule = require('react-native-pdf-jsi'); const Pdf = PdfModule.default; // Usage <Pdf source={{ uri: 'https://example.com/document.pdf' }} style={{ flex: 1 }} onLoadComplete={(numberOfPages, filePath) => { console.log(`📄 PDF loaded: ${numberOfPages} pages`); }} trustAllCerts={false} /> ``` ### **JSI Modules (Advanced Usage)** ```jsx // Import JSI functionality with error handling let PDFJSI = null; let usePDFJSI = null; try { const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI'); const usePDFJSIModule = require('react-native-pdf-jsi/src/hooks/usePDFJSI'); PDFJSI = PDFJSIModule.default; usePDFJSI = usePDFJSIModule.default; } catch (error) { console.log('JSI not available, using fallback'); } // Use JSI hook for enhanced operations const jsiHookResult = usePDFJSI ? usePDFJSI({ autoInitialize: true, enablePerformanceTracking: true, enableCaching: true, maxCacheSize: 200, }) : { isJSIAvailable: false, isInitialized: true }; ``` ### **JSI Methods Available** ```jsx // When JSI is available, these methods provide enhanced performance: const methods = { // High-performance page rendering renderPage: (pdfId, pageNumber, scale, base64Data) => Promise, // Get page metrics getPageMetrics: (pdfId, pageNumber) => Promise, // Preload pages for faster access preloadPages: (pdfId, startPage, endPage) => Promise, // Cache management getCacheMetrics: (pdfId) => Promise, clearCache: (pdfId, cacheType) => Promise, // Memory optimization optimizeMemory: (pdfId) => Promise, // Text search searchText: (pdfId, query, startPage, endPage) => Promise, // Performance monitoring getPerformanceMetrics: (pdfId) => Promise, // Render quality control setRenderQuality: (pdfId, quality) => Promise, // JSI availability check checkJSIAvailability: () => Promise, // Get JSI statistics getJSIStats: () => Promise }; ``` ### **Error Handling Pattern** ```jsx // Always wrap JSI operations in try-catch with fallbacks const handleJSIOperation = async () => { try { if (PDFJSI && jsiHookResult.isJSIAvailable) { // Use JSI for enhanced performance const result = await PDFJSI.renderPageDirect('pdf_123', 1, 2.0, 'base64data'); console.log('🚀 JSI operation successful:', result); } else { // Fallback to standard methods console.log('📱 Using standard PDF methods'); } } catch (error) { console.log('❌ Operation failed:', error); // Handle error gracefully } }; ``` ### Check Google Play 16KB Compliance ```jsx import React, { useEffect, useState } from 'react'; import { View, Text, Alert } from 'react-native'; import { PDFJSI } from 'react-native-pdf-enhanced'; const ComplianceChecker = () => { const [compliance, setCompliance] = useState(null); useEffect(() => { check16KBCompliance(); }, []); const check16KBCompliance = async () => { try { const result = await PDFJSI.check16KBSupport(); setCompliance(result); if (result.googlePlayCompliant) { Alert.alert('✅ Compliant', 'Your app supports 16KB page sizes and is Google Play compliant!'); } else { Alert.alert('⚠️ Non-Compliant', '16KB page size support required for Google Play updates after November 2025'); } } catch (error) { console.error('Compliance check failed:', error); } }; return ( <View style={{ padding: 20 }}> <Text style={{ fontSize: 16, fontWeight: 'bold' }}> Google Play Compliance Status </Text> {compliance && ( <Text style={{ marginTop: 10 }}> {compliance.message} </Text> )} </View> ); }; ``` ### Lazy Loading for Large PDF Files ```jsx import React, { useRef, useEffect } from 'react'; import { View } from 'react-native'; import Pdf from 'react-native-pdf-enhanced'; export default function LazyLoadingExample() { const pdfRef = useRef(null); const handlePageChange = async (page) => { if (pdfRef.current) { try { // Lazy load pages around current page const result = await pdfRef.current.lazyLoadPages(page, 3, 100); console.log('🚀 Lazy loaded pages:', result.preloadedRange); // Progressive loading for large PDFs const progressiveResult = await pdfRef.current.progressiveLoadPages( 1, // start page 5, // batch size (progress) => { console.log(`📄 Loaded batch ${progress.batchStartPage}-${progress.batchEndPage}`); } ); console.log('📊 Progressive loading completed:', progressiveResult.totalLoaded, 'pages'); } catch (error) { console.error('❌ Lazy loading error:', error); } } }; const handleSmartCache = async () => { if (pdfRef.current) { try { // Cache frequently accessed pages const frequentPages