react-native-pdf-jsi 4.0.0 → 4.1.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.
@@ -144,7 +144,6 @@ public class PdfManager extends SimpleViewManager<PdfView> implements RNPDFPdfVi
144
144
  // NOOP on Android
145
145
  }
146
146
 
147
- @Override
148
147
  public void setEnableMomentum(PdfView view, boolean value) {
149
148
  // NOOP on Android - momentum scrolling is handled automatically by Android's ScrollView
150
149
  }
@@ -179,8 +178,9 @@ public class PdfManager extends SimpleViewManager<PdfView> implements RNPDFPdfVi
179
178
  @Override
180
179
  public void onAfterUpdateTransaction(PdfView pdfView) {
181
180
  super.onAfterUpdateTransaction(pdfView);
182
- // Removed pdfView.drawPdf() - PdfView now manages reload internally
183
- // to prevent unnecessary document recreation on scroll/prop updates
181
+ // Call drawPdf() to ensure PDF loads initially and when path changes
182
+ // The drawPdf() method internally checks if reload is needed to prevent unnecessary reloads
183
+ pdfView.drawPdf();
184
184
  }
185
185
 
186
186
  }
@@ -20,6 +20,8 @@ import android.net.Uri;
20
20
  import android.util.AttributeSet;
21
21
  import android.view.MotionEvent;
22
22
  import android.graphics.Canvas;
23
+ import android.os.Handler;
24
+ import android.os.Looper;
23
25
 
24
26
 
25
27
  import com.facebook.react.uimanager.ThemedReactContext;
@@ -85,6 +87,8 @@ public class PdfView extends PDFView implements OnPageChangeListener,OnLoadCompl
85
87
  private boolean needsReload = true;
86
88
  private String lastLoadedPath = null;
87
89
  private float lastPageHeight = 0;
90
+ private boolean loadCompleteDispatched = false;
91
+ private int lastKnownPageCount = 0;
88
92
 
89
93
  // used to store the parameters for `super.onSizeChanged`
90
94
  private int oldW = 0;
@@ -100,6 +104,17 @@ public class PdfView extends PDFView implements OnPageChangeListener,OnLoadCompl
100
104
  page = page+1;
101
105
  this.page = page;
102
106
  showLog(format("%s %s / %s", path, page, numberOfPages));
107
+
108
+ // Store page count when we get it (useful for loadComplete dispatch)
109
+ if (numberOfPages > 0 && lastKnownPageCount == 0) {
110
+ lastKnownPageCount = numberOfPages;
111
+ }
112
+
113
+ // Note: We don't dispatch loadComplete from onPageChanged anymore because:
114
+ // 1. The PDF library's onLoad callback should call loadComplete() directly
115
+ // 2. If it doesn't, we've already fixed it in loadComplete() with delayed dispatch
116
+ // 3. This prevents duplicate loadComplete events
117
+ // The delayed dispatch in loadComplete() ensures React component is ready
103
118
 
104
119
  WritableMap event = Arguments.createMap();
105
120
  event.putString("message", "pageChanged|"+page+"|"+numberOfPages);
@@ -145,27 +160,75 @@ public class PdfView extends PDFView implements OnPageChangeListener,OnLoadCompl
145
160
 
146
161
  @Override
147
162
  public void loadComplete(int numberOfPages) {
148
- SizeF pageSize = getPageSize(0);
149
- float width = pageSize.getWidth();
150
- float height = pageSize.getHeight();
163
+ // Prevent duplicate calls - if already dispatched, skip
164
+ if (loadCompleteDispatched) {
165
+ showLog("loadComplete: Already dispatched, skipping duplicate call");
166
+ return;
167
+ }
168
+ showLog("loadComplete called with " + numberOfPages + " pages, loadCompleteDispatched=" + loadCompleteDispatched);
169
+ // Store the page count for later use
170
+ lastKnownPageCount = numberOfPages;
171
+
172
+ float width = 0;
173
+ float height = 0;
174
+
175
+ try {
176
+ SizeF pageSize = getPageSize(0);
177
+ if (pageSize != null) {
178
+ width = pageSize.getWidth();
179
+ height = pageSize.getHeight();
180
+ }
181
+ } catch (Exception e) {
182
+ showLog("Error getting page size in loadComplete: " + e.getMessage());
183
+ // Continue with default values to ensure event is dispatched
184
+ }
151
185
 
152
- this.zoomTo(this.scale);
186
+ try {
187
+ this.zoomTo(this.scale);
188
+ } catch (Exception e) {
189
+ showLog("Error setting zoom in loadComplete: " + e.getMessage());
190
+ // Continue even if zoom fails
191
+ }
192
+
153
193
  WritableMap event = Arguments.createMap();
154
194
 
155
195
  //create a new json Object for the TableOfContents
156
196
  Gson gson = new Gson();
197
+ String tableOfContents = "";
198
+ try {
199
+ tableOfContents = gson.toJson(this.getTableOfContents());
200
+ } catch (Exception e) {
201
+ showLog("Error serializing table of contents: " + e.getMessage());
202
+ // Continue with empty table of contents
203
+ }
204
+
157
205
  // Include path in loadComplete message for reliable access in JS
158
206
  String pathValue = this.path != null ? this.path : "";
159
- event.putString("message", "loadComplete|"+numberOfPages+"|"+width+"|"+height+"|"+pathValue+"|"+gson.toJson(this.getTableOfContents()));
207
+ event.putString("message", "loadComplete|"+numberOfPages+"|"+width+"|"+height+"|"+pathValue+"|"+tableOfContents);
160
208
 
161
209
  ThemedReactContext context = (ThemedReactContext) getContext();
162
- EventDispatcher dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, getId());
210
+ final EventDispatcher dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, getId());
163
211
  int surfaceId = UIManagerHelper.getSurfaceId(this);
