Kill RCTWebViewExecutor

Summary: public

The WebView executor has no benefits compared to the JSC executor (slower, no extra debugging tools...),
and it's pretty hacky (since it injects the code in a script tag we have to check for tags in the comments and etc...).

Reviewed By: nicklockwood, javache

Differential Revision: D2636465

fb-gh-sync-id: 0d0f8a59e2c12fe7905b02060b3938c894d2802b
This commit is contained in:
Tadeu Zagallo
2015-11-10 05:24:54 -08:00
committed by facebook-github-bot-3
parent 2eb8068cf1
commit 0764e4ef29
5 changed files with 8 additions and 300 deletions

View File

@@ -24,7 +24,6 @@
#import "RCTUIManager.h"
#import "RCTUtils.h"
#import "RCTView.h"
#import "RCTWebViewExecutor.h"
#import "UIView+React.h"
NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification";

View File

@@ -1,48 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTDefines.h"
#if RCT_DEV // Debug executors are only supported in dev mode
#import <UIKit/UIKit.h>
#import "RCTJavaScriptExecutor.h"
/**
* Uses an embedded web view merely for the purpose of being able to reuse the
* existing webkit debugging tools. Fulfills the role of a very constrained
* `JSContext`, which we call `RCTJavaScriptExecutor`.
*
* TODO: To ensure production-identical execution, scrub the window
* environment. And ensure main thread operations are actually added to a queue
* instead of being executed immediately if already on the main thread.
*/
@interface RCTWebViewExecutor : NSObject<RCTJavaScriptExecutor>
// Only one callback stored - will only be invoked for the latest issued
// application script request.
@property (nonatomic, copy) RCTJavaScriptCompleteBlock onApplicationScriptLoaded;
/**
* Instantiate with a specific webview instance
*/
- (instancetype)initWithWebView:(UIWebView *)webView NS_DESIGNATED_INITIALIZER;
/**
* Invoke this to reclaim the web view for reuse. This is necessary in order to
* allow debuggers to remain open, when creating a new `RCTWebViewExecutor`.
* This guards against the web view being invalidated, and makes sure the
* `delegate` is cleared first.
*/
- (UIWebView *)invalidateAndReclaimWebView;
@end
#endif

View File

