From 959aacff73783db83240c44266ea929aec6a018b Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Thu, 16 Aug 2018 13:34:33 -0700 Subject: [PATCH] Dynamically load WebKit Summary: @public We can't dynamically link `WebKit` because doing so will impact cold start of all our Apps. This diff includes a few changes: 1. Weakly link the `WebKit` framework in the `ReactInternal` library, so that the compiler doesn't die when it encounters a WebKit symbol. 2. Undo dynamic linking of WebKit in Catalyst. 3. Undo dynamic linking of WebKit in AdsManager 4. Before the first `WKWebView` is instantiated, dynamically load the `WebKit` framework. The end result of these changes is that WebKit will be loaded only when it's going to be used. Reviewed By: mmmulani Differential Revision: D6564328 fbshipit-source-id: a45a44e774d0c61c1fb578a6fa3d16bb08f68ac9 --- React/Base/RCTConvert.h | 3 +++ React/React.xcodeproj/project.pbxproj | 12 ++++++++++-- React/Views/RCTWKWebView.m | 23 +++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index 1f66328ea76..dff41ec1328 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -69,6 +69,9 @@ typedef NSURL RCTFileURL; + (UIReturnKeyType)UIReturnKeyType:(id)json; #if !TARGET_OS_TV + (UIDataDetectorTypes)UIDataDetectorTypes:(id)json; +#endif + +#if TARGET_OS_IPHONE + (WKDataDetectorTypes)WKDataDetectorTypes:(id)json; #endif diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index ac97a4d41e6..1f8c1e4b1eb 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -5240,7 +5240,11 @@ "RCT_METRO_PORT=${RCT_METRO_PORT}", ); GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "-ObjC", + "-weak_framework", + WebKit, + ); PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/React; RUN_CLANG_STATIC_ANALYZER = YES; @@ -5258,7 +5262,11 @@ "RCT_METRO_PORT=${RCT_METRO_PORT}", ); GCC_WARN_ABOUT_MISSING_NEWLINE = YES; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "-ObjC", + "-weak_framework", + WebKit, + ); PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/React; RUN_CLANG_STATIC_ANALYZER = NO; diff --git a/React/Views/RCTWKWebView.m b/React/Views/RCTWKWebView.m index 2488ff209a9..71c2d88de90 100644 --- a/React/Views/RCTWKWebView.m +++ b/React/Views/RCTWKWebView.m @@ -23,6 +23,25 @@ static NSString *const MessageHanderName = @"ReactNative"; } +/** + * See https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/DisplayWebContent/Tasks/WebKitAvail.html. + */ ++ (BOOL)dynamicallyLoadWebKitIfAvailable +{ + static BOOL _webkitAvailable=NO; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + NSBundle *webKitBundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/WebKit.framework"]; + if (webKitBundle) { + _webkitAvailable = [webKitBundle load]; + } + }); + + return _webkitAvailable; +} + + - (instancetype)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { @@ -38,6 +57,10 @@ static NSString *const MessageHanderName = @"ReactNative"; - (void)didMoveToWindow { if (self.window != nil) { + if (![[self class] dynamicallyLoadWebKitIfAvailable]) { + return; + }; + WKWebViewConfiguration *wkWebViewConfig = [WKWebViewConfiguration new]; wkWebViewConfig.userContentController = [WKUserContentController new]; [wkWebViewConfig.userContentController addScriptMessageHandler: self name: MessageHanderName];