164
212
 
165
- TopChangeEvent tce = new TopChangeEvent(surfaceId, getId(), event);
213
+ final TopChangeEvent tce = new TopChangeEvent(surfaceId, getId(), event);
166
214
 
167
215
  if (dispatcher != null) {
168
- dispatcher.dispatchEvent(tce);
216
+ showLog("loadComplete: Dispatching event with message: " + event.getString("message"));
217
+ // Post to next frame to ensure React component is ready to receive events
218
+ // This fixes timing issues where event is dispatched before component is mounted
219
+ final PdfView self = this;
220
+ new Handler(Looper.getMainLooper()).post(new Runnable() {
221
+ @Override
222
+ public void run() {
223
+ if (dispatcher != null) {
224
+ dispatcher.dispatchEvent(tce);
225
+ self.loadCompleteDispatched = true;
226
+ showLog("loadComplete: Event dispatched successfully (delayed)");
227
+ }
228
+ }
229
+ });
230
+ } else {
231
+ showLog("EventDispatcher is null, cannot dispatch loadComplete event");
169
232
  }
170
233
  // ReactContext reactContext = (ReactContext)this.getContext();
171
234
  // reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
@@ -296,6 +359,11 @@ public class PdfView extends PDFView implements OnPageChangeListener,OnLoadCompl
296
359
  if (this.page > 0 && !this.isRecycled()) {
297
360
  this.jumpTo(this.page - 1, false);
298
361
  }
362
+ // If PDF is already loaded but loadComplete event hasn't been dispatched yet, dispatch it now
363
+ if (!loadCompleteDispatched && !this.isRecycled() && lastKnownPageCount > 0) {
364
+ showLog("drawPdf: PDF already loaded but loadComplete not dispatched, dispatching now with " + lastKnownPageCount + " pages");
365
+ loadComplete(lastKnownPageCount);
366
+ }
299
367
  return;
300
368
  }
301
369
  showLog(format("drawPdf path:%s %s", this.path, this.page));
@@ -367,6 +435,9 @@ public class PdfView extends PDFView implements OnPageChangeListener,OnLoadCompl
367
435
  // Path changed - need to reload document
368
436
  needsReload = true;
369
437
  this.path = path;
438
+ // Reset flags when path changes
439
+ loadCompleteDispatched = false;
440
+ lastKnownPageCount = 0;
370
441
  }
371
442
 
372
443
  // page start from 1
package/index.js CHANGED
@@ -547,9 +547,14 @@ export default class Pdf extends Component {
547
547
  _onChange = (event) => {
548
548
 
549
549
  let message = event.nativeEvent.message.split('|');
550
- //__DEV__ && console.log("onChange: " + message);
550
+ if (__DEV__) {
551
+ console.log("📥 [Pdf] onChange received:", message[0], "full message:", event.nativeEvent.message);
552
+ }
551
553
  if (message.length > 0) {
552
554
  if (message[0] === 'loadComplete') {
555
+ if (__DEV__) {
556
+ console.log("📥 [Pdf] Processing loadComplete event");
557
+ }
553
558
  let tableContents;
554
559
  let filePath;
555
560
 
@@ -670,9 +670,31 @@ using namespace facebook::react;
670
670
  PDFPage *page = [_pdfDocument pageAtIndex:_pdfDocument.pageCount-1];
671
671
  CGSize pageSize = [_pdfView rowSizeForPage:page];
672
672
  NSString *jsonString = [self getTableContents];
673
-
674
- [self notifyOnChangeWithMessage:
675
- [[NSString alloc] initWithString:[NSString stringWithFormat:@"loadComplete|%lu|%f|%f|%@", numberOfPages, pageSize.width, pageSize.height,jsonString]]];
673
+
674
+ // Include path in loadComplete message for consistency with Android and reliable path access in JS
675
+ // Format: loadComplete|numberOfPages|width|height|path|tableContents
676
+ NSString *pathValue = @"";
677
+ if (_path != nil && _path.length > 0) {
678
+ pathValue = _path;
679
+ } else if (_pdfDocument.documentURL != nil) {
680
+ // Fallback: try to get path from document URL
681
+ pathValue = _pdfDocument.documentURL.path;
682
+ }
683
+
684
+ // Debug logging to verify path is being included (using RCTLog so it shows in all builds)
685
+ RCTLogInfo(@"🔍 [iOS] loadComplete: numberOfPages=%lu, width=%f, height=%f, path='%@', pathLength=%lu",
686
+ numberOfPages, pageSize.width, pageSize.height, pathValue, (unsigned long)pathValue.length);
687
+
688
+ // Ensure path is always included in message (even if empty) for consistent parsing
689
+ // Format: loadComplete|numberOfPages|width|height|path|tableContents
690
+ // Use explicit format to ensure path segment is always present
691
+ NSString *message = [NSString stringWithFormat:@"loadComplete|%lu|%f|%f|%@|%@",
692
+ numberOfPages, pageSize.width, pageSize.height,
693
+ (pathValue != nil ? pathValue : @""), jsonString];
694
+
695
+ RCTLogInfo(@"🔍 [iOS] loadComplete message: %@", message);
696
+
697
+ [self notifyOnChangeWithMessage:message];
676
698
  }
677
699
 
678
700
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-pdf-jsi",
3
- "version": "4.0.0",
3
+ "version": "4.1.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",