@@ -32,6 +32,7 @@ @implementation CodePush {
3232 long long _latestExpectedContentLength;
3333 long long _latestReceivedConentLength;
3434 BOOL _didUpdateProgress;
35+ NSTimeInterval _lastProgressEventTime;
3536
3637 BOOL _allowed;
3738 BOOL _restartInProgress;
@@ -336,6 +337,18 @@ - (void)dispatchDownloadProgressEvent {
336337 }];
337338}
338339
340+ - (void )dispatchThrottledDownloadProgressEventWithForce : (BOOL )force
341+ {
342+ static const NSTimeInterval interval = 0.05 ; // 50 ms throttle
343+ NSTimeInterval now = CFAbsoluteTimeGetCurrent ();
344+ if (!force && _lastProgressEventTime > 0 && (now - _lastProgressEventTime) < interval) {
345+ return ;
346+ }
347+
348+ _lastProgressEventTime = now;
349+ [self dispatchDownloadProgressEvent ];
350+ }
351+
339352/*
340353 * This method ensures that the app was packaged with a JS bundle
341354 * file, and if not, it throws the appropriate exception.
@@ -377,6 +390,7 @@ - (instancetype)init
377390 _allowed = YES ;
378391 _restartInProgress = NO ;
379392 _restartQueue = [NSMutableArray arrayWithCapacity: 1 ];
393+ _lastProgressEventTime = 0 ;
380394
381395 self = [super init ];
382396 if (self) {
@@ -723,6 +737,7 @@ -(void)loadBundleOnTick:(NSTimer *)timer {
723737 // progress events every frame if the progress is updated.
724738 _didUpdateProgress = NO ;
725739 self.paused = NO ;
740+ _lastProgressEventTime = 0 ;
726741 }
727742
728743 NSString * publicKey = [[CodePushConfig current ] publicKey ];
@@ -738,13 +753,19 @@ -(void)loadBundleOnTick:(NSTimer *)timer {
738753 _latestExpectedContentLength = expectedContentLength;
739754 _latestReceivedConentLength = receivedContentLength;
740755 _didUpdateProgress = YES ;
756+ // Fabric/TurboModules don't hook RCTFrameUpdateObserver, so _pauseCallback
757+ // stays nil there and we must emit progress events directly.
758+ // On the legacy bridge _pauseCallback is set, and didUpdateFrame handles dispatch.
759+ if (!_pauseCallback) {
760+ [self dispatchThrottledDownloadProgressEventWithForce: NO ];
761+ }
741762
742763 // If the download is completed, stop observing frame
743764 // updates and synchronously send the last event.
744765 if (expectedContentLength == receivedContentLength) {
745766 _didUpdateProgress = NO ;
746767 self.paused = YES ;
747- [self dispatchDownloadProgressEvent ];
768+ [self dispatchThrottledDownloadProgressEventWithForce: YES ];
748769 }
749770 }
750771 // The download completed
@@ -1115,7 +1136,7 @@ - (void)didUpdateFrame:(RCTFrameUpdate *)update
11151136 return ;
11161137 }
11171138
1118- [self dispatchDownloadProgressEvent ];
1139+ [self dispatchThrottledDownloadProgressEventWithForce: YES ];
11191140 _didUpdateProgress = NO ;
11201141}
11211142
0 commit comments