From 72abed2c96d65769567e2b7e492764c1a58e6e81 Mon Sep 17 00:00:00 2001 From: Matt Oakes Date: Wed, 12 Jul 2023 04:27:06 -0700 Subject: [PATCH] Fix window.requestIdleCallback not firing on iOS (#29895) Summary: Fixes https://github.com/facebook/react-native/issues/28602 When creating a `RCTFrameUpdate`, ensure it is created with the correct unix timestamp in seconds. This is needed to match the `NSTimeInterval` type defined in the header. Previously, it was using the `CADisplayLink`'s `timestamp` property, which is not an `NSTimeInterval` but is instead a `CFTimeInterval` (note the different class prefix). This is the host time converted to seconds, which is the number of seconds since the device was turned on and therefore not a unix timestamp as expected. This was causing issues with the `window.requestIdleCallback` timers as the timer code was expecting this `timestamp` property to be a unix timestamp in seconds which was causing the calculations to be done incorrectly and for the callbacks to never be called. The code does this calculation is here: https://github.com/facebook/react-native/blob/4d920fe7c991eaec61d229a71df30b0f6c446d38/React/CoreModules/RCTTiming.mm#L262 As one of these is a valid unix timestamp and the other is a much smaller number (number of seconds since device turn on), the `if` statement following this calculation never passes and the callbacks are never called. This regression seems to have been introduced with this pull request: https://github.com/facebook/react-native/pull/26114 ## Changelog [iOS] [Fixed] - Fixed window.requestIdleCallback not firing on iOS Pull Request resolved: https://github.com/facebook/react-native/pull/29895 Test Plan: I have tested this by patching my React Native code and testing that idle callbacks are correctly called. There is a reproduction case of the issue in the linked issue. Reviewed By: NickGerleman Differential Revision: D47381404 Pulled By: sammy-SC fbshipit-source-id: fd166741889b0084e1def8dedf6e4018adfd570f --- packages/react-native/React/CoreModules/RCTTiming.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-native/React/CoreModules/RCTTiming.mm b/packages/react-native/React/CoreModules/RCTTiming.mm index 13d0d57296bbba..6065006b8eb281 100644 --- a/packages/react-native/React/CoreModules/RCTTiming.mm +++ b/packages/react-native/React/CoreModules/RCTTiming.mm @@ -256,9 +256,9 @@ - (void)didUpdateFrame:(RCTFrameUpdate *)update } if (_sendIdleEvents) { - NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; - NSTimeInterval frameElapsed = currentTimestamp - update.timestamp; + NSTimeInterval frameElapsed = (CACurrentMediaTime() - update.timestamp); if (kFrameDuration - frameElapsed >= kIdleCallbackFrameDeadline) { + NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; NSNumber *absoluteFrameStartMS = @((currentTimestamp - frameElapsed) * 1000); if (_bridge) { [_bridge enqueueJSCall:@"JSTimers" method:@"callIdleCallbacks" args:@[ absoluteFrameStartMS ] completion:NULL];