@@ -1,229 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTDefines.h"
#if RCT_DEV // Debug executors are only supported in dev mode
#import "RCTWebViewExecutor.h"
#import <objc/runtime.h>
#import "RCTLog.h"
#import "RCTUtils.h"
static void RCTReportError(RCTJavaScriptCallback callback, NSString *fmt, ...)
{
va_list args;
va_start(args, fmt);
NSString *description = [[NSString alloc] initWithFormat:fmt arguments:args];
RCTLogError(@"%@", description);
NSError *error = [NSError errorWithDomain:NSStringFromClass([RCTWebViewExecutor class])
code:3
userInfo:@{NSLocalizedDescriptionKey:description}];
callback(nil, error);
va_end(args);
}
@interface RCTWebViewExecutor () <UIWebViewDelegate>
@end
@implementation RCTWebViewExecutor
{
UIWebView *_webView;
NSMutableDictionary *_objectsToInject;
NSRegularExpression *_commentsRegex;
NSRegularExpression *_scriptTagsRegex;
}
RCT_EXPORT_MODULE()
@synthesize valid = _valid;
- (instancetype)initWithWebView:(UIWebView *)webView
{
if ((self = [super init])) {
_webView = webView;
}
return self;
}
- (instancetype)init
{
return [self initWithWebView:nil];
}
- (void)setUp
{
if (!_webView) {
[self executeBlockOnJavaScriptQueue:^{
_webView = [UIWebView new];
_webView.delegate = self;
}];
}
_objectsToInject = [NSMutableDictionary new];
_commentsRegex = [NSRegularExpression regularExpressionWithPattern:@"(^ *?\\/\\/.*?$|\\/\\*\\*[\\s\\S]*?\\*\\/)" options:NSRegularExpressionAnchorsMatchLines error:NULL];
_scriptTagsRegex = [NSRegularExpression regularExpressionWithPattern:@"<(\\/?script[^>]*?)>" options:0 error:NULL];
}
- (void)invalidate
{
_valid = NO;
_webView.delegate = nil;
_webView = nil;
}
- (UIWebView *)invalidateAndReclaimWebView
{
UIWebView *webView = _webView;
[self invalidate];
return webView;
}
- (void)executeJSCall:(NSString *)name
method:(NSString *)method
arguments:(NSArray *)arguments
callback:(RCTJavaScriptCallback)onComplete
{
RCTAssert(onComplete != nil, @"");
[self executeBlockOnJavaScriptQueue:^{
if (!self.isValid) {
return;
}
NSError *error;
NSString *argsString = RCTJSONStringify(arguments, &error);
if (!argsString) {
RCTReportError(onComplete, @"Cannot convert argument to string: %@", error);
return;
}
NSString *execString = [NSString stringWithFormat:@"JSON.stringify(require('%@').%@.apply(null, %@));", name, method, argsString];
NSString *ret = [_webView stringByEvaluatingJavaScriptFromString:execString];
if (ret.length == 0) {
RCTReportError(onComplete, @"Empty return string: JavaScript error running script: %@", execString);
return;
}
id objcValue = RCTJSONParse(ret, &error);
if (!objcValue) {
RCTReportError(onComplete, @"Cannot parse json response: %@", error);
return;
}
onComplete(objcValue, nil);
}];
}
/**
* We cannot use the standard eval JS method. Source will not show up in the
* debugger. So we have to use this (essentially) async API - and register
* ourselves as the webview delegate to be notified when load is complete.
*/
- (void)executeApplicationScript:(NSData *)script
sourceURL:(NSURL *)url
onComplete:(RCTJavaScriptCompleteBlock)onComplete
{
if (![NSThread isMainThread]) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self executeApplicationScript:script sourceURL:url onComplete:onComplete];
});
return;
}
RCTAssert(onComplete != nil, @"");
NSString *scriptString = [[NSString alloc] initWithData:script encoding:NSUTF8StringEncoding];
__weak RCTWebViewExecutor *weakSelf = self;
_onApplicationScriptLoaded = ^(NSError *error){
RCTWebViewExecutor *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
strongSelf->_valid = error == nil;
onComplete(error);
};
if (_objectsToInject.count > 0) {
NSMutableString *scriptWithInjections = [[NSMutableString alloc] initWithString:@"/* BEGIN NATIVELY INJECTED OBJECTS */\n"];
[_objectsToInject enumerateKeysAndObjectsUsingBlock:
^(NSString *objectName, NSString *blockScript, __unused BOOL *stop) {
[scriptWithInjections appendString:objectName];
[scriptWithInjections appendString:@" = ("];
[scriptWithInjections appendString:blockScript];
[scriptWithInjections appendString:@");\n"];
}];
[_objectsToInject removeAllObjects];
[scriptWithInjections appendString:@"/* END NATIVELY INJECTED OBJECTS */\n"];
[scriptWithInjections appendString:scriptString];
scriptString = scriptWithInjections;
}
scriptString = [_commentsRegex stringByReplacingMatchesInString:scriptString
options:0
range:NSMakeRange(0, script.length)
withTemplate:@""];
scriptString = [_scriptTagsRegex stringByReplacingMatchesInString:scriptString
options:0
range:NSMakeRange(0, script.length)
withTemplate:@"\\\\<$1\\\\>"];
NSString *runScript =
[NSString
stringWithFormat:@"<html><head></head><body><script type='text/javascript'>%@</script></body></html>",
scriptString
];
[_webView loadHTMLString:runScript baseURL:url];
}
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
{
if ([NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
}
- (void)executeAsyncBlockOnJavaScriptQueue:(dispatch_block_t)block
{
dispatch_async(dispatch_get_main_queue(), block);
}
/**
* `UIWebViewDelegate` methods. Handle application script load.
*/
- (void)webViewDidFinishLoad:(__unused UIWebView *)webView
{
RCTAssertMainThread();
if (_onApplicationScriptLoaded) {
_onApplicationScriptLoaded(nil); // TODO(frantic): how to fetch error from UIWebView?
}
_onApplicationScriptLoaded = nil;
}
- (void)injectJSONText:(NSString *)script
asGlobalObjectNamed:(NSString *)objectName
callback:(RCTJavaScriptCompleteBlock)onComplete
{
if (RCT_DEBUG) {
RCTAssert(!_objectsToInject[objectName],
@"already injected object named %@", _objectsToInject[objectName]);
}
_objectsToInject[objectName] = script;
onComplete(nil);
}
@end
#endif

View File

@@ -415,13 +415,6 @@ RCT_EXPORT_MODULE()
}]];
}
Class safariExecutorClass = NSClassFromString(@"RCTWebViewExecutor");
BOOL isDebuggingInSafari = _executorClass && _executorClass == safariExecutorClass;
NSString *debugTitleSafari = isDebuggingInSafari ? @"Disable Safari Debugging" : @"Debug in Safari";
[items addObject:[RCTDevMenuItem buttonItemWithTitle:debugTitleSafari handler:^{
weakSelf.executorClass = isDebuggingInSafari ? Nil : safariExecutorClass;
}]];
if (_liveReloadURL) {
NSString *liveReloadTitle = _liveReloadEnabled ? @"Disable Live Reload" : @"Enable Live Reload";
[items addObject:[RCTDevMenuItem buttonItemWithTitle:liveReloadTitle handler:^{
@@ -552,8 +545,7 @@ RCT_EXPORT_METHOD(reload)
// needed to prevent overriding a custom executor with the default if a
// custom executor has been set directly on the bridge
if (executorClass == Nil &&
(_bridge.executorClass != NSClassFromString(@"RCTWebSocketExecutor") &&
_bridge.executorClass != NSClassFromString(@"RCTWebViewExecutor"))) {
_bridge.executorClass != NSClassFromString(@"RCTWebSocketExecutor")) {
return;
}

View File

@@ -15,7 +15,6 @@
13456E961ADAD482009F94A7 /* RCTConvert+MapKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 13456E951ADAD482009F94A7 /* RCTConvert+MapKit.m */; };
134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */; };
134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */; };
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */; };
13513F3C1B1F43F400FCE529 /* RCTProgressViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */; };
13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */; };
1372B70A1AB030C200659ED6 /* RCTAppState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1372B7091AB030C200659ED6 /* RCTAppState.m */; };
@@ -53,11 +52,11 @@
142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 142014171B32094000CC17BA /* RCTPerformanceLogger.m */; };
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 14435CE21AAC4AE100FC20F4 /* RCTMap.m */; };
14435CE61AAC4AE100FC20F4 /* RCTMapManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14435CE41AAC4AE100FC20F4 /* RCTMapManager.m */; };
1450FF861BCFF28A00208362 /* RCTProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF811BCFF28A00208362 /* RCTProfile.m */; settings = {ASSET_TAGS = (); }; };
1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */; settings = {ASSET_TAGS = (); }; };
1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */; settings = {ASSET_TAGS = (); }; };
1450FF891BCFF28A00208362 /* RCTProfileTrampoline-x86.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF841BCFF28A00208362 /* RCTProfileTrampoline-x86.S */; settings = {ASSET_TAGS = (); }; };
1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */; settings = {ASSET_TAGS = (); }; };
1450FF861BCFF28A00208362 /* RCTProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF811BCFF28A00208362 /* RCTProfile.m */; };
1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */; };
1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */; };
1450FF891BCFF28A00208362 /* RCTProfileTrampoline-x86.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF841BCFF28A00208362 /* RCTProfileTrampoline-x86.S */; };
1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */; };
14C2CA711B3AC63800E6CBB2 /* RCTModuleMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */; };
14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */; };
14C2CA761B3AC64F00E6CBB2 /* RCTFrameUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA751B3AC64F00E6CBB2 /* RCTFrameUpdate.m */; };
@@ -65,8 +64,8 @@
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F362081AABD06A001CE568 /* RCTSwitch.m */; };
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */; };
14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */; };
14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */; settings = {ASSET_TAGS = (); }; };
14F7A0F01BDA714B003C6C10 /* RCTFPSGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */; settings = {ASSET_TAGS = (); }; };
14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */; };
14F7A0F01BDA714B003C6C10 /* RCTFPSGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */; };
58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; };
58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; };
@@ -121,8 +120,6 @@
1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTURLRequestHandler.h; sourceTree = "<group>"; };
134FCB391A6E7F0800051CC8 /* RCTContextExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTContextExecutor.h; sourceTree = "<group>"; };
134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTContextExecutor.m; sourceTree = "<group>"; };
134FCB3B1A6E7F0800051CC8 /* RCTWebViewExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewExecutor.h; sourceTree = "<group>"; };
134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebViewExecutor.m; sourceTree = "<group>"; };
13513F3A1B1F43F400FCE529 /* RCTProgressViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTProgressViewManager.h; sourceTree = "<group>"; };
13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTProgressViewManager.m; sourceTree = "<group>"; };
13723B4E1A82FD3C00F88898 /* RCTStatusBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStatusBarManager.h; sourceTree = "<group>"; };
@@ -290,8 +287,6 @@
children = (
134FCB391A6E7F0800051CC8 /* RCTContextExecutor.h */,
134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */,
134FCB3B1A6E7F0800051CC8 /* RCTWebViewExecutor.h */,
134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */,
);
path = Executors;
sourceTree = "<group>";
@@ -686,7 +681,6 @@
83392EB31B6634E10013B15F /* RCTModalHostViewController.m in Sources */,
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */,
1450FF891BCFF28A00208362 /* RCTProfileTrampoline-x86.S in Sources */,
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */,
13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
1385D0341B665AAE000A309B /* RCTModuleMap.m in Sources */,
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,