react-native-pdf-jsi 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,7 +35,7 @@ Starting November 1, 2025, Google Play will require apps to support 16KB page si
35
35
  - ✅ **Google Play Approved** - Meets all current and future requirements
36
36
  - ✅ **Drop-in Replacement** - Easy migration from existing libraries
37
37
 
38
- ## 🎉 Version 2.0.0 - Major Release!
38
+ ## 🎉 Version 2.1.0 - Enhanced 16KB Compliance & Documentation!
39
39
 
40
40
  **We've completely rewritten the core architecture with revolutionary performance improvements!**
41
41
 
@@ -148,17 +148,25 @@ yarn add react-native-pdf-jsi react-native-blob-util
148
148
  ## 🚀 **Quick Start**
149
149
 
150
150
  ```jsx
151
- // Replace your existing import
152
- import Pdf from 'react-native-pdf'; // Old library
153
-
154
- // With our enhanced version
155
- import Pdf from 'react-native-pdf-enhanced'; // Enhanced with JSI
156
-
157
- // Same API, improved performance
158
- <Pdf source={{ uri: 'https://example.com/document.pdf' }} />
151
+ // Import the Pdf component from react-native-pdf-jsi
152
+ const PdfModule = require('react-native-pdf-jsi');
153
+ const Pdf = PdfModule.default;
154
+
155
+ // Use the component with the same API as react-native-pdf
156
+ <Pdf
157
+ source={{ uri: 'https://example.com/document.pdf' }}
158
+ style={{ flex: 1 }}
159
+ onLoadComplete={(numberOfPages, filePath) => {
160
+ console.log(`PDF loaded: ${numberOfPages} pages`);
161
+ }}
162
+ onPageChanged={(page, numberOfPages) => {
163
+ console.log(`Current page: ${page} of ${numberOfPages}`);
164
+ }}
165
+ trustAllCerts={false}
166
+ />
159
167
  ```
160
168
 
161
- **Simple migration with improved performance and Google Play compliance.**
169
+ **Drop-in replacement for react-native-pdf with enhanced performance and Google Play compliance.**
162
170
 
163
171
  Then follow the instructions for your platform to link react-native-pdf-jsi into your project:
164
172
 
