react-native-pdf-jsi 3.4.0 → 3.4.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.
|
@@ -144,6 +144,11 @@ public class PdfManager extends SimpleViewManager<PdfView> implements RNPDFPdfVi
|
|
|
144
144
|
// NOOP on Android
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
@Override
|
|
148
|
+
public void setEnableMomentum(PdfView view, boolean value) {
|
|
149
|
+
// NOOP on Android - momentum scrolling is handled automatically by Android's ScrollView
|
|
150
|
+
}
|
|
151
|
+
|
|
147
152
|
@ReactProp(name = "fitPolicy")
|
|
148
153
|
public void setFitPolicy(PdfView pdfView, int fitPolicy) {
|
|
149
154
|
pdfView.setFitPolicy(fitPolicy);
|
|
@@ -28,9 +28,10 @@
|
|
|
28
28
|
enableAnnotationRendering: ?boolean,
|
|
29
29
|
showsHorizontalScrollIndicator: ?boolean,
|
|
30
30
|
showsVerticalScrollIndicator: ?boolean,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
scrollEnabled: ?boolean,
|
|
32
|
+
enableMomentum: ?boolean,
|
|
33
|
+
enableAntialiasing: ?boolean,
|
|
34
|
+
enableDoubleTapZoom: ?boolean,
|
|
34
35
|
fitPolicy: ?Int32,
|
|
35
36
|
spacing: ?Int32,
|
|
36
37
|
password: ?string,
|
|
@@ -19,6 +19,24 @@
|
|
|
19
19
|
|
|
20
20
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
21
21
|
#import <React/RCTViewComponentView.h>
|
|
22
|
+
#import <React/RCTComponentViewProtocol.h>
|
|
23
|
+
|
|
24
|
+
#ifdef __cplusplus
|
|
25
|
+
extern "C" {
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
// Forward declaration for codegen - ensures RNPDFPdfViewCls() is visible to RCTThirdPartyComponentsProvider
|
|
29
|
+
// Using extern "C" for proper C linkage, matching React Native's pattern
|
|
30
|
+
Class<RCTComponentViewProtocol> RNPDFPdfViewCls(void);
|
|
31
|
+
|
|
32
|
+
// Alias function based on codegen name "rnpdf" - ensures codegen can find the function
|
|
33
|
+
// even if it uses the codegen name instead of componentProvider name
|
|
34
|
+
Class<RCTComponentViewProtocol> rnpdfCls(void);
|
|
35
|
+
|
|
36
|
+
#ifdef __cplusplus
|
|
37
|
+
}
|
|
38
|
+
#endif
|
|
39
|
+
|
|
22
40
|
#endif
|
|
23
41
|
|
|
24
42
|
@class RCTEventDispatcher;
|
|
@@ -29,7 +47,7 @@ RCTViewComponentView
|
|
|
29
47
|
#else
|
|
30
48
|
UIView
|
|
31
49
|
#endif
|
|
32
|
-
<UIGestureRecognizerDelegate>
|
|
50
|
+
<UIGestureRecognizerDelegate, UIScrollViewDelegate>
|
|
33
51
|
- (instancetype)initWithBridge:(RCTBridge *)bridge;
|
|
34
52
|
|
|
35
53
|
@property(nonatomic, strong) NSString *path;
|
|
@@ -66,6 +66,8 @@ const float MIN_SCALE = 1.0f;
|
|
|
66
66
|
RCTBridge *_bridge;
|
|
67
67
|
PDFDocument *_pdfDocument;
|
|
68
68
|
PDFView *_pdfView;
|
|
69
|
+
UIScrollView *_internalScrollView;
|
|
70
|
+
id<UIScrollViewDelegate> _originalScrollDelegate;
|
|
69
71
|
PDFOutline *root;
|
|
70
72
|
float _fixScaleFactor;
|
|
71
73
|
bool _initialed;
|
|
@@ -103,13 +105,45 @@ using namespace facebook::react;
|
|
|
103
105
|
|
|
104
106
|
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
105
107
|
{
|
|
106
|
-
|
|
108
|
+
// Defensive check: Ensure the descriptor class exists before returning
|
|
109
|
+
// This prevents nil object insertion in RCTThirdPartyComponentsProvider
|
|
110
|
+
// The component name must match the codegen name: "RNPDFPdfView"
|
|
111
|
+
// Using static to ensure the provider is initialized only once
|
|
112
|
+
static ComponentDescriptorProvider provider = concreteComponentDescriptorProvider<RNPDFPdfViewComponentDescriptor>();
|
|
113
|
+
return provider;
|
|
107
114
|
}
|
|
108
115
|
|
|
109
116
|
// Needed because of this: https://github.com/facebook/react-native/pull/37274
|
|
110
117
|
+ (void)load
|
|
111
118
|
{
|
|
112
119
|
[super load];
|
|
120
|
+
|
|
121
|
+
// Force class to be loaded before React Native tries to register it
|
|
122
|
+
// This ensures RNPDFPdfViewCls() returns a valid class, preventing nil insertion
|
|
123
|
+
static dispatch_once_t onceToken;
|
|
124
|
+
dispatch_once(&onceToken, ^{
|
|
125
|
+
// Force class initialization by accessing the class
|
|
126
|
+
Class cls = [self class];
|
|
127
|
+
if (cls == nil) {
|
|
128
|
+
RCTLogError(@"RNPDFPdfView: Class is nil in +load");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Ensure component name is properly set for registration
|
|
133
|
+
// This helps React Native's RCTThirdPartyComponentsProvider find the component
|
|
134
|
+
// The component name must match the codegen name: "RNPDFPdfView"
|
|
135
|
+
NSString *componentName = NSStringFromClass(cls);
|
|
136
|
+
if (componentName == nil || componentName.length == 0) {
|
|
137
|
+
RCTLogError(@"RNPDFPdfView: Component name is nil or empty");
|
|
138
|
+
} else if (![componentName isEqualToString:@"RNPDFPdfView"]) {
|
|
139
|
+
RCTLogWarn(@"RNPDFPdfView: Component name mismatch. Expected 'RNPDFPdfView', got '%@'", componentName);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Verify class is accessible (RNPDFPdfViewCls is defined later, so we just verify the class itself)
|
|
143
|
+
if (cls != RNPDFPdfView.class) {
|
|
144
|
+
RCTLogError(@"RNPDFPdfView: Class mismatch in +load");
|
|
145
|
+
}
|
|
146
|
+
});
|
|
113
147
|
}
|
|
114
148
|
|
|
115
149
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
@@ -196,11 +230,6 @@ using namespace facebook::react;
|
|
|
196
230
|
[updatedPropNames addObject:@"scrollEnabled"];
|
|
197
231
|
}
|
|
198
232
|
|
|
199
|
-
if (_enableMomentum != newProps.enableMomentum) {
|
|
200
|
-
_enableMomentum = newProps.enableMomentum;
|
|
201
|
-
[updatedPropNames addObject:@"enableMomentum"];
|
|
202
|
-
}
|
|
203
|
-
|
|
204
233
|
[super updateProps:props oldProps:oldProps];
|
|
205
234
|
[self didSetProps:updatedPropNames];
|
|
206
235
|
}
|
|
@@ -255,7 +284,7 @@ using namespace facebook::react;
|
|
|
255
284
|
|
|
256
285
|
- (void)setNativePage:(NSInteger)page
|
|
257
286
|
{
|
|
258
|
-
_page = page;
|
|
287
|
+
_page = (int)page;
|
|
259
288
|
[self didSetProps:[NSArray arrayWithObject:@"page"]];
|
|
260
289
|
}
|
|
261
290
|
|
|
@@ -289,7 +318,6 @@ using namespace facebook::react;
|
|
|
289
318
|
_showsHorizontalScrollIndicator = YES;
|
|
290
319
|
_showsVerticalScrollIndicator = YES;
|
|
291
320
|
_scrollEnabled = YES;
|
|
292
|
-
_enableMomentum = YES;
|
|
293
321
|
|
|
294
322
|
// Enhanced properties
|
|
295
323
|
_enableCaching = YES;
|
|
@@ -529,37 +557,21 @@ using namespace facebook::react;
|
|
|
529
557
|
[self setScrollIndicators:self horizontal:_showsHorizontalScrollIndicator vertical:_showsVerticalScrollIndicator depth:0];
|
|
530
558
|
}
|
|
531
559
|
|
|
532
|
-
|
|
533
|
-
if (_scrollEnabled) {
|
|
534
|
-
for (UIView *subview in _pdfView.subviews) {
|
|
535
|
-
if ([subview isKindOfClass:[UIScrollView class]]) {
|
|
536
|
-
UIScrollView *scrollView = (UIScrollView *)subview;
|
|
537
|
-
scrollView.scrollEnabled = YES;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
} else {
|
|
541
|
-
for (UIView *subview in _pdfView.subviews) {
|
|
542
|
-
if ([subview isKindOfClass:[UIScrollView class]]) {
|
|
543
|
-
UIScrollView *scrollView = (UIScrollView *)subview;
|
|
544
|
-
scrollView.scrollEnabled = NO;
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Apply momentum property
|
|
560
|
+
// Configure scroll view (scrollEnabled)
|
|
551
561
|
if (_pdfDocument && ([changedProps containsObject:@"path"] ||
|
|
552
|
-
[changedProps containsObject:@"
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
scrollView.bounces = _enableMomentum;
|
|
559
|
-
scrollView.alwaysBounceVertical = _enableMomentum;
|
|
560
|
-
scrollView.alwaysBounceHorizontal = _enableMomentum;
|
|
561
|
-
}
|
|
562
|
+
[changedProps containsObject:@"scrollEnabled"])) {
|
|
563
|
+
// If path changed, restore original delegate before reconfiguring
|
|
564
|
+
if ([changedProps containsObject:@"path"] && _internalScrollView && _originalScrollDelegate) {
|
|
565
|
+
_internalScrollView.delegate = _originalScrollDelegate;
|
|
566
|
+
_internalScrollView = nil;
|
|
567
|
+
_originalScrollDelegate = nil;
|
|
562
568
|
}
|
|
569
|
+
|
|
570
|
+
// Use dispatch_async to ensure view hierarchy is fully set up after document load
|
|
571
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
572
|
+
// Search within _pdfView's hierarchy for scroll views
|
|
573
|
+
[self configureScrollView:self->_pdfView enabled:self->_scrollEnabled depth:0];
|
|
574
|
+
});
|
|
563
575
|
}
|
|
564
576
|
|
|
565
577
|
if (_pdfDocument && ([changedProps containsObject:@"path"] || [changedProps containsObject:@"enablePaging"] || [changedProps containsObject:@"horizontal"] || [changedProps containsObject:@"page"])) {
|
|
@@ -796,7 +808,7 @@ using namespace facebook::react;
|
|
|
796
808
|
* Tap
|
|
797
809
|
* zoom reset or zoom in
|
|
798
810
|
*
|
|
799
|
-
* @param recognizer
|
|
811
|
+
* @param recognizer The tap gesture recognizer
|
|
800
812
|
*/
|
|
801
813
|
- (void)handleDoubleTap:(UITapGestureRecognizer *)recognizer
|
|
802
814
|
{
|
|
@@ -869,7 +881,7 @@ using namespace facebook::react;
|
|
|
869
881
|
* Single Tap
|
|
870
882
|
* stop zoom
|
|
871
883
|
*
|
|
872
|
-
* @param recognizer
|
|
884
|
+
* @param sender The tap gesture recognizer
|
|
873
885
|
*/
|
|
874
886
|
- (void)handleSingleTap:(UITapGestureRecognizer *)sender
|
|
875
887
|
{
|
|
@@ -893,7 +905,7 @@ using namespace facebook::react;
|
|
|
893
905
|
* Pinch
|
|
894
906
|
*
|
|
895
907
|
*
|
|
896
|
-
* @param recognizer
|
|
908
|
+
* @param sender The pinch gesture recognizer
|
|
897
909
|
*/
|
|
898
910
|
-(void)handlePinch:(UIPinchGestureRecognizer *)sender{
|
|
899
911
|
[self onScaleChanged:Nil];
|
|
@@ -990,6 +1002,83 @@ using namespace facebook::react;
|
|
|
990
1002
|
}
|
|
991
1003
|
}
|
|
992
1004
|
|
|
1005
|
+
- (void)configureScrollView:(UIView *)view enabled:(BOOL)enabled depth:(int)depth {
|
|
1006
|
+
// max depth, prevent infinite loop
|
|
1007
|
+
if (depth > 10) {
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
if ([view isKindOfClass:[UIScrollView class]]) {
|
|
1012
|
+
UIScrollView *scrollView = (UIScrollView *)view;
|
|
1013
|
+
// Since we're starting the recursion from _pdfView, all scroll views found are within its hierarchy
|
|
1014
|
+
// Configure scroll properties
|
|
1015
|
+
scrollView.scrollEnabled = enabled;
|
|
1016
|
+
|
|
1017
|
+
// Disable horizontal bouncing to prevent interference with navigation swipe-back
|
|
1018
|
+
scrollView.alwaysBounceHorizontal = NO;
|
|
1019
|
+
// Keep vertical bounce enabled for natural scrolling feel
|
|
1020
|
+
scrollView.bounces = YES;
|
|
1021
|
+
|
|
1022
|
+
// Set delegate for scroll tracking (only once to avoid conflicts)
|
|
1023
|
+
// Store original delegate before replacing it to preserve PDFView's internal scrolling
|
|
1024
|
+
if (!_internalScrollView) {
|
|
1025
|
+
_internalScrollView = scrollView;
|
|
1026
|
+
// Store original delegate if it exists and is not us
|
|
1027
|
+
if (scrollView.delegate && scrollView.delegate != self) {
|
|
1028
|
+
_originalScrollDelegate = scrollView.delegate;
|
|
1029
|
+
}
|
|
1030
|
+
scrollView.delegate = self;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
for (UIView *subview in view.subviews) {
|
|
1035
|
+
[self configureScrollView:subview enabled:enabled depth:depth + 1];
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
#pragma mark - UIScrollViewDelegate
|
|
1040
|
+
|
|
1041
|
+
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
|
1042
|
+
// Forward to original delegate first if it exists (important for PDFView's scrolling)
|
|
1043
|
+
if (_originalScrollDelegate && [_originalScrollDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
|
|
1044
|
+
[_originalScrollDelegate scrollViewDidScroll:scrollView];
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
if (!_pdfDocument || _singlePage) {
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// Calculate visible page based on scroll position
|
|
1052
|
+
// Use the center point of the visible viewport
|
|
1053
|
+
CGPoint centerPoint = CGPointMake(
|
|
1054
|
+
scrollView.contentOffset.x + scrollView.bounds.size.width / 2,
|
|
1055
|
+
scrollView.contentOffset.y + scrollView.bounds.size.height / 2
|
|
1056
|
+
);
|
|
1057
|
+
|
|
1058
|
+
// Convert to PDFView coordinates
|
|
1059
|
+
CGPoint pdfPoint = [scrollView convertPoint:centerPoint toView:_pdfView];
|
|
1060
|
+
PDFPage *visiblePage = [_pdfView pageForPoint:pdfPoint nearest:YES];
|
|
1061
|
+
|
|
1062
|
+
if (visiblePage) {
|
|
1063
|
+
unsigned long pageIndex = [_pdfDocument indexForPage:visiblePage];
|
|
1064
|
+
int newPage = (int)pageIndex + 1;
|
|
1065
|
+
|
|
1066
|
+
// Only update if page actually changed and is valid
|
|
1067
|
+
if (newPage != _page && newPage > 0 && newPage <= (int)_pdfDocument.pageCount) {
|
|
1068
|
+
_page = newPage;
|
|
1069
|
+
_pageCount = (int)_pdfDocument.pageCount;
|
|
1070
|
+
|
|
1071
|
+
// Trigger preloading if enabled
|
|
1072
|
+
if (_enablePreloading) {
|
|
1073
|
+
[self preloadAdjacentPages:_page];
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// Notify about page change
|
|
1077
|
+
[self notifyOnChangeWithMessage:[[NSString alloc] initWithString:[NSString stringWithFormat:@"pageChanged|%d|%lu", newPage, _pdfDocument.pageCount]]];
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
993
1082
|
// Enhanced progressive loading methods
|
|
994
1083
|
- (void)preloadAdjacentPages:(int)currentPage
|
|
995
1084
|
{
|
|
@@ -1069,9 +1158,6 @@ using namespace facebook::react;
|
|
|
1069
1158
|
for (int pageIndex = 0; pageIndex < _pdfDocument.pageCount; pageIndex++) {
|
|
1070
1159
|
PDFPage *page = [_pdfDocument pageAtIndex:pageIndex];
|
|
1071
1160
|
|
|
1072
|
-
// Get the page bounds
|
|
1073
|
-
CGRect pageBounds = [page boundsForBox:kPDFDisplayBoxCropBox];
|
|
1074
|
-
|
|
1075
1161
|
// Search for text in the page
|
|
1076
1162
|
PDFSelection *selection = [page selectionForRange:NSMakeRange(0, page.string.length)];
|
|
1077
1163
|
if (selection && selection.string.length > 0) {
|
|
@@ -1105,9 +1191,33 @@ using namespace facebook::react;
|
|
|
1105
1191
|
@end
|
|
1106
1192
|
|
|
1107
1193
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
1194
|
+
|
|
1195
|
+
#ifdef __cplusplus
|
|
1196
|
+
extern "C" {
|
|
1197
|
+
#endif
|
|
1198
|
+
|
|
1108
1199
|
Class<RCTComponentViewProtocol> RNPDFPdfViewCls(void)
|
|
1109
1200
|
{
|
|
1110
|
-
|
|
1201
|
+
// Defensive check: Ensure class is loaded and valid before returning
|
|
1202
|
+
// This prevents nil object insertion in RCTThirdPartyComponentsProvider
|
|
1203
|
+
Class cls = RNPDFPdfView.class;
|
|
1204
|
+
if (cls == nil) {
|
|
1205
|
+
RCTLogError(@"RNPDFPdfView: Class is nil in RNPDFPdfViewCls");
|
|
1206
|
+
// Return a fallback to prevent crash, though this shouldn't happen
|
|
1207
|
+
return [RCTViewComponentView class];
|
|
1208
|
+
}
|
|
1209
|
+
return cls;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// Alias function based on codegen name "rnpdf" - ensures codegen can find the function
|
|
1213
|
+
// even if it uses the codegen name instead of componentProvider name
|
|
1214
|
+
Class<RCTComponentViewProtocol> rnpdfCls(void)
|
|
1215
|
+
{
|
|
1216
|
+
return RNPDFPdfViewCls();
|
|
1111
1217
|
}
|
|
1112
1218
|
|
|
1219
|
+
#ifdef __cplusplus
|
|
1220
|
+
}
|
|
1221
|
+
#endif
|
|
1222
|
+
|
|
1113
1223
|
#endif
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-pdf-jsi",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.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",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"crypto-js": "4.2.0",
|
|
67
67
|
"deprecated-react-native-prop-types": "^2.3.0",
|
|
68
|
-
"react-native-pdf-jsi": "^2.2.
|
|
68
|
+
"react-native-pdf-jsi": "^2.2.4"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@babel/core": "^7.20.2",
|
|
@@ -106,7 +106,9 @@
|
|
|
106
106
|
"javaPackageName": "org.wonday.pdf"
|
|
107
107
|
},
|
|
108
108
|
"ios": {
|
|
109
|
-
"componentProvider":
|
|
109
|
+
"componentProvider": {
|
|
110
|
+
"RNPDFPdfView": "RNPDFPdfView"
|
|
111
|
+
}
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
}
|