react-native-pdf-jsi 4.3.0 → 4.3.2

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/PdfView.js CHANGED
@@ -393,7 +393,7 @@ export default class PdfView extends Component {
393
393
  renderScrollComponent={(props) => <ScrollView
394
394
  {...props}
395
395
  centerContent={this.state.centerContent}
396
- pinchGestureEnabled={false}
396
+ pinchGestureEnabled={true}
397
397
  />}
398
398
  initialScrollIndex={this.props.page < 1 ? 0 : this.props.page - 1}
399
399
  onViewableItemsChanged={this._onViewableItemsChanged}
package/README.md CHANGED
@@ -12,6 +12,7 @@
12
12
  [![Expo Compatible](https://img.shields.io/badge/Expo-Compatible-4630EB?style=flat-square&logo=expo)](https://expo.dev)
13
13
  [![total downloads](https://img.shields.io/npm/dt/react-native-pdf-jsi?style=flat-square&logo=npm&color=cb3837)](https://www.npmjs.com/package/react-native-pdf-jsi)
14
14
  [![weekly downloads](https://img.shields.io/npm/dw/react-native-pdf-jsi?style=flat-square&logo=npm&color=cb3837)](https://www.npmjs.com/package/react-native-pdf-jsi)
15
+ [![monthly downloads](https://img.shields.io/npm/dm/react-native-pdf-jsi?style=flat-square&logo=npm&color=cb3837)](https://www.npmjs.com/package/react-native-pdf-jsi)
15
16
  [![GitHub stars](https://img.shields.io/github/stars/126punith/react-native-pdf-jsi?style=flat-square&logo=github&color=181717)](https://github.com/126punith/react-native-pdf-jsi)
16
17
  [![license](https://img.shields.io/npm/l/react-native-pdf-jsi?style=flat-square&color=green)](https://github.com/126punith/react-native-pdf-jsi/blob/main/LICENSE)
17
18
 
@@ -456,6 +457,12 @@ MIT License - see [LICENSE](LICENSE) file for details.
456
457
 
457
458
  ## Recent Fixes
458
459
 
460
+ ### iOS Pinch-to-Zoom (v4.3.2)
461
+ Fixed iOS pinch-to-zoom not working when the scroll view delegate was set to the view itself or when the delegate proxy's primary didn't implement `viewForZoomingInScrollView`. Implemented the missing `viewForZoomingInScrollView:` in RNPDFPdfView so the scroll view receives the correct zoomable view. Fixes [#23](https://github.com/126punith/react-native-pdf-jsi/issues/23) (PR [#22](https://github.com/126punith/react-native-pdf-jsi/pull/22)).
462
+
463
+ ### Android PDF Preserved on Navigation (v4.3.1)
464
+ Fixed issue where the PDF instance was destroyed on Android when navigating away and returning to the screen ([#20](https://github.com/126punith/react-native-pdf-jsi/issues/20)). The PDF is now preserved in memory during navigation (matching iOS behavior) and only recycled when the component unmounts.
465
+
459
466
  ### Expo Support (v4.3.0)
460
467
  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`.
461
468
 
@@ -60,7 +60,8 @@ public class PdfManager extends SimpleViewManager<PdfView> implements RNPDFPdfVi
60
60
 
61
61
  @Override
62
62
  public void onDropViewInstance(PdfView pdfView) {
63
- pdfView = null;
63
+ pdfView.recycle();
64
+ this.pdfView = null;
64
65
  }
65
66
 
66
67
  @ReactProp(name = "path")
@@ -349,6 +349,18 @@ public class PdfView extends PDFView implements OnPageChangeListener,OnLoadCompl
349
349
  this.drawPdf();
350
350
  }
351
351
 
352
+ /**
353
+ * Override to prevent barteksc PDFView's recycle() on navigation.
354
+ * The parent class calls recycle() in onDetachedFromWindow, which destroys the PDF
355
+ * when the view is temporarily detached (e.g., navigating to another screen).
356
+ * We only recycle when PdfManager.onDropViewInstance is called (component unmount).
357
+ */
358
+ @Override
359
+ protected void onDetachedFromWindow() {
360
+ // Intentionally skip super to prevent barteksc PDFView's recycle() which destroys
361
+ // the PDF on navigation. We only recycle when PdfManager.onDropViewInstance is called.
362
+ }
363
+
352
364
  public void drawPdf() {
353
365
 
354
366
  // FIX: Check if we actually need to reload the document
@@ -98,10 +98,33 @@ const float MIN_SCALE = 1.0f;
98
98
  }
99
99
 
100
100
  - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
101
+ // First check if primary delegate (PDFView's internal) handles it
101
102
  if (_primary && [_primary respondsToSelector:@selector(viewForZoomingInScrollView:)]) {
102
- return [_primary viewForZoomingInScrollView:scrollView];
103
+ UIView *zoomView = [_primary viewForZoomingInScrollView:scrollView];
104
+ if (zoomView != nil) {
105
+ NSLog(@"🔍 [iOS Zoom Delegate] Primary delegate returned zoom view: %@", NSStringFromClass([zoomView class]));
106
+ return zoomView;
107
+ }
103
108
  }
104
- return nil;
109
+
110
+ // PDFKit's scroll view needs to zoom the PDFDocumentView
111
+ // Search for it in the hierarchy
112
+ for (UIView *subview in scrollView.subviews) {
113
+ NSString *className = NSStringFromClass([subview class]);
114
+ if ([className containsString:@"PDFDocumentView"] || [className containsString:@"PDFPage"]) {
115
+ NSLog(@"🔍 [iOS Zoom Delegate] Found PDF view for zooming: %@", className);
116
+ return subview;
117
+ }
118
+ }
119
+
120
+ // Fallback to first subview if it exists
121
+ UIView *fallback = scrollView.subviews.firstObject;
122
+ if (fallback) {
123
+ NSLog(@"🔍 [iOS Zoom Delegate] Using fallback zoom view: %@", NSStringFromClass([fallback class]));
124
+ } else {
125
+ NSLog(@"⚠️ [iOS Zoom Delegate] WARNING: No view found for zooming! Scroll view has %lu subviews", (unsigned long)scrollView.subviews.count);
126
+ }
127
+ return fallback;
105
128
  }
106
129
 
107
130
  @end
@@ -443,10 +466,14 @@ using namespace facebook::react;
443
466
  [[_pdfView document] setDelegate: self];
444
467
  [_pdfView setDelegate: self];
445
468
 
446
- // Disable built-in double tap, so as not to conflict with custom recognizers.
469
+ // Only disable double-tap recognizers to avoid conflicts with custom double-tap
470
+ // Leave all other gestures (including pinch) enabled
447
471
  for (UIGestureRecognizer *recognizer in _pdfView.gestureRecognizers) {
448
472
  if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
449
- recognizer.enabled = NO;
473
+ UITapGestureRecognizer *tapGesture = (UITapGestureRecognizer *)recognizer;
474
+ if (tapGesture.numberOfTapsRequired == 2) {
475
+ recognizer.enabled = NO;
476
+ }
450
477
  }
451
478
  }
452
479
 
@@ -661,6 +688,18 @@ using namespace facebook::react;
661
688
  _pdfView.maxScaleFactor = _fixScaleFactor*_maxScale;
662
689
  }
663
690
  }
691
+
692
+ // CRITICAL: Also configure the internal scroll view zoom scales
693
+ // This must be done AFTER _fixScaleFactor is set above
694
+ if (_internalScrollView && _fixScaleFactor > 0) {
695
+ _internalScrollView.minimumZoomScale = _fixScaleFactor * _minScale;
696
+ _internalScrollView.maximumZoomScale = _fixScaleFactor * _maxScale;
697
+ _internalScrollView.zoomScale = _pdfView.scaleFactor;
698
+ RCTLogInfo(@"🔍 [iOS Zoom] Configured internal scroll view zoom scales - min=%f, max=%f, current=%f",
699
+ _internalScrollView.minimumZoomScale,
700
+ _internalScrollView.maximumZoomScale,
701
+ _internalScrollView.zoomScale);
702
+ }
664
703
 
665
704
  }
666
705
 
@@ -668,6 +707,12 @@ using namespace facebook::react;
668
707
  _pdfView.scaleFactor = _scale * _fixScaleFactor;
669
708
  if (_pdfView.scaleFactor>_pdfView.maxScaleFactor) _pdfView.scaleFactor = _pdfView.maxScaleFactor;
670
709
  if (_pdfView.scaleFactor<_pdfView.minScaleFactor) _pdfView.scaleFactor = _pdfView.minScaleFactor;
710
+
711
+ // Also update internal scroll view zoom scale when scale changes
712
+ if (_internalScrollView && _fixScaleFactor > 0) {
713
+ _internalScrollView.zoomScale = _pdfView.scaleFactor;
714
+ RCTLogInfo(@"🔍 [iOS Zoom] Updated internal scroll view zoom scale to %f", _internalScrollView.zoomScale);
715
+ }
671
716
  }
672
717
 
673
718
  if (_pdfDocument && ([effectiveChangedProps containsObject:@"path"] || [changedProps containsObject:@"horizontal"])) {
@@ -1328,6 +1373,18 @@ using namespace facebook::react;
1328
1373
  // Keep vertical bounce enabled for natural scrolling feel
1329
1374
  scrollView.bounces = YES;
1330
1375
 
1376
+ // Configure scroll view zoom scales to match PDFView's scale factors
1377
+ // This enables native pinch-to-zoom gestures
1378
+ if (_fixScaleFactor > 0) {
1379
+ scrollView.minimumZoomScale = _fixScaleFactor * _minScale;
1380
+ scrollView.maximumZoomScale = _fixScaleFactor * _maxScale;
1381
+ scrollView.zoomScale = _pdfView.scaleFactor;
1382
+ RCTLogInfo(@"🔍 [iOS Zoom] Configured zoom scales - min=%f, max=%f, current=%f",
1383
+ scrollView.minimumZoomScale,
1384
+ scrollView.maximumZoomScale,
1385
+ scrollView.zoomScale);
1386
+ }
1387
+
1331
1388
  RCTLogInfo(@"📊 [iOS Scroll] ScrollView config - scrollEnabled=%d, alwaysBounceHorizontal=%d, bounces=%d, delegate=%@",
1332
1389
  scrollView.scrollEnabled,
1333
1390
  scrollView.alwaysBounceHorizontal,
@@ -1336,23 +1393,30 @@ using namespace facebook::react;
1336
1393
 
1337
1394
  // IMPORTANT: PDFKit relies on the scrollView delegate for pinch-zoom (viewForZoomingInScrollView).
1338
1395
  // Install a proxy delegate that forwards to the original delegate, while still letting us observe scroll events.
1339
- if (!_internalScrollView) {
1340
- RCTLogInfo(@"✅ [iOS Scroll] Setting internal scroll view reference");
1396
+ // CRITICAL FIX: Always set up delegate for new scroll views (PDFView may recreate scroll view on document load)
1397
+ if (!_internalScrollView || _internalScrollView != scrollView) {
1398
+ RCTLogInfo(@"✅ [iOS Scroll] Setting up scroll view delegate (new=%d)", _internalScrollView == nil);
1341
1399
  _internalScrollView = scrollView;
1342
- if (scrollView.delegate && scrollView.delegate != self) {
1343
- _originalScrollDelegate = scrollView.delegate;
1344
- RCTLogInfo(@"📝 [iOS Scroll] Stored original scroll delegate");
1400
+
1401
+ // Get the current delegate (might be PDFView's internal delegate)
1402
+ id<UIScrollViewDelegate> currentDelegate = scrollView.delegate;
1403
+
1404
+ // Only capture original delegate if it's not us or our proxy
1405
+ if (currentDelegate && currentDelegate != self && ![currentDelegate isKindOfClass:[RNPDFScrollViewDelegateProxy class]]) {
1406
+ _originalScrollDelegate = currentDelegate;
1407
+ RCTLogInfo(@"📝 [iOS Scroll] Captured original scroll delegate: %@", NSStringFromClass([currentDelegate class]));
1345
1408
  }
1409
+
1346
1410
  if (_originalScrollDelegate) {
1347
1411
  _scrollDelegateProxy = [[RNPDFScrollViewDelegateProxy alloc] initWithPrimary:_originalScrollDelegate secondary:(id<UIScrollViewDelegate>)self];
1348
1412
  scrollView.delegate = (id<UIScrollViewDelegate>)_scrollDelegateProxy;
1349
1413
  RCTLogInfo(@"🔗 [iOS Scroll] Installed scroll delegate proxy");
1350
1414
  } else {
1351
1415
  scrollView.delegate = self;
1352
- RCTLogInfo(@"🔗 [iOS Scroll] Set self as scroll delegate");
1416
+ RCTLogInfo(@"🔗 [iOS Scroll] Set self as scroll delegate (no original delegate)");
1353
1417
  }
1354
1418
  } else {
1355
- RCTLogInfo(@"⚠️ [iOS Scroll] Internal scroll view already set, skipping delegate setup");
1419
+ RCTLogInfo(@"⚠️ [iOS Scroll] Same scroll view, delegate already configured");
1356
1420
  }
1357
1421
  }
1358
1422
 
@@ -1440,6 +1504,57 @@ using namespace facebook::react;
1440
1504
  }
1441
1505
  }
1442
1506
 
1507
+ #pragma mark - UIScrollViewDelegate Zoom Support
1508
+
1509
+ - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
1510
+ // Called during pinch-to-zoom
1511
+ if (_fixScaleFactor > 0 && _pdfView.scaleFactor > 0) {
1512
+ float newScale = _pdfView.scaleFactor / _fixScaleFactor;
1513
+
1514
+ // Only notify if scale changed significantly (prevent spam)
1515
+ if (fabs(_scale - newScale) > 0.01f) {
1516
+ _scale = newScale;
1517
+ RCTLogInfo(@"🔍 [iOS Zoom] Pinch zoom - scale changed to %f", _scale);
1518
+ [self notifyOnChangeWithMessage:[[NSString alloc] initWithString:
1519
+ [NSString stringWithFormat:@"scaleChanged|%f", _scale]]];
1520
+ }
1521
+ }
1522
+ }
1523
+
1524
+ // CRITICAL: Return the view that should be zoomed
1525
+ - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
1526
+ // Search for PDFDocumentView in the scroll view's hierarchy
1527
+ for (UIView *subview in scrollView.subviews) {
1528
+ NSString *className = NSStringFromClass([subview class]);
1529
+ if ([className containsString:@"PDFDocumentView"] || [className containsString:@"PDFPage"]) {
1530
+ RCTLogInfo(@"🔍 [iOS Zoom] viewForZoomingInScrollView returning: %@", className);
1531
+ return subview;
1532
+ }
1533
+ }
1534
+
1535
+ // Fallback to first subview
1536
+ UIView *fallback = scrollView.subviews.firstObject;
1537
+ if (fallback) {
1538
+ RCTLogInfo(@"🔍 [iOS Zoom] viewForZoomingInScrollView using fallback: %@", NSStringFromClass([fallback class]));
1539
+ return fallback;
1540
+ }
1541
+
1542
+ RCTLogInfo(@"⚠️ [iOS Zoom] viewForZoomingInScrollView returning NIL - no view to zoom!");
1543
+ return nil;
1544
+ }
1545
+
1546
+ - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
1547
+ // Optional: Track zoom start
1548
+ RCTLogInfo(@"🔍 [iOS Zoom] Will begin zooming");
1549
+ }
1550
+
1551
+ - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView
1552
+ withView:(UIView *)view
1553
+ atScale:(CGFloat)scale {
1554
+ // Optional: Track zoom end
1555
+ RCTLogInfo(@"🔍 [iOS Zoom] Did end zooming at scale %f", scale);
1556
+ }
1557
+
1443
1558
  // Enhanced progressive loading methods
1444
1559
  - (void)preloadAdjacentPages:(int)currentPage
1445
1560
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-pdf-jsi",
3
- "version": "4.3.0",
3
+ "version": "4.3.2",
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",