mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Implement HostTargetDelegate.networkRequest on iOS (#44846)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44846 Implement the `networkRequest` method of `jsinspector_modern::HostTargetDelegate` for iOS (bridge and bridgeless) to satisfy CDP `Network.loadNetworkResource` (etc) requests. Changelog: [iOS][Added] Debugger: Implement CDP methods for loading network resources through the debug target. Differential Revision: D54496969 fbshipit-source-id: fdaf445dda69b621617decdba49ba89c42043a92
This commit is contained in:
committed by
Facebook GitHub Bot
parent
62231ea883
commit
c720583f6c
@@ -20,6 +20,7 @@
|
||||
#import <jsinspector-modern/ReactCdp.h>
|
||||
#import <optional>
|
||||
#import "RCTDevLoadingViewProtocol.h"
|
||||
#import "RCTInspectorNetworkHelper.h"
|
||||
#import "RCTInspectorUtils.h"
|
||||
#import "RCTJSThread.h"
|
||||
#import "RCTLog.h"
|
||||
@@ -182,7 +183,9 @@ void RCTUIManagerSetDispatchAccessibilityManagerInitOntoMain(BOOL enabled)
|
||||
class RCTBridgeHostTargetDelegate : public facebook::react::jsinspector_modern::HostTargetDelegate {
|
||||
public:
|
||||
RCTBridgeHostTargetDelegate(RCTBridge *bridge)
|
||||
: bridge_(bridge), pauseOverlayController_([[RCTPausedInDebuggerOverlayController alloc] init])
|
||||
: bridge_(bridge),
|
||||
pauseOverlayController_([[RCTPausedInDebuggerOverlayController alloc] init]),
|
||||
networkHelper_([[RCTInspectorNetworkHelper alloc] init])
|
||||
{
|
||||
}
|
||||
|
||||
@@ -229,9 +232,16 @@ class RCTBridgeHostTargetDelegate : public facebook::react::jsinspector_modern::
|
||||
}
|
||||
}
|
||||
|
||||
void loadNetworkResource(const RCTInspectorLoadNetworkResourceRequest ¶ms, RCTInspectorNetworkExecutor executor)
|
||||
override
|
||||
{
|
||||
[networkHelper_ loadNetworkResourceWithParams:params executor:executor];
|
||||
}
|
||||
|
||||
private:
|
||||
__weak RCTBridge *bridge_;
|
||||
RCTPausedInDebuggerOverlayController *pauseOverlayController_;
|
||||
RCTInspectorNetworkHelper *networkHelper_;
|
||||
};
|
||||
|
||||
@interface RCTBridge () <RCTReloadListener>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <jsinspector-modern/ReactCdp.h>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef facebook::react::jsinspector_modern::NetworkRequestListener RCTInspectorNetworkListener;
|
||||
|
||||
typedef facebook::react::jsinspector_modern::ScopedExecutor<RCTInspectorNetworkListener> RCTInspectorNetworkExecutor;
|
||||
|
||||
typedef facebook::react::jsinspector_modern::LoadNetworkResourceRequest RCTInspectorLoadNetworkResourceRequest;
|
||||
|
||||
/**
|
||||
* A helper class that wraps around NSURLSession to make network requests.
|
||||
*/
|
||||
@interface RCTInspectorNetworkHelper : NSObject
|
||||
- (instancetype)init;
|
||||
- (void)loadNetworkResourceWithParams:(const RCTInspectorLoadNetworkResourceRequest &)params
|
||||
executor:(RCTInspectorNetworkExecutor)executor;
|
||||
@end
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTInspectorNetworkHelper.h"
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
typedef void (^ListenerBlock)(RCTInspectorNetworkListener *);
|
||||
|
||||
@interface RCTInspectorNetworkHelper () <NSURLSessionDataDelegate>
|
||||
@property (nonatomic, strong) NSURLSession *session;
|
||||
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, void (^)(ListenerBlock)> *executorsByTaskId;
|
||||
- (void)withListenerForTask:(NSURLSessionTask *)task execute:(ListenerBlock)block;
|
||||
@end
|
||||
|
||||
@implementation RCTInspectorNetworkHelper
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
|
||||
self.executorsByTaskId = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadNetworkResourceWithParams:(const RCTInspectorLoadNetworkResourceRequest &)params
|
||||
executor:(RCTInspectorNetworkExecutor)executor
|
||||
{
|
||||
NSString *urlString = [NSString stringWithCString:params.url.c_str() encoding:NSUTF8StringEncoding];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
auto executorBlock = ^(ListenerBlock func) {
|
||||
executor([=](RCTInspectorNetworkListener &listener) { func(&listener); });
|
||||
};
|
||||
|
||||
if (url == nil) {
|
||||
executorBlock(^(RCTInspectorNetworkListener *listener) {
|
||||
listener->onError([NSString stringWithFormat:@"Not a valid URL: %@", urlString].UTF8String);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
|
||||
[urlRequest setHTTPMethod:@"GET"];
|
||||
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:urlRequest];
|
||||
__weak NSURLSessionDataTask *weakDataTask = dataTask;
|
||||
|
||||
executorBlock(^(RCTInspectorNetworkListener *listener) {
|
||||
listener->setCancelFunction([weakDataTask]() { [weakDataTask cancel]; });
|
||||
});
|
||||
|
||||
// Store the executor as a block per task.
|
||||
self.executorsByTaskId[@(dataTask.taskIdentifier)] = executorBlock;
|
||||
|
||||
[dataTask resume];
|
||||
}
|
||||
|
||||
- (void)withListenerForTask:(NSURLSessionTask *)task execute:(ListenerBlock)block
|
||||
{
|
||||
void (^executor)(ListenerBlock) = self.executorsByTaskId[@(task.taskIdentifier)];
|
||||
if (executor) {
|
||||
executor(block);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSessionDataDelegate
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveResponse:(NSURLResponse *)response
|
||||
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
|
||||
{
|
||||
auto callbackWithHeadersOrError = (^(RCTInspectorNetworkListener *listener) {
|
||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
std::map<std::string, std::string> headersMap;
|
||||
for (NSString *key in httpResponse.allHeaderFields) {
|
||||
headersMap[[key UTF8String]] = [[httpResponse.allHeaderFields objectForKey:key] UTF8String];
|
||||
}
|
||||
completionHandler(NSURLSessionResponseAllow);
|
||||
listener->onHeaders(httpResponse.statusCode, headersMap);
|
||||
} else {
|
||||
listener->onError("Unsupported response type");
|
||||
completionHandler(NSURLSessionResponseCancel);
|
||||
}
|
||||
});
|
||||
[self withListenerForTask:dataTask execute:callbackWithHeadersOrError];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
|
||||
{
|
||||
auto callbackWithData = ^(RCTInspectorNetworkListener *listener) {
|
||||
listener->onData(std::string_view(static_cast<const char *>(data.bytes), data.length));
|
||||
};
|
||||
[self withListenerForTask:dataTask execute:callbackWithData];
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
|
||||
{
|
||||
auto callbackWithCompletionOrError = ^(RCTInspectorNetworkListener *listener) {
|
||||
if (error != nil) {
|
||||
listener->onError(error.localizedDescription.UTF8String);
|
||||
} else {
|
||||
listener->onCompletion();
|
||||
}
|
||||
};
|
||||
[self withListenerForTask:task execute:callbackWithCompletionOrError];
|
||||
}
|
||||
|
||||
@end
|
||||
+11
-1
@@ -13,6 +13,7 @@
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTFabricSurface.h>
|
||||
#import <React/RCTInspectorDevServerHelper.h>
|
||||
#import <React/RCTInspectorNetworkHelper.h>
|
||||
#import <React/RCTInspectorUtils.h>
|
||||
#import <React/RCTJSThread.h>
|
||||
#import <React/RCTLog.h>
|
||||
@@ -37,7 +38,9 @@ using namespace facebook::react;
|
||||
class RCTHostHostTargetDelegate : public facebook::react::jsinspector_modern::HostTargetDelegate {
|
||||
public:
|
||||
RCTHostHostTargetDelegate(RCTHost *host)
|
||||
: host_(host), pauseOverlayController_([[RCTPausedInDebuggerOverlayController alloc] init])
|
||||
: host_(host),
|
||||
pauseOverlayController_([[RCTPausedInDebuggerOverlayController alloc] init]),
|
||||
networkHelper_([[RCTInspectorNetworkHelper alloc] init])
|
||||
{
|
||||
}
|
||||
|
||||
@@ -84,9 +87,16 @@ class RCTHostHostTargetDelegate : public facebook::react::jsinspector_modern::Ho
|
||||
}
|
||||
}
|
||||
|
||||
void loadNetworkResource(const RCTInspectorLoadNetworkResourceRequest ¶ms, RCTInspectorNetworkExecutor executor)
|
||||
override
|
||||
{
|
||||
[networkHelper_ loadNetworkResourceWithParams:params executor:executor];
|
||||
}
|
||||
|
||||
private:
|
||||
__weak RCTHost *host_;
|
||||
RCTPausedInDebuggerOverlayController *pauseOverlayController_;
|
||||
RCTInspectorNetworkHelper *networkHelper_;
|
||||
};
|
||||
|
||||
@implementation RCTHost {
|
||||
|
||||
Reference in New Issue
Block a user