@@ -275,127 +283,285 @@ protected List<ReactPackage> getPackages() {
275
283
 
276
284
  ### Basic Usage
277
285
 
278
- ```js
279
- import React from 'react';
280
- import { StyleSheet, Dimensions, View } from 'react-native';
281
- import Pdf from 'react-native-pdf-enhanced';
286
+ ```jsx
287
+ import React, { useState } from 'react';
288
+ import { StyleSheet, Dimensions, View, Modal, TouchableOpacity, Text } from 'react-native';
282
289
 
283
- export default class PDFExample extends React.Component {
284
- render() {
285
- const source = { uri: 'http://samples.leanpub.com/thereactnativebook-sample.pdf', cache: true };
286
- //const source = require('./test.pdf'); // ios only
287
- //const source = {uri:'bundle-assets://test.pdf' };
288
- //const source = {uri:'file:///sdcard/test.pdf'};
289
- //const source = {uri:"data:application/pdf;base64,JVBERi0xLjcKJc..."};
290
- //const source = {uri:"content://com.example.blobs/xxxxxxxx-...?offset=0&size=xxx"};
291
- //const source = {uri:"blob:xxxxxxxx-...?offset=0&size=xxx"};
290
+ // Import the Pdf component from react-native-pdf-jsi
291
+ const PdfModule = require('react-native-pdf-jsi');
292
+ const Pdf = PdfModule.default;
292
293
 
293
- return (
294
- <View style={styles.container}>
295
- <Pdf
296
- source={source}
297
- onLoadComplete={(numberOfPages,filePath) => {
298
- console.log(`Number of pages: ${numberOfPages}`);
299
- }}
300
- onPageChanged={(page,numberOfPages) => {
301
- console.log(`Current page: ${page}`);
302
- }}
303
- onError={(error) => {
304
- console.log(error);
305
- }}
306
- onPressLink={(uri) => {
307
- console.log(`Link pressed: ${uri}`);
308
- }}
309
- style={styles.pdf}/>
310
- </View>
311
- )
312
- }
294
+ export default function PDFExample() {
295
+ const [visible, setVisible] = useState(false);
296
+ const [currentPage, setCurrentPage] = useState(1);
297
+ const [totalPages, setTotalPages] = useState(0);
298
+
299
+ const source = {
300
+ uri: 'http://samples.leanpub.com/thereactnativebook-sample.pdf',
301
+ cache: true
302
+ };
303
+
304
+ return (
305
+ <View style={styles.container}>
306
+ <TouchableOpacity
307
+ style={styles.button}
308
+ onPress={() => setVisible(true)}
309
+ >
310
+ <Text style={styles.buttonText}>Open PDF</Text>
311
+ </TouchableOpacity>
312
+
313
+ <Modal
314
+ visible={visible}
315
+ animationType="slide"
316
+ onRequestClose={() => setVisible(false)}
317
+ >
318
+ <View style={styles.modalContainer}>
319
+ <View style={styles.header}>
320
+ <Text style={styles.pageInfo}>
321
+ Page {currentPage} of {totalPages}
322
+ </Text>
323
+ <TouchableOpacity
324
+ style={styles.closeButton}
325
+ onPress={() => setVisible(false)}
326
+ >
327
+ <Text style={styles.closeButtonText}>Close</Text>
328
+ </TouchableOpacity>
329
+ </View>
330
+
331
+ <Pdf
332
+ source={source}
333
+ style={styles.pdf}
334
+ onLoadComplete={(numberOfPages, filePath) => {
335
+ console.log(`📄 PDF loaded: ${numberOfPages} pages`);
336
+ setTotalPages(numberOfPages);
337
+ }}
338
+ onPageChanged={(page, numberOfPages) => {
339
+ console.log(`📄 Current page: ${page}`);
340
+ setCurrentPage(page);
341
+ }}
342
+ onError={(error) => {
343
+ console.error('📄 PDF Error:', error);
344
+ }}
345
+ trustAllCerts={false}
346
+ />
347
+ </View>
348
+ </Modal>
349
+ </View>
350
+ );
313
351
  }
314
352
 
315
353
  const styles = StyleSheet.create({
316
354
  container: {
317
355
  flex: 1,
318
- justifyContent: 'flex-start',
356
+ justifyContent: 'center',
357
+ alignItems: 'center',
358
+ padding: 20,
359
+ },
360
+ button: {
361
+ backgroundColor: '#007AFF',
362
+ paddingHorizontal: 20,
363
+ paddingVertical: 10,
364
+ borderRadius: 8,
365
+ },
366
+ buttonText: {
367
+ color: 'white',
368
+ fontSize: 16,
369
+ fontWeight: 'bold',
370
+ },
371
+ modalContainer: {
372
+ flex: 1,
373
+ backgroundColor: '#fff',
374
+ },
375
+ header: {
376
+ flexDirection: 'row',
377
+ justifyContent: 'space-between',
319
378
  alignItems: 'center',
320
- marginTop: 25,
379
+ padding: 15,
380
+ backgroundColor: '#f5f5f5',
381
+ borderBottomWidth: 1,
382
+ borderBottomColor: '#ddd',
383
+ },
384
+ pageInfo: {
385
+ fontSize: 16,
386
+ fontWeight: 'bold',
387
+ },
388
+ closeButton: {
389
+ backgroundColor: '#FF3B30',
390
+ paddingHorizontal: 15,
391
+ paddingVertical: 8,
392
+ borderRadius: 6,
393
+ },
394
+ closeButtonText: {
395
+ color: 'white',
396
+ fontSize: 14,
397
+ fontWeight: 'bold',
321
398
  },
322
399
  pdf: {
323
- flex:1,
324
- width:Dimensions.get('window').width,
325
- height:Dimensions.get('window').height,
400
+ flex: 1,
401
+ width: Dimensions.get('window').width,
402
+ height: Dimensions.get('window').height - 100,
326
403
  }
327
404
  });
328
405
  ```
329
406
 
330
407
  ### 🚀 JSI Enhanced Usage
331
408
 
332
- #### Using Enhanced PDF View Component
333
- ```js
334
- import React from 'react';
335
- import { View } from 'react-native';
336
- import { EnhancedPdfView } from 'react-native-pdf-enhanced';
409
+ #### Real-World JSI Integration Pattern
410
+ ```jsx
411
+ import React, { useState, useEffect } from 'react';
412
+ import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
337
413
 
338
- export default function EnhancedPDFExample() {
339
- return (
340
- <View style={{ flex: 1 }}>
341
- <EnhancedPdfView
342
- source={{ uri: 'http://example.com/document.pdf' }}
343
- onLoadComplete={(pages) => {
344
- console.log(`🚀 Loaded ${pages} pages with JSI acceleration`);
345
- }}
346
- style={{ flex: 1 }}
347
- />
348
- </View>
349
- );
414
+ // Import JSI modules with proper error handling
415
+ let PDFJSI = null;
416
+ let usePDFJSI = null;
417
+
418
+ try {
419
+ // Import JSI functionality with dynamic imports for release mode compatibility
420
+ const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI');
421
+ const usePDFJSIModule = require('react-native-pdf-jsi/src/hooks/usePDFJSI');
422
+
423
+ PDFJSI = PDFJSIModule.default;
424
+ usePDFJSI = usePDFJSIModule.default;
425
+
426
+ console.log(`🔍 PDFJSI found: ${PDFJSI ? '✅' : '❌'} (type: ${typeof PDFJSI})`);
427
+ console.log(`🔍 usePDFJSI found: ${usePDFJSI ? '✅' : '❌'} (type: ${typeof usePDFJSI})`);
428
+
429
+ } catch (error) {
430
+ console.log('📱 JSI: PDFJSI not available, using fallback - Error:', error.message);
350
431
  }
351
- ```
352
432
 
353
- #### Using React Hooks for JSI Operations
354
- ```js
355
- import React, { useEffect } from 'react';
356
- import { View, Button } from 'react-native';
357
- import { usePDFJSI } from 'react-native-pdf-enhanced';
358
-
359
- export default function JSIHookExample() {
360
- const {
361
- isJSIAvailable,
362
- renderPage,
363
- preloadPages,
364
- getPerformanceMetrics,
365
- getPerformanceHistory
366
- } = usePDFJSI({
433
+ // Create fallback functions for release builds
434
+ if (!PDFJSI || !usePDFJSI) {
435
+ console.log('🛡️ Creating JSI fallback functions for stability');
436
+
437
+ PDFJSI = {
438
+ checkJSIAvailability: async () => false,
439
+ getJSIStats: async () => ({ jsiEnabled: false }),
440
+ // ... other fallback methods
441
+ };
442
+
443
+ usePDFJSI = (options) => ({
444
+ isJSIAvailable: false,
445
+ isInitialized: true,
446
+ renderPage: () => Promise.resolve({ success: false, error: 'JSI not available' }),
447
+ // ... other fallback methods
448
+ });
449
+ }
450
+
451
+ export default function EnhancedPDFExample() {
452
+ const [isJSIAvailable, setIsJSIAvailable] = useState(false);
453
+ const [jsiStats, setJsiStats] = useState(null);
454
+ const [isInitialized, setIsInitialized] = useState(false);
455
+
456
+ // 🚀 JSI Hook Integration with Fallback
457
+ const jsiHookResult = usePDFJSI({
367
458
  autoInitialize: true,
368
- enablePerformanceTracking: true
459
+ enablePerformanceTracking: true,
460
+ enableCaching: true,
461
+ maxCacheSize: 200,
369
462
  });
370
463
 
371
- const handleJSIOperations = async () => {
372
- try {
373
- // High-performance page rendering
374
- const result = await renderPage('pdf_123', 1, 2.0, 'base64data');
375
- console.log('🚀 JSI Render result:', result);
376
-
377
- // Preload pages for faster access
378
- const preloadSuccess = await preloadPages('pdf_123', 1, 5);
379
- console.log('🚀 Preload success:', preloadSuccess);
464
+ useEffect(() => {
465
+ initializeJSI();
466
+ }, []);
380
467
 
381
- // Get performance metrics
382
- const metrics = await getPerformanceMetrics('pdf_123');
383
- console.log('🚀 Performance metrics:', metrics);
468
+ const initializeJSI = async () => {
469
+ try {
470
+ if (PDFJSI && typeof PDFJSI.checkJSIAvailability === 'function') {
471
+ const isAvailable = await PDFJSI.checkJSIAvailability();
472
+ setIsJSIAvailable(isAvailable);
473
+
474
+ if (isAvailable) {
475
+ const stats = await PDFJSI.getJSIStats();
476
+ setJsiStats(stats);
477
+ console.log('🚀 JSI Stats:', stats);
478
+ }
479
+ }
480
+ } catch (error) {
481
+ console.log('📱 JSI initialization failed:', error);
482
+ }
483
+ };
384
484
 
485
+ const handleJSIOperations = async () => {
486
+ try {
487
+ if (jsiHookResult.isJSIAvailable) {
488
+ // High-performance page rendering
489
+ const result = await jsiHookResult.renderPage('pdf_123', 1, 2.0, 'base64data');
490
+ console.log('🚀 JSI Render result:', result);
491
+
492
+ // Preload pages for faster access
493
+ const preloadSuccess = await jsiHookResult.preloadPages('pdf_123', 1, 5);
494
+ console.log('🚀 Preload success:', preloadSuccess);
495
+
496
+ // Get performance metrics
497
+ const metrics = await jsiHookResult.getPerformanceMetrics('pdf_123');
498
+ console.log('🚀 Performance metrics:', metrics);
499
+ } else {
500
+ console.log('📱 JSI not available, using standard methods');
501
+ }
385
502
  } catch (error) {
386
503
  console.log('JSI operations failed:', error);
387
504
  }
388
505
  };
389
506
 
390
507
  return (
391
- <View style={{ flex: 1, padding: 20 }}>
392
- <Button
393
- title={`JSI Available: ${isJSIAvailable ? '✅' : '❌'}`}
508
+ <View style={styles.container}>
509
+ <View style={styles.statusContainer}>
510
+ <Text style={styles.statusText}>
511
+ JSI Status: {isJSIAvailable ? '✅ Available' : '❌ Not Available'}
512
+ </Text>
513
+ {jsiStats && (
514
+ <Text style={styles.statsText}>
515
+ Performance Level: {jsiStats.performanceLevel}
516
+ </Text>
517
+ )}
518
+ </View>
519
+
520
+ <TouchableOpacity
521
+ style={styles.button}
394
522
  onPress={handleJSIOperations}
395
- />
523
+ >
524
+ <Text style={styles.buttonText}>
525
+ Test JSI Operations
526
+ </Text>
527
+ </TouchableOpacity>
396
528
  </View>
397
529
  );
398
530
  }
531
+
532
+ const styles = StyleSheet.create({
533
+ container: {
534
+ flex: 1,
535
+ padding: 20,
536
+ justifyContent: 'center',
537
+ },
538
+ statusContainer: {
539
+ backgroundColor: '#f5f5f5',
540
+ padding: 15,
541
+ borderRadius: 8,
542
+ marginBottom: 20,
543
+ },
544
+ statusText: {
545
+ fontSize: 16,
546
+ fontWeight: 'bold',
547
+ marginBottom: 5,
548
+ },
549
+ statsText: {
550
+ fontSize: 14,
551
+ color: '#666',
552
+ },
553
+ button: {
554
+ backgroundColor: '#007AFF',
555
+ padding: 15,
556
+ borderRadius: 8,
557
+ alignItems: 'center',
558
+ },
559
+ buttonText: {
560
+ color: 'white',
561
+ fontSize: 16,
562
+ fontWeight: 'bold',
563
+ },
564
+ });
399
565
  ```
400
566
 
401
567
  #### Advanced JSI Operations
@@ -466,6 +632,125 @@ export default function AdvancedJSIExample() {
466
632
  }
467
633
  ```
468
634
 
635
+ ## 🛡️ **ProGuard Configuration (Required for Production)**
636
+
637
+ **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.
638
+
639
+ ### **Add to `android/app/proguard-rules.pro`:**
640
+
641
+ ```proguard
642
+ # Add project specific ProGuard rules here.
643
+ # By default, the flags in this file are appended to flags specified
644
+ # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
645
+ # You can edit the include path and order by changing the proguardFiles
646
+ # directive in build.gradle.
647
+ #
648
+ # For more details, see
649
+ # http://developer.android.com/guide/developing/tools/proguard.html
650
+
651
+ # Add any project specific keep options here:
652
+
653
+ # 🚀 JSI Module ProGuard Rules - Prevent obfuscation of JSI classes
654
+ # react-native-pdf-jsi package classes
655
+ -keep class org.wonday.pdf.PDFJSIManager { *; }
656
+ -keep class org.wonday.pdf.PDFJSIModule { *; }
657
+ -keep class org.wonday.pdf.EnhancedPdfJSIBridge { *; }
658
+ -keep class org.wonday.pdf.RNPDFPackage { *; }
659
+ -keep class org.wonday.pdf.PdfManager { *; }
660
+ -keep class org.wonday.pdf.PDFNativeCacheManager { *; }
661
+ -keep class org.wonday.pdf.PdfView { *; }
662
+ -keep class org.wonday.pdf.events.TopChangeEvent { *; }
663
+
664
+ # Keep all JSI native methods
665
+ -keepclasseswithmembernames class * {
666
+ native <methods>;
667
+ }
668
+
669
+ # Keep JSI bridge methods
670
+ -keepclassmembers class * {
671
+ @com.facebook.react.bridge.ReactMethod <methods>;
672
+ }
673
+
674
+ # Keep React Native bridge classes
675
+ -keep class com.facebook.react.bridge.** { *; }
676
+ -keep class com.facebook.react.turbomodule.** { *; }
677
+
678
+ # Keep native library loading
679
+ -keep class com.facebook.soloader.** { *; }
680
+
681
+ # Keep JSI related classes
682
+ -keep class com.facebook.jni.** { *; }
683
+
684
+ # Prevent obfuscation of PDF JSI native methods
685
+ -keepclassmembers class org.wonday.pdf.PDFJSIManager {
686
+ native void nativeInitializeJSI(java.lang.Object);
687
+ native boolean nativeIsJSIAvailable();
688
+ native com.facebook.react.bridge.WritableMap nativeRenderPageDirect(java.lang.String, int, float, java.lang.String);
689
+ native com.facebook.react.bridge.WritableMap nativeGetPageMetrics(java.lang.String, int);
690
+ native boolean nativePreloadPagesDirect(java.lang.String, int, int);
691
+ native com.facebook.react.bridge.WritableMap nativeGetCacheMetrics(java.lang.String);
692
+ native boolean nativeClearCacheDirect(java.lang.String, java.lang.String);
693
+ native boolean nativeOptimizeMemory(java.lang.String);
694
+ native com.facebook.react.bridge.ReadableArray nativeSearchTextDirect(java.lang.String, java.lang.String, int, int);
695
+ native com.facebook.react.bridge.WritableMap nativeGetPerformanceMetrics(java.lang.String);
696
+ native boolean nativeSetRenderQuality(java.lang.String, int);
697
+ native void nativeCleanupJSI();
698
+ }
699
+
700
+ # Keep all PDF related classes
701
+ -keep class org.wonday.pdf.** { *; }
702
+
703
+ # Keep React Native modules
704
+ -keep class * extends com.facebook.react.bridge.ReactContextBaseJavaModule { *; }
705
+ -keep class * extends com.facebook.react.ReactPackage { *; }
706
+
707
+ # Keep native library names
708
+ -keepnames class * {
709
+ native <methods>;
710
+ }
711
+
712
+ # Keep crypto-js classes (dependency of react-native-pdf-jsi)
713
+ -keep class com.google.crypto.** { *; }
714
+ -keep class javax.crypto.** { *; }
715
+
716
+ # Keep JSI specific classes and methods
717
+ -keepclassmembers class org.wonday.pdf.** {
718
+ public <methods>;
719
+ protected <methods>;
720
+ }
721
+
722
+ # Keep all event classes
723
+ -keep class org.wonday.pdf.events.** { *; }
724
+
725
+ # Keep React Native JSI specific classes
726
+ -keep class com.facebook.jsi.** { *; }
727
+ -keep class com.facebook.hermes.** { *; }
728
+ ```
729
+
730
+ ### **Why These Rules Are Essential:**
731
+
732
+ 1. **JSI Class Protection**: Prevents ProGuard from obfuscating JSI-related classes
733
+ 2. **Native Method Preservation**: Keeps native method signatures intact
734
+ 3. **Bridge Method Safety**: Protects React Native bridge methods
735
+ 4. **Event System**: Maintains event handling functionality
736
+ 5. **Crypto Dependencies**: Preserves cryptographic functionality
737
+
738
+ ### **Build Configuration:**
739
+
740
+ Make sure your `android/app/build.gradle` has ProGuard enabled:
741
+
742
+ ```gradle
743
+ android {
744
+ buildTypes {
745
+ release {
746
+ minifyEnabled true
747
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
748
+ // ... other release config
749
+ }
750
+ }
751
+ }
752
+ ```
753
+
469
754
  ## 🚨 Expo Support
470
755
 
471
756
  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).
@@ -526,27 +811,115 @@ react-native run-ios
526
811
 
527
812
  **Q6. How do I enable JSI mode?**
528
813
  A6: JSI mode is automatically enabled on Android. Check JSI availability with:
529
- ```js
530
- const stats = await pdfRef.current.getJSIStats();
531
- console.log('JSI Available:', stats.jsiEnabled);
814
+ ```jsx
815
+ // Import JSI modules
816
+ let PDFJSI = null;
817
+ try {
818
+ const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI');
819
+ PDFJSI = PDFJSIModule.default;
820
+ } catch (error) {
821
+ console.log('JSI not available');
822
+ }
823
+
824
+ // Check availability
825
+ const isAvailable = await PDFJSI?.checkJSIAvailability();
826
+ console.log('JSI Available:', isAvailable);
532
827
  ```
533
828
 
534
829
  **Q7. What if JSI is not available?**
535
- A7: The package automatically falls back to standard bridge mode. You can check availability and handle accordingly:
536
- ```js
537
- if (stats.jsiEnabled) {
538
- // Use JSI methods
539
- await pdfRef.current.renderPageWithJSI(1, 2.0);
540
- } else {
541
- // Use standard methods
542
- pdfRef.current.setPage(1);
830
+ A7: The package automatically falls back to standard bridge mode. Always implement fallbacks:
831
+ ```jsx
832
+ // Import with fallback
833
+ let PDFJSI = null;
834
+ let usePDFJSI = null;
835
+
836
+ try {
837
+ const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI');
838
+ const usePDFJSIModule = require('react-native-pdf-jsi/src/hooks/usePDFJSI');
839
+
840
+ PDFJSI = PDFJSIModule.default;
841
+ usePDFJSI = usePDFJSIModule.default;
842
+ } catch (error) {
843
+ console.log('JSI not available, using fallback');
543
844
  }
845
+
846
+ // Use with fallback
847
+ const jsiHookResult = usePDFJSI ? usePDFJSI({
848
+ autoInitialize: true,
849
+ enablePerformanceTracking: true,
850
+ }) : { isJSIAvailable: false, isInitialized: true };
851
+ ```
852
+
853
+ **Q8. My app crashes in release mode with JSI errors**
854
+ A8: You need to add ProGuard rules. Add the complete ProGuard configuration from the documentation to your `android/app/proguard-rules.pro` file.
855
+
856
+ **Q9. How do I migrate from react-native-pdf?**
857
+ A9: Follow the migration steps in the documentation:
858
+ 1. Update package: `npm install react-native-pdf-jsi`
859
+ 2. Update imports: Use `require('react-native-pdf-jsi')`
860
+ 3. Add ProGuard rules
861
+ 4. Update component usage (same API)
862
+ 5. Optionally add JSI integration
863
+
864
+ **Q10. The shimmer loader gets stuck and documents don't load**
865
+ A10: This usually means JSI initialization is failing. Ensure:
866
+ - ProGuard rules are properly configured
867
+ - JSI modules are imported correctly with error handling
868
+ - Fallback mechanisms are in place
869
+ - Check console logs for JSI availability status
870
+
871
+ **Q11. TypeError: constructor is not callable**
872
+ A11: This error occurs when the Pdf component is not imported correctly. Use:
873
+ ```jsx
874
+ const PdfModule = require('react-native-pdf-jsi');
875
+ const Pdf = PdfModule.default;
876
+ // NOT: const Pdf = require('react-native-pdf-jsi');
544
877
  ```
545
878
  </details>
546
879
 
547
880
  ## 📝 Changelog
548
881
 
549
- ### v2.0.1 (2025) - Latest ✅ GOOGLE PLAY COMPLIANT
882
+ ### v2.1.0 (2025) - Latest ✅ ENHANCED 16KB COMPLIANCE & DOCUMENTATION
883
+
884
+ #### 🚀 **16KB Page Alignment Enhancements**
885
+ - **Dependency Updates**: Updated `io.legere:pdfiumandroid` from v1.0.24 to v1.0.32 for optimal 16KB support
886
+ - **Gson Update**: Updated `com.google.code.gson:gson` from v2.8.5 to v2.11.0 for compatibility
887
+ - **Build Configuration**: Updated `compileSdkVersion` and `targetSdkVersion` from 34 to 35 for Android 15+ compatibility
888
+ - **CMakeLists Enhancement**: Added missing executable linker flag `-Wl,-z,max-page-size=16384` for complete 16KB page alignment
889
+ - **Dependency Management**: Added exclusion for bundled PdfiumAndroid to prevent conflicts with specific version
890
+
891
+ #### 📚 **Documentation Overhaul**
892
+ - **README Rewrite**: Complete rewrite of README with real-world usage examples from production projects
893
+ - **Import Patterns**: Updated all examples to show correct import patterns using `require('react-native-pdf-jsi')`
894
+ - **Error Handling**: Added comprehensive error handling and fallback mechanisms in all examples
895
+ - **Modal Implementation**: Added complete modal-based PDF viewer example matching production usage
896
+ - **JSI Integration**: Updated JSI usage examples with proper initialization and error handling patterns
897
+
898
+ #### 🛡️ **Production Safety & ProGuard**
899
+ - **ProGuard Rules**: Added comprehensive ProGuard configuration documentation with complete rule set
900
+ - **Release Build Safety**: Added critical warnings about ProGuard rules preventing production crashes
901
+ - **JSI Class Protection**: Documented all necessary ProGuard rules for JSI class preservation
902
+ - **Native Method Safety**: Added rules for preserving native method signatures and React Native bridge methods
903
+
904
+ #### 📖 **Migration & FAQ Enhancement**
905
+ - **Step-by-Step Migration**: Complete migration guide from react-native-pdf with 5 clear steps
906
+ - **Common Issues**: Added solutions for shimmer loader stuck, constructor errors, and JSI initialization failures
907
+ - **Production Troubleshooting**: Added FAQ entries for release build crashes and ProGuard configuration
908
+ - **Error Solutions**: Documented solutions for "TypeError: constructor is not callable" and other common errors
909
+
910
+ #### ⚡ **Performance & Reliability**
911
+ - **JSI Fallback Patterns**: Enhanced JSI integration with robust fallback mechanisms for production stability
912
+ - **Error Handling**: Added comprehensive try-catch patterns for JSI module loading
913
+ - **Release Build Compatibility**: Ensured compatibility with both debug and release builds
914
+ - **Memory Management**: Enhanced memory optimization patterns for large PDF files
915
+
916
+ #### 📊 **Google Play Compliance**
917
+ - **16KB Verification**: Complete implementation of Google Play 16KB page size requirements
918
+ - **Android 15+ Ready**: Full compatibility with Android 15+ requirements
919
+ - **Future-Proof**: Ensures long-term compatibility with Google Play policy changes
920
+ - **Compliance Testing**: Added verification methods for 16KB page size support
921
+
922
+ ### v2.0.1 (2025) - ✅ GOOGLE PLAY COMPLIANT
550
923
  - 🚨 **Google Play 16KB Compliance**: Added full support for Google Play's 16KB page size requirement
551
924
  - 🔧 **NDK r27+ Support**: Updated to NDK version 27.0.12077973 for Android 15+ compatibility
552
925
  - 📱 **16KB Page Size Check**: Added `check16KBSupport()` method to verify compliance
@@ -602,67 +975,189 @@ if (stats.jsiEnabled) {
602
975
 
603
976
  ## 🔄 Migration from react-native-pdf
604
977
 
605
- ```js
606
- // Old import
607
- import Pdf from 'react-native-pdf';
978
+ ### **Step 1: Update Package**
608
979
 
609
- // New import (same API, enhanced performance)
610
- import Pdf from 'react-native-pdf-enhanced';
980
+ ```bash
981
+ # Remove old package
982
+ npm uninstall react-native-pdf
611
983
 
612
- // All existing code works without changes
613
- // JSI enhancements are automatic on Android
984
+ # Install new package
985
+ npm install react-native-pdf-jsi react-native-blob-util
614
986
  ```
615
987
 
616
- ## 📦 Available Exports
988
+ ### **Step 2: Update Imports**
617
989
 
618
- ### Core Components
619
- ```js
620
- // Standard PDF component (enhanced with JSI)
621
- import Pdf from 'react-native-pdf-enhanced';
990
+ ```jsx
991
+ // ❌ Old import
992
+ import Pdf from 'react-native-pdf';
622
993
 
623
- // Enhanced PDF view with automatic JSI detection
624
- import { EnhancedPdfView } from 'react-native-pdf-enhanced';
994
+ // New import
995
+ const PdfModule = require('react-native-pdf-jsi');
996
+ const Pdf = PdfModule.default;
997
+ ```
625
998
 
626
- // React hook for JSI operations
627
- import { usePDFJSI } from 'react-native-pdf-enhanced';
999
+ ### **Step 3: Add ProGuard Rules**
628
1000
 
629
- // Direct JSI interface
630
- import { PDFJSI } from 'react-native-pdf-enhanced';
1001
+ Add the ProGuard rules from the section above to your `android/app/proguard-rules.pro`.
1002
+
1003
+ ### **Step 4: Update Component Usage**
1004
+
1005
+ ```jsx
1006
+ // ❌ Old usage
1007
+ <Pdf
1008
+ source={{ uri: 'https://example.com/document.pdf' }}
1009
+ />
1010
+
1011
+ // ✅ New usage (same API, enhanced performance)
1012
+ <Pdf
1013
+ source={{ uri: 'https://example.com/document.pdf' }}
1014
+ style={{ flex: 1 }}
1015
+ onLoadComplete={(numberOfPages, filePath) => {
1016
+ console.log(`📄 PDF loaded: ${numberOfPages} pages`);
1017
+ }}
1018
+ onPageChanged={(page, numberOfPages) => {
1019
+ console.log(`📄 Current page: ${page}`);
1020
+ }}
1021
+ trustAllCerts={false}
1022
+ />
631
1023
  ```
632
1024
 
633
- ### Individual JSI Methods
634
- ```js
635
- import {
636
- renderPageDirect,
637
- getPageMetrics,
638
- preloadPagesDirect,
639
- getCacheMetrics,
640
- clearCacheDirect,
641
- optimizeMemory,
642
- searchTextDirect,
643
- getPerformanceMetrics,
644
- setRenderQuality,
645
- getJSIStats,
646
- getPerformanceHistory,
647
- clearPerformanceHistory
648
- } from 'react-native-pdf-enhanced';
649
- ```
650
-
651
- ### Utility Functions
652
- ```js
653
- import { EnhancedPdfUtils } from 'react-native-pdf-enhanced';
1025
+ ### **Step 5: Add JSI Integration (Optional)**
1026
+
1027
+ For enhanced performance, add JSI integration:
654
1028
 
655
- // Check JSI availability
656
- const isAvailable = await EnhancedPdfUtils.isJSIAvailable();
1029
+ ```jsx
1030
+ // Import JSI modules with error handling
1031
+ let PDFJSI = null;
1032
+ let usePDFJSI = null;
1033
+
1034
+ try {
1035
+ const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI');
1036
+ const usePDFJSIModule = require('react-native-pdf-jsi/src/hooks/usePDFJSI');
1037
+
1038
+ PDFJSI = PDFJSIModule.default;
1039
+ usePDFJSI = usePDFJSIModule.default;
1040
+ } catch (error) {
1041
+ console.log('JSI not available, using fallback');
1042
+ }
657
1043
 
658
- // Get performance benchmark
659
- const benchmark = await EnhancedPdfUtils.getPerformanceBenchmark();
1044
+ // Use JSI hook
1045
+ const jsiHookResult = usePDFJSI ? usePDFJSI({
1046
+ autoInitialize: true,
1047
+ enablePerformanceTracking: true,
1048
+ }) : { isJSIAvailable: false };
1049
+ ```
1050
+
1051
+ ### **Migration Benefits:**
660
1052
 
661
- // Clear all caches
662
- await EnhancedPdfUtils.clearAllCaches();
1053
+ - **Same API**: No code changes required for basic usage
1054
+ - ✅ **Enhanced Performance**: Up to 80x faster on Android
1055
+ - ✅ **Google Play Compliant**: 16KB page size support
1056
+ - ✅ **Future-Proof**: Built with latest NDK and modern toolchain
1057
+ - ✅ **Better Caching**: Advanced persistent cache system
663
1058
 
664
- // Optimize memory
665
- await EnhancedPdfUtils.optimizeAllMemory();
1059
+ ## 📦 Available Exports
1060
+
1061
+ ### **Core Components**
1062
+ ```jsx
1063
+ // Standard PDF component (enhanced with JSI)
1064
+ const PdfModule = require('react-native-pdf-jsi');
1065
+ const Pdf = PdfModule.default;
1066
+
1067
+ // Usage
1068
+ <Pdf
1069
+ source={{ uri: 'https://example.com/document.pdf' }}
1070
+ style={{ flex: 1 }}
1071
+ onLoadComplete={(numberOfPages, filePath) => {
1072
+ console.log(`📄 PDF loaded: ${numberOfPages} pages`);
1073
+ }}
1074
+ trustAllCerts={false}
1075
+ />
1076
+ ```
1077
+
1078
+ ### **JSI Modules (Advanced Usage)**
1079
+ ```jsx
1080
+ // Import JSI functionality with error handling
1081
+ let PDFJSI = null;
1082
+ let usePDFJSI = null;
1083
+
1084
+ try {
1085
+ const PDFJSIModule = require('react-native-pdf-jsi/src/PDFJSI');
1086
+ const usePDFJSIModule = require('react-native-pdf-jsi/src/hooks/usePDFJSI');
1087
+
1088
+ PDFJSI = PDFJSIModule.default;
1089
+ usePDFJSI = usePDFJSIModule.default;
1090
+ } catch (error) {
1091
+ console.log('JSI not available, using fallback');
1092
+ }
1093
+
1094
+ // Use JSI hook for enhanced operations
1095
+ const jsiHookResult = usePDFJSI ? usePDFJSI({
1096
+ autoInitialize: true,
1097
+ enablePerformanceTracking: true,
1098
+ enableCaching: true,
1099
+ maxCacheSize: 200,
1100
+ }) : {
1101
+ isJSIAvailable: false,
1102
+ isInitialized: true
1103
+ };
1104
+ ```
1105
+
1106
+ ### **JSI Methods Available**
1107
+ ```jsx
1108
+ // When JSI is available, these methods provide enhanced performance:
1109
+ const methods = {
1110
+ // High-performance page rendering
1111
+ renderPage: (pdfId, pageNumber, scale, base64Data) => Promise,
1112
+
1113
+ // Get page metrics
1114
+ getPageMetrics: (pdfId, pageNumber) => Promise,
1115
+
1116
+ // Preload pages for faster access
1117
+ preloadPages: (pdfId, startPage, endPage) => Promise,
1118
+
1119
+ // Cache management
1120
+ getCacheMetrics: (pdfId) => Promise,
1121
+ clearCache: (pdfId, cacheType) => Promise,
1122
+
1123
+ // Memory optimization
1124
+ optimizeMemory: (pdfId) => Promise,
1125
+
1126
+ // Text search
1127
+ searchText: (pdfId, query, startPage, endPage) => Promise,
1128
+
1129
+ // Performance monitoring
1130
+ getPerformanceMetrics: (pdfId) => Promise,
1131
+
1132
+ // Render quality control
1133
+ setRenderQuality: (pdfId, quality) => Promise,
1134
+
1135
+ // JSI availability check
1136
+ checkJSIAvailability: () => Promise,
1137
+
1138
+ // Get JSI statistics
1139
+ getJSIStats: () => Promise
1140
+ };
1141
+ ```
1142
+
1143
+ ### **Error Handling Pattern**
1144
+ ```jsx
1145
+ // Always wrap JSI operations in try-catch with fallbacks
1146
+ const handleJSIOperation = async () => {
1147
+ try {
1148
+ if (PDFJSI && jsiHookResult.isJSIAvailable) {
1149
+ // Use JSI for enhanced performance
1150
+ const result = await PDFJSI.renderPageDirect('pdf_123', 1, 2.0, 'base64data');
1151
+ console.log('🚀 JSI operation successful:', result);
1152
+ } else {
1153
+ // Fallback to standard methods
1154
+ console.log('📱 Using standard PDF methods');
1155
+ }
1156
+ } catch (error) {
1157
+ console.log('❌ Operation failed:', error);
1158
+ // Handle error gracefully
1159
+ }
1160
+ };
666
1161
  ```
667
1162
 
668
1163
  ### Check Google Play 16KB Compliance
@@ -937,7 +1432,7 @@ For issues and questions:
937
1432
 
938
1433
  *Transform your PDF viewing experience with enterprise-grade performance and reliability.*
939
1434
 
940
- **v1.0.3 - Enhanced JSI Integration**
1435
+ **v2.1.0 - Enhanced 16KB Compliance & Documentation**
941
1436
  **Copyright (c) 2025-present, Punith M (punithm300@gmail.com). Enhanced PDF JSI Integration. All rights reserved.**
942
1437
 
943
1438
  *Original work Copyright (c) 2017-present, Wonday (@wonday.org). All rights reserved.*
@@ -93,14 +93,15 @@ android {
93
93
  if (agpVersion.tokenize('.')[0].toInteger() >= 7) {
94
94
  namespace "org.wonday.pdf"
95
95
  }
96
- compileSdkVersion safeExtGet('compileSdkVersion', 34)
96
+ compileSdkVersion safeExtGet('compileSdkVersion', 35)
97
97
 
98
98
  // 🚀 NDK Configuration for 16KB Page Size Support
99
- ndkVersion "27.0.12077973" // NDK r27+ required for 16KB page support
99
+ // Use NDK r28 which provides proper 16KB page alignment toolchain
100
+ ndkVersion "28.0.12674087"
100
101
 
101
102
  defaultConfig {
102
103
  minSdkVersion safeExtGet('minSdkVersion', 21)
103
- targetSdkVersion safeExtGet('targetSdkVersion', 34)
104
+ targetSdkVersion safeExtGet('targetSdkVersion', 35)
104
105
  buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString())
105
106
 
106
107
  // 🚀 JSI Configuration with 16KB Page Support
@@ -69,6 +69,10 @@ target_compile_options(
69
69
  -fvisibility=hidden
70
70
  )
71
71
 
72
+ # 16KB page size alignment for shared objects
73
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
74
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
75
+
72
76
  # Set output directory
73
77
  set_target_properties(
74
78
  pdfjsi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-pdf-jsi",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "summary": "High-performance React Native PDF viewer with JSI acceleration - up to 80x faster than traditional bridge",
5
5
  "description": "🚀 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 cache and advanced memory optimization. Google Play 16KB page size compliant for Android 15+. Supports iOS, Android, and Windows platforms.",
6
6
  "main": "index.js",