Skip to content

Commit dd056d9

Browse files
vzaidmanmeta-codesync[bot]
authored andcommitted
introduce isPackagerRunningAsync (#56004)
Summary: Pull Request resolved: #56004 Changelog: [iOS][Added] Introduce "isPackagerRunningAsync" that does not block the ui thread waiting on the request to DevServer ("Packager") validating that it is running The previous behavior was getting the UI blocked when the network conditions meant that a request was taking some time to result in success / fail / timeout. Reviewed By: huntie Differential Revision: D94430009 fbshipit-source-id: 6292ce74c027af7c217153620a03b417f30dff49
1 parent c336bfa commit dd056d9

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

packages/react-native/React/Base/RCTBundleURLProvider.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,23 @@ NS_ASSUME_NONNULL_BEGIN
5757
*/
5858
+ (BOOL)isPackagerRunning:(NSString *)hostPort scheme:(NSString *__nullable)scheme;
5959

60+
/**
61+
* Asynchronously checks if there's a packager running at the given host:port.
62+
* The port is optional, if not specified, kRCTBundleURLProviderDefaultPort will be used
63+
* The completion handler is called on an arbitrary queue.
64+
*/
65+
+ (void)isPackagerRunningAsync:(NSString *)hostPort completion:(void (^)(BOOL isRunning))completion;
66+
67+
/**
68+
* Asynchronously checks if there's a packager running at the given scheme://host:port.
69+
* The port is optional, if not specified, kRCTBundleURLProviderDefaultPort will be used
70+
* The scheme is also optional, if not specified, a default http protocol will be used
71+
* The completion handler is called on an arbitrary queue.
72+
*/
73+
+ (void)isPackagerRunningAsync:(NSString *)hostPort
74+
scheme:(NSString *__nullable)scheme
75+
completion:(void (^)(BOOL isRunning))completion;
76+
6077
/**
6178
* Returns the jsBundleURL for a given bundle entrypoint and
6279
* the fallback offline JS bundle if the packager is not running.

packages/react-native/React/Base/RCTBundleURLProvider.mm

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ + (BOOL)isPackagerRunning:(NSString *)hostPort scheme:(NSString *)scheme
9494
}
9595

9696
NSURL *url = [serverRootWithHostPort(hostPort, scheme) URLByAppendingPathComponent:@"status"];
97+
if (url == nil) {
98+
return NO;
99+
}
97100

98101
NSURLSession *session = [NSURLSession sharedSession];
99102
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
@@ -133,6 +136,73 @@ + (BOOL)isPackagerRunning:(NSString *)hostPort scheme:(NSString *)scheme
133136
return isRunning;
134137
}
135138

139+
+ (void)isPackagerRunningAsync:(NSString *)hostPort completion:(void (^)(BOOL isRunning))completion
140+
{
141+
[RCTBundleURLProvider isPackagerRunningAsync:hostPort scheme:nil completion:completion];
142+
}
143+
144+
+ (void)isPackagerRunningAsync:(NSString *)hostPort
145+
scheme:(NSString *)scheme
146+
completion:(void (^)(BOOL isRunning))completion
147+
{
148+
if (!kRCTAllowPackagerAccess) {
149+
completion(NO);
150+
return;
151+
}
152+
153+
NSURL *url = [serverRootWithHostPort(hostPort, scheme) URLByAppendingPathComponent:@"status"];
154+
if (url == nil) {
155+
completion(NO);
156+
return;
157+
}
158+
159+
NSURLSession *session = [NSURLSession sharedSession];
160+
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
161+
cachePolicy:NSURLRequestUseProtocolCachePolicy
162+
timeoutInterval:kRCTPackagerStatusRequestTimeout];
163+
[[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:request];
164+
165+
__block BOOL hasCompleted = NO;
166+
NSObject *lock = [[NSObject alloc] init];
167+
168+
void (^safeCompletion)(BOOL) = ^(BOOL isRunning) {
169+
@synchronized(lock) {
170+
if (!hasCompleted) {
171+
hasCompleted = YES;
172+
completion(isRunning);
173+
}
174+
}
175+
};
176+
177+
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
178+
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
179+
if (error != nil || data == nil) {
180+
safeCompletion(NO);
181+
return;
182+
}
183+
NSString *status = [[NSString alloc] initWithData:data
184+
encoding:NSUTF8StringEncoding];
185+
BOOL isRunning = [status isEqualToString:@"packager-status:running"];
186+
safeCompletion(isRunning);
187+
}];
188+
[task resume];
189+
190+
dispatch_after(
191+
dispatch_time(
192+
DISPATCH_TIME_NOW,
193+
(int64_t)((kRCTPackagerStatusRequestTimeout + kRCTPackagerStatusRequestTimeoutGraceTime) * NSEC_PER_SEC)),
194+
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
195+
^{
196+
@synchronized(lock) {
197+
if (!hasCompleted) {
198+
hasCompleted = YES;
199+
[task cancel];
200+
completion(NO);
201+
}
202+
}
203+
});
204+
}
205+
136206
- (NSString *)guessPackagerHost
137207
{
138208
static NSString *ipGuess;
@@ -160,6 +230,18 @@ + (BOOL)isPackagerRunning:(NSString *)hostPort scheme:(NSString *)scheme
160230
{
161231
return false;
162232
}
233+
234+
+ (void)isPackagerRunningAsync:(NSString *)hostPort completion:(void (^)(BOOL isRunning))completion
235+
{
236+
completion(NO);
237+
}
238+
239+
+ (void)isPackagerRunningAsync:(NSString *)hostPort
240+
scheme:(NSString *)scheme
241+
completion:(void (^)(BOOL isRunning))completion
242+
{
243+
completion(NO);
244+
}
163245
#endif
164246

165247
- (NSString *)packagerServerHost

0 commit comments

Comments
 (0)