diff --git a/packages/react-native/Libraries/Blob/RCTBlobManager.mm b/packages/react-native/Libraries/Blob/RCTBlobManager.mm index 82c0897890417d..286710d69105cf 100755 --- a/packages/react-native/Libraries/Blob/RCTBlobManager.mm +++ b/packages/react-native/Libraries/Blob/RCTBlobManager.mm @@ -159,11 +159,11 @@ - (void)remove:(NSString *)blobId // TODO(T63516227): Why can methodQueue be nil here? // We don't want to do anything when methodQueue is nil. - if (!networking.methodQueue) { + if (![networking requestQueue]) { return; } - dispatch_async(networking.methodQueue, ^{ + dispatch_async([networking requestQueue], ^{ [networking addRequestHandler:self]; [networking addResponseHandler:self]; }); diff --git a/packages/react-native/Libraries/Network/RCTHTTPRequestHandler.mm b/packages/react-native/Libraries/Network/RCTHTTPRequestHandler.mm index 8f21bf3e284682..4a0353396d7eda 100644 --- a/packages/react-native/Libraries/Network/RCTHTTPRequestHandler.mm +++ b/packages/react-native/Libraries/Network/RCTHTTPRequestHandler.mm @@ -78,7 +78,8 @@ - (NSURLSessionDataTask *)sendRequest:(NSURLRequest *)request withDelegate:(id #import +RCT_EXTERN void RCTEnableNetworkingRequestQueue(BOOL enabled); + @protocol RCTNetworkingRequestHandler // @lint-ignore FBOBJCUNTYPEDCOLLECTION1 @@ -54,6 +56,8 @@ - (void)removeResponseHandler:(id)handler; +- (dispatch_queue_t)requestQueue; + @end @interface RCTBridge (RCTNetworking) diff --git a/packages/react-native/Libraries/Network/RCTNetworking.mm b/packages/react-native/Libraries/Network/RCTNetworking.mm index 7abc90d75c2ead..734bf33034384d 100644 --- a/packages/react-native/Libraries/Network/RCTNetworking.mm +++ b/packages/react-native/Libraries/Network/RCTNetworking.mm @@ -19,6 +19,13 @@ #import "RCTNetworkPlugins.h" +static BOOL gEnableNetworkingRequestQueue = NO; + +RCT_EXTERN void RCTEnableNetworkingRequestQueue(BOOL enabled) +{ + gEnableNetworkingRequestQueue = enabled; +} + typedef RCTURLRequestCancellationBlock (^RCTHTTPQueryResult)(NSError *error, NSDictionary *result); NSString *const RCTNetworkingPHUploadHackScheme = @"ph-upload"; @@ -151,6 +158,7 @@ @implementation RCTNetworking { NSArray> * (^_handlersProvider)(RCTModuleRegistry *); NSMutableArray> *_requestHandlers; NSMutableArray> *_responseHandlers; + dispatch_queue_t _requestQueue; } @synthesize methodQueue = _methodQueue; @@ -162,15 +170,13 @@ + (BOOL)requiresMainQueueSetup return YES; } -- (instancetype)init -{ - return [super initWithDisabledObservation]; -} - - (instancetype)initWithHandlersProvider: (NSArray> * (^)(RCTModuleRegistry *moduleRegistry))getHandlers { if (self = [super initWithDisabledObservation]) { + if (gEnableNetworkingRequestQueue) { + _requestQueue = dispatch_queue_create("com.facebook.react.network.request", DISPATCH_QUEUE_SERIAL); + } _handlersProvider = getHandlers; } return self; @@ -294,7 +300,7 @@ - (void)invalidate - (RCTURLRequestCancellationBlock)buildRequest:(NSDictionary *)query completionBlock:(void (^)(NSURLRequest *request))block { - RCTAssertThread(_methodQueue, @"buildRequest: must be called on method queue"); + RCTAssertThread([self requestQueue], @"buildRequest: must be called on method queue"); NSURL *URL = [RCTConvert NSURL:query[@"url"]]; // this is marked as nullable in JS, but should not be null NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; @@ -347,7 +353,7 @@ - (RCTURLRequestCancellationBlock)buildRequest:(NSDictionary *)q forHTTPHeaderField:@"Content-Length"]; } - dispatch_async(self->_methodQueue, ^{ + dispatch_async([self requestQueue], ^{ block(request); }); @@ -385,7 +391,7 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request callback:(RCTURLRequestCancellationBlock (^)(NSError *error, NSDictionary *result)) callback { - RCTAssertThread(_methodQueue, @"processDataForHTTPQuery: must be called on method queue"); + RCTAssertThread([self requestQueue], @"processDataForHTTPQuery: must be called on method queue"); if (!query) { return callback(nil, nil); @@ -414,7 +420,7 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request RCTNetworkTask *task = [self networkTaskWithRequest:request completionBlock:^(NSURLResponse *response, NSData *data, NSError *error) { - dispatch_async(self->_methodQueue, ^{ + dispatch_async([self requestQueue], ^{ cancellationBlock = callback( error, data ? @{@"body" : data, @"contentType" : RCTNullIfNil(response.MIMEType)} : nil); }); @@ -514,7 +520,7 @@ - (void)sendData:(NSData *)data response:(NSURLResponse *)response forTask:(RCTNetworkTask *)task { - RCTAssertThread(_methodQueue, @"sendData: must be called on method queue"); + RCTAssertThread([self requestQueue], @"sendData: must be called on method queue"); id responseData = nil; for (id handler in _responseHandlers) { @@ -552,7 +558,7 @@ - (void)sendRequest:(NSURLRequest *)request incrementalUpdates:(BOOL)incrementalUpdates responseSender:(RCTResponseSenderBlock)responseSender { - RCTAssertThread(_methodQueue, @"sendRequest: must be called on method queue"); + RCTAssertThread([self requestQueue], @"sendRequest: must be called on method queue"); __weak __typeof(self) weakSelf = self; __block RCTNetworkTask *task; RCTURLRequestProgressBlock uploadProgressBlock = ^(int64_t progress, int64_t total) { @@ -689,7 +695,9 @@ - (RCTNetworkTask *)networkTaskWithRequest:(NSURLRequest *)request return nil; } - RCTNetworkTask *task = [[RCTNetworkTask alloc] initWithRequest:request handler:handler callbackQueue:_methodQueue]; + RCTNetworkTask *task = [[RCTNetworkTask alloc] initWithRequest:request + handler:handler + callbackQueue:[self requestQueue]]; task.completionBlock = completionBlock; return task; } @@ -709,7 +717,7 @@ - (RCTNetworkTask *)networkTaskWithRequest:(NSURLRequest *)request double timeout = query.timeout(); bool withCredentials = query.withCredentials(); - dispatch_async(_methodQueue, ^{ + dispatch_async([self requestQueue], ^{ NSDictionary *queryDict = @{ @"method" : method, @"url" : url, @@ -738,7 +746,7 @@ - (RCTNetworkTask *)networkTaskWithRequest:(NSURLRequest *)request RCT_EXPORT_METHOD(abortRequest : (double)requestID) { - dispatch_async(_methodQueue, ^{ + dispatch_async([self requestQueue], ^{ [self->_tasksByRequestID[[NSNumber numberWithDouble:requestID]] cancel]; [self->_tasksByRequestID removeObjectForKey:[NSNumber numberWithDouble:requestID]]; }); @@ -746,7 +754,7 @@ - (RCTNetworkTask *)networkTaskWithRequest:(NSURLRequest *)request RCT_EXPORT_METHOD(clearCookies : (RCTResponseSenderBlock)responseSender) { - dispatch_async(_methodQueue, ^{ + dispatch_async([self requestQueue], ^{ NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; if (!storage.cookies.count) { responseSender(@[ @NO ]); @@ -760,6 +768,11 @@ - (RCTNetworkTask *)networkTaskWithRequest:(NSURLRequest *)request }); } +- (dispatch_queue_t)requestQueue +{ + return gEnableNetworkingRequestQueue ? _requestQueue : _methodQueue; +} + - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params {