Move iOS WebView files to FB internal

Summary: This moves the iOS WebView files to be fb internal which completes the removal of WebView from React Native open source as part of the Lean Core effort.

Reviewed By: TheSavior

Differential Revision: D14630076

fbshipit-source-id: 7bc11d6c1470bb748c823c86cbb8b5ee94b508ff
This commit is contained in:
Christoph Nakazawa
2019-04-04 15:39:17 -07:00
committed by Facebook Github Bot
parent 06cf7face2
commit 6ca438a7f4
10 changed files with 0 additions and 1272 deletions

View File

@@ -41,8 +41,6 @@ Pod::Spec.new do |s|
"Views/RCTRefreshControl*",
"Views/RCTSlider*",
"Views/RCTSwitch*",
"Views/RCTWebView*",
"Views/RCTWKWebView*"
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags
s.header_dir = "React"
s.framework = "JavaScriptCore"

View File

@@ -106,8 +106,6 @@
13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080241A694A8400A75B9A /* RCTWrapperViewController.m */; };
13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BB3D011BECD54500932C10 /* RCTImageSource.m */; };
13BCE8091C99CB9D00DD7AAD /* RCTRootShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BCE8081C99CB9D00DD7AAD /* RCTRootShadowView.m */; };
13C156051AB1A2840079392D /* RCTWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156021AB1A2840079392D /* RCTWebView.m */; };
13C156061AB1A2840079392D /* RCTWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156041AB1A2840079392D /* RCTWebViewManager.m */; };
13CC8A821B17642100940AE7 /* RCTBorderDrawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */; };
13D033631C1837FE0021DC29 /* RCTClipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D033621C1837FE0021DC29 /* RCTClipboard.m */; };
13D9FEEB1CDCCECF00158BD7 /* RCTEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D9FEEA1CDCCECF00158BD7 /* RCTEventEmitter.m */; };
@@ -546,8 +544,6 @@
3D80D9921DF6FA890028D040 /* RCTTextDecorationLineType.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */; };
3D80D9931DF6FA890028D040 /* RCTView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13E0674F1A70F44B002CDEE1 /* RCTView.h */; };
3D80D9951DF6FA890028D040 /* RCTViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13E0674D1A70F44B002CDEE1 /* RCTViewManager.h */; };
3D80D9961DF6FA890028D040 /* RCTWebView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13C156011AB1A2840079392D /* RCTWebView.h */; };
3D80D9971DF6FA890028D040 /* RCTWebViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13C156031AB1A2840079392D /* RCTWebViewManager.h */; };
3D80D9981DF6FA890028D040 /* RCTWrapperViewController.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B080231A694A8400A75B9A /* RCTWrapperViewController.h */; };
3D80D99A1DF6FA890028D040 /* UIView+React.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13E067531A70F44B002CDEE1 /* UIView+React.h */; };
3D80DA191DF820620028D040 /* RCTImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D1FA0831DE4F3A000E03CC6 /* RCTImageLoader.h */; };
@@ -644,8 +640,6 @@
3D80DA8C1DF820620028D040 /* RCTTextDecorationLineType.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */; };
3D80DA8D1DF820620028D040 /* RCTView.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E0674F1A70F44B002CDEE1 /* RCTView.h */; };
3D80DA8F1DF820620028D040 /* RCTViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E0674D1A70F44B002CDEE1 /* RCTViewManager.h */; };
3D80DA901DF820620028D040 /* RCTWebView.h in Headers */ = {isa = PBXBuildFile; fileRef = 13C156011AB1A2840079392D /* RCTWebView.h */; };
3D80DA911DF820620028D040 /* RCTWebViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13C156031AB1A2840079392D /* RCTWebViewManager.h */; };
3D80DA921DF820620028D040 /* RCTWrapperViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B080231A694A8400A75B9A /* RCTWrapperViewController.h */; };
3D80DA931DF820620028D040 /* UIView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F15A171B7CC46900F10295 /* UIView+Private.h */; };
3D80DA941DF820620028D040 /* UIView+React.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E067531A70F44B002CDEE1 /* UIView+React.h */; };
@@ -757,8 +751,6 @@
3DA982301E5B0F7F004F2374 /* RCTTVView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130443D61E401AD800D93A67 /* RCTTVView.h */; };
3DA982311E5B0F7F004F2374 /* RCTView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13E0674F1A70F44B002CDEE1 /* RCTView.h */; };
3DA982331E5B0F7F004F2374 /* RCTViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13E0674D1A70F44B002CDEE1 /* RCTViewManager.h */; };
3DA982341E5B0F7F004F2374 /* RCTWebView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13C156011AB1A2840079392D /* RCTWebView.h */; };
3DA982351E5B0F7F004F2374 /* RCTWebViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13C156031AB1A2840079392D /* RCTWebViewManager.h */; };
3DA982361E5B0F7F004F2374 /* RCTWrapperViewController.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13B080231A694A8400A75B9A /* RCTWrapperViewController.h */; };
3DA982381E5B0F7F004F2374 /* UIView+React.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 13E067531A70F44B002CDEE1 /* UIView+React.h */; };
3DA982391E5B0F8A004F2374 /* UIView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F15A171B7CC46900F10295 /* UIView+Private.h */; };
@@ -804,10 +796,6 @@
4F56C93822167A4800DB9F3F /* jsilib.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsilib.h */; };
4F56C93922167A4D00DB9F3F /* jsilib.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsilib.h */; };
4F56C93A2216A3B700DB9F3F /* jsilib.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsilib.h */; };
50E98FEA21460B0D00CD9289 /* RCTWKWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 50E98FE621460B0D00CD9289 /* RCTWKWebViewManager.m */; };
50E98FEB21460B0D00CD9289 /* RCTWKWebView.h in Headers */ = {isa = PBXBuildFile; fileRef = 50E98FE721460B0D00CD9289 /* RCTWKWebView.h */; };
50E98FEC21460B0D00CD9289 /* RCTWKWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 50E98FE821460B0D00CD9289 /* RCTWKWebView.m */; };
50E98FED21460B0D00CD9289 /* RCTWKWebViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 50E98FE921460B0D00CD9289 /* RCTWKWebViewManager.h */; };
5335D5411FE81A4700883D58 /* RCTShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5335D5401FE81A4700883D58 /* RCTShadowView.m */; };
53438962203905BB008E0CB3 /* YGLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5343895E203905B6008E0CB3 /* YGLayout.cpp */; };
53438963203905BC008E0CB3 /* YGLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5343895E203905B6008E0CB3 /* YGLayout.cpp */; };
@@ -1436,8 +1424,6 @@
3DA982301E5B0F7F004F2374 /* RCTTVView.h in Copy Headers */,
3DA982311E5B0F7F004F2374 /* RCTView.h in Copy Headers */,
3DA982331E5B0F7F004F2374 /* RCTViewManager.h in Copy Headers */,
3DA982341E5B0F7F004F2374 /* RCTWebView.h in Copy Headers */,
3DA982351E5B0F7F004F2374 /* RCTWebViewManager.h in Copy Headers */,
3DA982361E5B0F7F004F2374 /* RCTWrapperViewController.h in Copy Headers */,
3DA982381E5B0F7F004F2374 /* UIView+React.h in Copy Headers */,
3DA981BF1E5B0F29004F2374 /* RCTAssert.h in Copy Headers */,
@@ -1669,8 +1655,6 @@
3D80D9921DF6FA890028D040 /* RCTTextDecorationLineType.h in Copy Headers */,
3D80D9931DF6FA890028D040 /* RCTView.h in Copy Headers */,
3D80D9951DF6FA890028D040 /* RCTViewManager.h in Copy Headers */,
3D80D9961DF6FA890028D040 /* RCTWebView.h in Copy Headers */,
3D80D9971DF6FA890028D040 /* RCTWebViewManager.h in Copy Headers */,
3D80D9981DF6FA890028D040 /* RCTWrapperViewController.h in Copy Headers */,
3D80D99A1DF6FA890028D040 /* UIView+React.h in Copy Headers */,
);
@@ -1936,10 +1920,6 @@
13BB3D011BECD54500932C10 /* RCTImageSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageSource.m; sourceTree = "<group>"; };
13BCE8071C99CB9D00DD7AAD /* RCTRootShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootShadowView.h; sourceTree = "<group>"; };
13BCE8081C99CB9D00DD7AAD /* RCTRootShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootShadowView.m; sourceTree = "<group>"; };
13C156011AB1A2840079392D /* RCTWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebView.h; sourceTree = "<group>"; };
13C156021AB1A2840079392D /* RCTWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebView.m; sourceTree = "<group>"; };
13C156031AB1A2840079392D /* RCTWebViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewManager.h; sourceTree = "<group>"; };
13C156041AB1A2840079392D /* RCTWebViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebViewManager.m; sourceTree = "<group>"; };
13C325261AA63B6A0048765F /* RCTAutoInsetsProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAutoInsetsProtocol.h; sourceTree = "<group>"; };
13C325281AA63B6A0048765F /* RCTComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTComponent.h; sourceTree = "<group>"; };
13CC8A801B17642100940AE7 /* RCTBorderDrawing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBorderDrawing.h; sourceTree = "<group>"; };
@@ -2067,10 +2047,6 @@
3EDCA8A31D3591E700450C31 /* RCTErrorInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorInfo.h; sourceTree = "<group>"; };
3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTErrorInfo.m; sourceTree = "<group>"; };
4F56C93722167A4800DB9F3F /* jsilib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsilib.h; sourceTree = "<group>"; };
50E98FE621460B0D00CD9289 /* RCTWKWebViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWKWebViewManager.m; sourceTree = "<group>"; };
50E98FE721460B0D00CD9289 /* RCTWKWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWKWebView.h; sourceTree = "<group>"; };
50E98FE821460B0D00CD9289 /* RCTWKWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWKWebView.m; sourceTree = "<group>"; };
50E98FE921460B0D00CD9289 /* RCTWKWebViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWKWebViewManager.h; sourceTree = "<group>"; };
5335D5401FE81A4700883D58 /* RCTShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowView.m; sourceTree = "<group>"; };
5343895E203905B6008E0CB3 /* YGLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGLayout.cpp; sourceTree = "<group>"; };
5343895F203905B6008E0CB3 /* YGLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGLayout.h; sourceTree = "<group>"; };
@@ -2552,10 +2528,6 @@
13B07FF31A6947C200A75B9A /* Views */ = {
isa = PBXGroup;
children = (
50E98FE721460B0D00CD9289 /* RCTWKWebView.h */,
50E98FE821460B0D00CD9289 /* RCTWKWebView.m */,
50E98FE921460B0D00CD9289 /* RCTWKWebViewManager.h */,
50E98FE621460B0D00CD9289 /* RCTWKWebViewManager.m */,
B95154301D1B34B200FE7B80 /* RCTActivityIndicatorView.h */,
B95154311D1B34B200FE7B80 /* RCTActivityIndicatorView.m */,
13B080181A69489C00A75B9A /* RCTActivityIndicatorViewManager.h */,
@@ -2630,10 +2602,6 @@
13E067501A70F44B002CDEE1 /* RCTView.m */,
13E0674D1A70F44B002CDEE1 /* RCTViewManager.h */,
13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */,
13C156011AB1A2840079392D /* RCTWebView.h */,
13C156021AB1A2840079392D /* RCTWebView.m */,
13C156031AB1A2840079392D /* RCTWebViewManager.h */,
13C156041AB1A2840079392D /* RCTWebViewManager.m */,
13B080231A694A8400A75B9A /* RCTWrapperViewController.h */,
13B080241A694A8400A75B9A /* RCTWrapperViewController.m */,
59D031E41F8353D3008361F0 /* SafeAreaView */,
@@ -3421,7 +3389,6 @@
3D80DA2A1DF820620028D040 /* RCTErrorCustomizer.h in Headers */,
3D80DA2B1DF820620028D040 /* RCTErrorInfo.h in Headers */,
1384E2081E806D4E00545659 /* RCTNativeModule.h in Headers */,
50E98FED21460B0D00CD9289 /* RCTWKWebViewManager.h in Headers */,
3D7BFD2D1EA8E3FA008DFB7A /* RCTReconnectingWebSocket.h in Headers */,
3D80DA2C1DF820620028D040 /* RCTEventDispatcher.h in Headers */,
3D80DA2D1DF820620028D040 /* RCTFrameUpdate.h in Headers */,
@@ -3431,7 +3398,6 @@
599FAA3A1FB274980058CCF6 /* RCTSurfaceDelegate.h in Headers */,
3D80DA301DF820620028D040 /* RCTJavaScriptExecutor.h in Headers */,
3DCE53281FEAB23100613583 /* RCTDatePicker.h in Headers */,
50E98FEB21460B0D00CD9289 /* RCTWKWebView.h in Headers */,
3D80DA311DF820620028D040 /* RCTJavaScriptLoader.h in Headers */,
130E3D881E6A082100ACE484 /* RCTDevSettings.h in Headers */,
3D80DA321DF820620028D040 /* RCTJSStackFrame.h in Headers */,
@@ -3551,8 +3517,6 @@
3D80DA8F1DF820620028D040 /* RCTViewManager.h in Headers */,
13134CA01E296B2A00B9F3CB /* RCTCxxUtils.h in Headers */,
599FAA4A1FB274980058CCF6 /* RCTSurfaceView.h in Headers */,
3D80DA901DF820620028D040 /* RCTWebView.h in Headers */,
3D80DA911DF820620028D040 /* RCTWebViewManager.h in Headers */,
3D80DA921DF820620028D040 /* RCTWrapperViewController.h in Headers */,
3D80DA931DF820620028D040 /* UIView+Private.h in Headers */,
3D80DA941DF820620028D040 /* UIView+React.h in Headers */,
@@ -4471,7 +4435,6 @@
C60128AD1F3D1258009DF9FF /* RCTCxxConvert.m in Sources */,
3DCE53291FEAB23100613583 /* RCTDatePicker.m in Sources */,
0EEEA8DF2239002200A8C82D /* RCTSurfacePresenterStub.m in Sources */,
50E98FEA21460B0D00CD9289 /* RCTWKWebViewManager.m in Sources */,
83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */,
59EB6DBD1EBD6FC90072A5E7 /* RCTUIManagerObserverCoordinator.mm in Sources */,
59E604A21FE9CCE300BD90C5 /* RCTScrollContentViewManager.m in Sources */,
@@ -4546,13 +4509,10 @@
130443C61E401A8C00D93A67 /* RCTConvert+Transform.m in Sources */,
191E3EC11C29DC3800C180A6 /* RCTRefreshControl.m in Sources */,
3DCE532B1FEAB23100613583 /* RCTDatePickerManager.m in Sources */,
13C156051AB1A2840079392D /* RCTWebView.m in Sources */,
83CBBA601A601EAA00E9B192 /* RCTBridge.m in Sources */,
50E98FEC21460B0D00CD9289 /* RCTWKWebView.m in Sources */,
590D7BFF1EBD458B00D8A370 /* RCTShadowView+Layout.m in Sources */,
5335D5411FE81A4700883D58 /* RCTShadowView.m in Sources */,
66CD94B31F1045E700CB3C7C /* RCTMaskedView.m in Sources */,
13C156061AB1A2840079392D /* RCTWebViewManager.m in Sources */,
58114A161AAE854800E7D092 /* RCTPicker.m in Sources */,
83A1FE8C1B62640A00BE0E65 /* RCTModalHostView.m in Sources */,
5925356A20084D0600DD584B /* RCTSurfaceSizeMeasureMode.mm in Sources */,

View File

@@ -1,47 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTView.h>
#import <React/RCTDefines.h>
#import <WebKit/WebKit.h>
@class RCTWKWebView;
@protocol RCTWKWebViewDelegate <NSObject>
- (BOOL)webView:(RCTWKWebView *)webView
shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
withCallback:(RCTDirectEventBlock)callback;
@end
@interface RCTWKWebView : RCTView
@property (nonatomic, weak) id<RCTWKWebViewDelegate> delegate;
@property (nonatomic, copy) NSDictionary *source;
@property (nonatomic, assign) BOOL messagingEnabled;
@property (nonatomic, copy) NSString *injectedJavaScript;
@property (nonatomic, assign) BOOL scrollEnabled;
@property (nonatomic, assign) CGFloat decelerationRate;
@property (nonatomic, assign) BOOL allowsInlineMediaPlayback;
@property (nonatomic, assign) BOOL bounces;
@property (nonatomic, assign) BOOL mediaPlaybackRequiresUserAction;
#if WEBKIT_IOS_10_APIS_AVAILABLE
@property (nonatomic, assign) WKDataDetectorTypes dataDetectorTypes;
#endif
@property (nonatomic, assign) UIEdgeInsets contentInset;
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
+ (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential;
- (void)postMessage:(NSString *)message;
- (void)injectJavaScript:(NSString *)script;
- (void)goForward;
- (void)goBack;
- (void)reload;
- (void)stopLoading;
@end

View File

@@ -1,435 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTWKWebView.h"
#import <React/RCTConvert.h>
#import "RCTAutoInsetsProtocol.h"
static NSString *const MessageHanderName = @"ReactNative";
static NSURLCredential* clientAuthenticationCredential;
@interface RCTWKWebView () <WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, UIScrollViewDelegate, RCTAutoInsetsProtocol>
@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
@property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
@property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
@property (nonatomic, copy) RCTDirectEventBlock onMessage;
@property (nonatomic, copy) WKWebView *webView;
@end
@implementation RCTWKWebView
{
UIColor * _savedBackgroundColor;
}
- (void)dealloc
{
}
/**
* 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])) {
super.backgroundColor = [UIColor clearColor];
_bounces = YES;
_scrollEnabled = YES;
_automaticallyAdjustContentInsets = YES;
_contentInset = UIEdgeInsetsZero;
}
return self;
}
- (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];
wkWebViewConfig.allowsInlineMediaPlayback = _allowsInlineMediaPlayback;
#if WEBKIT_IOS_10_APIS_AVAILABLE
wkWebViewConfig.mediaTypesRequiringUserActionForPlayback = _mediaPlaybackRequiresUserAction
? WKAudiovisualMediaTypeAll
: WKAudiovisualMediaTypeNone;
wkWebViewConfig.dataDetectorTypes = _dataDetectorTypes;
#else
wkWebViewConfig.mediaPlaybackRequiresUserAction = _mediaPlaybackRequiresUserAction;
#endif
_webView = [[WKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig];
_webView.scrollView.delegate = self;
_webView.UIDelegate = self;
_webView.navigationDelegate = self;
_webView.scrollView.scrollEnabled = _scrollEnabled;
_webView.scrollView.bounces = _bounces;
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
_webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
#endif
[self addSubview:_webView];
[self visitSource];
}
}
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
_savedBackgroundColor = backgroundColor;
if (_webView == nil) {
return;
}
CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
self.opaque = _webView.opaque = (alpha == 1.0);
_webView.scrollView.backgroundColor = backgroundColor;
_webView.backgroundColor = backgroundColor;
}
/**
* This method is called whenever JavaScript running within the web view calls:
* - window.webkit.messageHandlers.[MessageHanderName].postMessage
*/
- (void)userContentController:(__unused WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message
{
if (_onMessage != nil) {
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary: @{@"data": message.body}];
_onMessage(event);
}
}
- (void)setSource:(NSDictionary *)source
{
if (![_source isEqualToDictionary:source]) {
_source = [source copy];
if (_webView != nil) {
[self visitSource];
}
}
}
- (void)setContentInset:(UIEdgeInsets)contentInset
{
_contentInset = contentInset;
[RCTView autoAdjustInsetsForView:self
withScrollView:_webView.scrollView
updateOffset:NO];
}
- (void)refreshContentInset
{
[RCTView autoAdjustInsetsForView:self
withScrollView:_webView.scrollView
updateOffset:YES];
}
- (void)visitSource
{
// Check for a static html source first
NSString *html = [RCTConvert NSString:_source[@"html"]];
if (html) {
NSURL *baseURL = [RCTConvert NSURL:_source[@"baseUrl"]];
if (!baseURL) {
baseURL = [NSURL URLWithString:@"about:blank"];
}
[_webView loadHTMLString:html baseURL:baseURL];
return;
}
NSURLRequest *request = [RCTConvert NSURLRequest:_source];
// Because of the way React works, as pages redirect, we actually end up
// passing the redirect urls back here, so we ignore them if trying to load
// the same url. We'll expose a call to 'reload' to allow a user to load
// the existing page.
if ([request.URL isEqual:_webView.URL]) {
return;
}
if (!request.URL) {
// Clear the webview
[_webView loadHTMLString:@"" baseURL:nil];
return;
}
[_webView loadRequest:request];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
scrollView.decelerationRate = _decelerationRate;
}
- (void)setScrollEnabled:(BOOL)scrollEnabled
{
_scrollEnabled = scrollEnabled;
_webView.scrollView.scrollEnabled = scrollEnabled;
}
- (void)postMessage:(NSString *)message
{
NSDictionary *eventInitDict = @{@"data": message};
NSString *source = [NSString
stringWithFormat:@"document.dispatchEvent(new MessageEvent('message', %@));",
RCTJSONStringify(eventInitDict, NULL)
];
[self evaluateJS: source thenCall: nil];
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Ensure webview takes the position and dimensions of RCTWKWebView
_webView.frame = self.bounds;
}
- (NSMutableDictionary<NSString *, id> *)baseEvent
{
NSDictionary *event = @{
@"url": _webView.URL.absoluteString ?: @"",
@"title": _webView.title,
@"loading" : @(_webView.loading),
@"canGoBack": @(_webView.canGoBack),
@"canGoForward" : @(_webView.canGoForward)
};
return [[NSMutableDictionary alloc] initWithDictionary: event];
}
#pragma mark - WKNavigationDelegate methods
/**
* Decides whether to allow or cancel a navigation.
* @see https://fburl.com/42r9fxob
*/
- (void) webView:(__unused WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
static NSDictionary<NSNumber *, NSString *> *navigationTypes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
navigationTypes = @{
@(WKNavigationTypeLinkActivated): @"click",
@(WKNavigationTypeFormSubmitted): @"formsubmit",
@(WKNavigationTypeBackForward): @"backforward",
@(WKNavigationTypeReload): @"reload",
@(WKNavigationTypeFormResubmitted): @"formresubmit",
@(WKNavigationTypeOther): @"other",
};
});
WKNavigationType navigationType = navigationAction.navigationType;
NSURLRequest *request = navigationAction.request;
if (_onShouldStartLoadWithRequest) {
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary: @{
@"url": (request.URL).absoluteString,
@"navigationType": navigationTypes[@(navigationType)]
}];
if (![self.delegate webView:self
shouldStartLoadForRequest:event
withCallback:_onShouldStartLoadWithRequest]) {
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
if (_onLoadingStart) {
// We have this check to filter out iframe requests and whatnot
BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
if (isTopFrame) {
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary: @{
@"url": (request.URL).absoluteString,
@"navigationType": navigationTypes[@(navigationType)]
}];
_onLoadingStart(event);
}
}
// Allow all navigation by default
decisionHandler(WKNavigationActionPolicyAllow);
}
/**
* Called when an error occurs while the web view is loading content.
* @see https://fburl.com/km6vqenw
*/
- (void) webView:(__unused WKWebView *)webView
didFailProvisionalNavigation:(__unused WKNavigation *)navigation
withError:(NSError *)error
{
if (_onLoadingError) {
if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) {
// NSURLErrorCancelled is reported when a page has a redirect OR if you load
// a new URL in the WebView before the previous one came back. We can just
// ignore these since they aren't real errors.
// http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
return;
}
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary:@{
@"didFailProvisionalNavigation": @YES,
@"domain": error.domain,
@"code": @(error.code),
@"description": error.localizedDescription,
}];
_onLoadingError(event);
}
[self setBackgroundColor: _savedBackgroundColor];
}
+ (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential {
clientAuthenticationCredential = credential;
}
- (void) webView:(__unused WKWebView *)webView
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable))completionHandler
{
if (!clientAuthenticationCredential) {
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
return;
}
if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
completionHandler(NSURLSessionAuthChallengeUseCredential, clientAuthenticationCredential);
} else {
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
}
}
- (void)evaluateJS:(NSString *)js
thenCall: (void (^)(NSString*)) callback
{
[self.webView evaluateJavaScript: js completionHandler: ^(id result, NSError *error) {
if (error == nil && callback != nil) {
callback([NSString stringWithFormat:@"%@", result]);
}
}];
}
/**
* Called when the navigation is complete.
* @see https://fburl.com/rtys6jlb
*/
- (void) webView:(__unused WKWebView *)webView
didFinishNavigation:(__unused WKNavigation *)navigation
{
if (_messagingEnabled) {
#if RCT_DEV
// Implementation inspired by Lodash.isNative.
NSString *isPostMessageNative = @"String(String(window.postMessage) === String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage'))";
[self evaluateJS: isPostMessageNative thenCall: ^(NSString *result) {
if (! [result isEqualToString:@"true"]) {
RCTLogError(@"Setting onMessage on a WebView overrides existing values of window.postMessage, but a previous value was defined");
}
}];
#endif
NSString *source = [NSString stringWithFormat:
@"(function() {"
"window.originalPostMessage = window.postMessage;"
"window.postMessage = function(data) {"
"window.webkit.messageHandlers.%@.postMessage(String(data));"
"};"
"})();",
MessageHanderName
];
[self evaluateJS: source thenCall: nil];
}
if (_injectedJavaScript) {
[self evaluateJS: _injectedJavaScript thenCall: ^(NSString *jsEvaluationValue) {
NSMutableDictionary *event = [self baseEvent];
event[@"jsEvaluationValue"] = jsEvaluationValue;
if (self.onLoadingFinish) {
self.onLoadingFinish(event);
}
}];
} else if (_onLoadingFinish) {
_onLoadingFinish([self baseEvent]);
}
[self setBackgroundColor: _savedBackgroundColor];
}
- (void)injectJavaScript:(NSString *)script
{
[self evaluateJS: script thenCall: nil];
}
- (void)goForward
{
[_webView goForward];
}
- (void)goBack
{
[_webView goBack];
}
- (void)reload
{
/**
* When the initial load fails due to network connectivity issues,
* [_webView reload] doesn't reload the webpage. Therefore, we must
* manually call [_webView loadRequest:request].
*/
NSURLRequest *request = [RCTConvert NSURLRequest:self.source];
if (request.URL && !_webView.URL.absoluteString.length) {
[_webView loadRequest:request];
}
else {
[_webView reload];
}
}
- (void)stopLoading
{
[_webView stopLoading];
}
- (void)setBounces:(BOOL)bounces
{
_bounces = bounces;
_webView.scrollView.bounces = bounces;
}
@end

View File

@@ -1,11 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTViewManager.h>
@interface RCTWKWebViewManager : RCTViewManager
@end

View File

@@ -1,170 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTWKWebViewManager.h"
#import "RCTUIManager.h"
#import "RCTWKWebView.h"
#import <React/RCTDefines.h>
@interface RCTWKWebViewManager () <RCTWKWebViewDelegate>
@end
@implementation RCTWKWebViewManager
{
NSConditionLock *_shouldStartLoadLock;
BOOL _shouldStartLoad;
}
RCT_EXPORT_MODULE()
- (UIView *)view
{
RCTWKWebView *webView = [RCTWKWebView new];
webView.delegate = self;
return webView;
}
RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL)
RCT_EXPORT_VIEW_PROPERTY(mediaPlaybackRequiresUserAction, BOOL)
#if WEBKIT_IOS_10_APIS_AVAILABLE
RCT_EXPORT_VIEW_PROPERTY(dataDetectorTypes, WKDataDetectorTypes)
#endif
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
/**
* Expose methods to enable messaging the webview.
*/
RCT_EXPORT_VIEW_PROPERTY(messagingEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onMessage, RCTDirectEventBlock)
RCT_EXPORT_METHOD(postMessage:(nonnull NSNumber *)reactTag message:(NSString *)message)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWKWebView *> *viewRegistry) {
RCTWKWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWKWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view postMessage:message];
}
}];
}
RCT_CUSTOM_VIEW_PROPERTY(bounces, BOOL, __unused RCTWKWebView) {
view.bounces = json == nil ? true : [RCTConvert BOOL: json];
}
RCT_CUSTOM_VIEW_PROPERTY(scrollEnabled, BOOL, __unused RCTWKWebView) {
view.scrollEnabled = json == nil ? true : [RCTConvert BOOL: json];
}
RCT_CUSTOM_VIEW_PROPERTY(decelerationRate, CGFloat, __unused RCTWKWebView) {
view.decelerationRate = json == nil ? UIScrollViewDecelerationRateNormal : [RCTConvert CGFloat: json];
}
RCT_EXPORT_METHOD(injectJavaScript:(nonnull NSNumber *)reactTag script:(NSString *)script)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWKWebView *> *viewRegistry) {
RCTWKWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWKWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view injectJavaScript:script];
}
}];
}
RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWKWebView *> *viewRegistry) {
RCTWKWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWKWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view goBack];
}
}];
}
RCT_EXPORT_METHOD(goForward:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWKWebView *> *viewRegistry) {
RCTWKWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWKWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view goForward];
}
}];
}
RCT_EXPORT_METHOD(reload:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWKWebView *> *viewRegistry) {
RCTWKWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWKWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view reload];
}
}];
}
RCT_EXPORT_METHOD(stopLoading:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWKWebView *> *viewRegistry) {
RCTWKWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWKWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view stopLoading];
}
}];
}
#pragma mark - Exported synchronous methods
- (BOOL) webView:(__unused RCTWKWebView *)webView
shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
withCallback:(RCTDirectEventBlock)callback
{
_shouldStartLoadLock = [[NSConditionLock alloc] initWithCondition:arc4random()];
_shouldStartLoad = YES;
request[@"lockIdentifier"] = @(_shouldStartLoadLock.condition);
callback(request);
// Block the main thread for a maximum of 250ms until the JS thread returns
if ([_shouldStartLoadLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:.25]]) {
BOOL returnValue = _shouldStartLoad;
[_shouldStartLoadLock unlock];
_shouldStartLoadLock = nil;
return returnValue;
} else {
RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES");
return YES;
}
}
RCT_EXPORT_METHOD(startLoadWithResult:(BOOL)result lockIdentifier:(NSInteger)lockIdentifier)
{
if ([_shouldStartLoadLock tryLockWhenCondition:lockIdentifier]) {
_shouldStartLoad = result;
[_shouldStartLoadLock unlockWithCondition:0];
} else {
RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: "
"got %lld, expected %lld", (long long)lockIdentifier, (long long)_shouldStartLoadLock.condition);
}
}
@end

View File

@@ -1,46 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTView.h>
@class RCTWebView;
/**
* Special scheme used to pass messages to the injectedJavaScript
* code without triggering a page load. Usage:
*
* window.location.href = RCTJSNavigationScheme + '://hello'
*/
extern NSString *const RCTJSNavigationScheme;
@protocol RCTWebViewDelegate <NSObject>
- (BOOL)webView:(RCTWebView *)webView
shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
withCallback:(RCTDirectEventBlock)callback;
@end
@interface RCTWebView : RCTView
@property (nonatomic, weak) id<RCTWebViewDelegate> delegate;
@property (nonatomic, copy) NSDictionary *source;
@property (nonatomic, assign) UIEdgeInsets contentInset;
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
@property (nonatomic, assign) BOOL messagingEnabled;
@property (nonatomic, copy) NSString *injectedJavaScript;
@property (nonatomic, assign) BOOL scalesPageToFit;
- (void)goForward;
- (void)goBack;
- (void)reload;
- (void)stopLoading;
- (void)postMessage:(NSString *)message;
- (void)injectJavaScript:(NSString *)script;
@end

View File

@@ -1,351 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTWebView.h"
#import <UIKit/UIKit.h>
#import "RCTAutoInsetsProtocol.h"
#import "RCTConvert.h"
#import "RCTEventDispatcher.h"
#import "RCTLog.h"
#import "RCTUtils.h"
#import "RCTView.h"
#import "UIView+React.h"
NSString *const RCTJSNavigationScheme = @"react-js-navigation";
static NSString *const kPostMessageHost = @"postMessage";
@interface RCTWebView () <UIWebViewDelegate, RCTAutoInsetsProtocol>
@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
@property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
@property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
@property (nonatomic, copy) RCTDirectEventBlock onMessage;
@end
@implementation RCTWebView
{
UIWebView *_webView;
NSString *_injectedJavaScript;
}
- (void)dealloc
{
_webView.delegate = nil;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
super.backgroundColor = [UIColor clearColor];
_automaticallyAdjustContentInsets = YES;
_contentInset = UIEdgeInsetsZero;
_webView = [[UIWebView alloc] initWithFrame:self.bounds];
_webView.delegate = self;
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
_webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
#endif
[self addSubview:_webView];
}
return self;
}
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
- (void)goForward
{
[_webView goForward];
}
- (void)goBack
{
[_webView goBack];
}
- (void)reload
{
NSURLRequest *request = [RCTConvert NSURLRequest:self.source];
if (request.URL && !_webView.request.URL.absoluteString.length) {
[_webView loadRequest:request];
}
else {
[_webView reload];
}
}
- (void)stopLoading
{
[_webView stopLoading];
}
- (void)postMessage:(NSString *)message
{
NSDictionary *eventInitDict = @{
@"data": message,
};
NSString *source = [NSString
stringWithFormat:@"document.dispatchEvent(new MessageEvent('message', %@));",
RCTJSONStringify(eventInitDict, NULL)
];
[_webView stringByEvaluatingJavaScriptFromString:source];
}
- (void)injectJavaScript:(NSString *)script
{
[_webView stringByEvaluatingJavaScriptFromString:script];
}
- (void)setSource:(NSDictionary *)source
{
if (![_source isEqualToDictionary:source]) {
_source = [source copy];
// Check for a static html source first
NSString *html = [RCTConvert NSString:source[@"html"]];
if (html) {
NSURL *baseURL = [RCTConvert NSURL:source[@"baseUrl"]];
if (!baseURL) {
baseURL = [NSURL URLWithString:@"about:blank"];
}
[_webView loadHTMLString:html baseURL:baseURL];
return;
}
NSURLRequest *request = [RCTConvert NSURLRequest:source];
// Because of the way React works, as pages redirect, we actually end up
// passing the redirect urls back here, so we ignore them if trying to load
// the same url. We'll expose a call to 'reload' to allow a user to load
// the existing page.
if ([request.URL isEqual:_webView.request.URL]) {
return;
}
if (!request.URL) {
// Clear the webview
[_webView loadHTMLString:@"" baseURL:nil];
return;
}
[_webView loadRequest:request];
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
_webView.frame = self.bounds;
}
- (void)setContentInset:(UIEdgeInsets)contentInset
{
_contentInset = contentInset;
[RCTView autoAdjustInsetsForView:self
withScrollView:_webView.scrollView
updateOffset:NO];
}
- (void)setScalesPageToFit:(BOOL)scalesPageToFit
{
if (_webView.scalesPageToFit != scalesPageToFit) {
_webView.scalesPageToFit = scalesPageToFit;
[_webView reload];
}
}
- (BOOL)scalesPageToFit
{
return _webView.scalesPageToFit;
}
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
self.opaque = _webView.opaque = (alpha == 1.0);
_webView.backgroundColor = backgroundColor;
}
- (UIColor *)backgroundColor
{
return _webView.backgroundColor;
}
- (NSMutableDictionary<NSString *, id> *)baseEvent
{
NSMutableDictionary<NSString *, id> *event = [[NSMutableDictionary alloc] initWithDictionary:@{
@"url": _webView.request.URL.absoluteString ?: @"",
@"loading" : @(_webView.loading),
@"title": [_webView stringByEvaluatingJavaScriptFromString:@"document.title"],
@"canGoBack": @(_webView.canGoBack),
@"canGoForward" : @(_webView.canGoForward),
}];
return event;
}
- (void)refreshContentInset
{
[RCTView autoAdjustInsetsForView:self
withScrollView:_webView.scrollView
updateOffset:YES];
}
#pragma mark - UIWebViewDelegate methods
- (BOOL)webView:(__unused UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
BOOL isJSNavigation = [request.URL.scheme isEqualToString:RCTJSNavigationScheme];
static NSDictionary<NSNumber *, NSString *> *navigationTypes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
navigationTypes = @{
@(UIWebViewNavigationTypeLinkClicked): @"click",
@(UIWebViewNavigationTypeFormSubmitted): @"formsubmit",
@(UIWebViewNavigationTypeBackForward): @"backforward",
@(UIWebViewNavigationTypeReload): @"reload",
@(UIWebViewNavigationTypeFormResubmitted): @"formresubmit",
@(UIWebViewNavigationTypeOther): @"other",
};
});
// skip this for the JS Navigation handler
if (!isJSNavigation && _onShouldStartLoadWithRequest) {
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary: @{
@"url": (request.URL).absoluteString,
@"navigationType": navigationTypes[@(navigationType)]
}];
if (![self.delegate webView:self
shouldStartLoadForRequest:event
withCallback:_onShouldStartLoadWithRequest]) {
return NO;
}
}
if (_onLoadingStart) {
// We have this check to filter out iframe requests and whatnot
BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
if (isTopFrame) {
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary: @{
@"url": (request.URL).absoluteString,
@"navigationType": navigationTypes[@(navigationType)]
}];
_onLoadingStart(event);
}
}
if (isJSNavigation && [request.URL.host isEqualToString:kPostMessageHost]) {
NSString *data = request.URL.query;
data = [data stringByReplacingOccurrencesOfString:@"+" withString:@" "];
data = [data stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary: @{
@"data": data,
}];
NSString *source = @"document.dispatchEvent(new MessageEvent('message:received'));";
[_webView stringByEvaluatingJavaScriptFromString:source];
_onMessage(event);
}
// JS Navigation handler
return !isJSNavigation;
}
- (void)webView:(__unused UIWebView *)webView didFailLoadWithError:(NSError *)error
{
if (_onLoadingError) {
if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled) {
// NSURLErrorCancelled is reported when a page has a redirect OR if you load
// a new URL in the WebView before the previous one came back. We can just
// ignore these since they aren't real errors.
// http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
return;
}
if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102) {
// Error code 102 "Frame load interrupted" is raised by the UIWebView if
// its delegate returns FALSE from webView:shouldStartLoadWithRequest:navigationType
// when the URL is from an http redirect. This is a common pattern when
// implementing OAuth with a WebView.
return;
}
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary:@{
@"domain": error.domain,
@"code": @(error.code),
@"description": error.localizedDescription,
}];
_onLoadingError(event);
}
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (_messagingEnabled) {
#if RCT_DEV
// See isNative in lodash
NSString *testPostMessageNative = @"String(window.postMessage) === String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage')";
BOOL postMessageIsNative = [
[webView stringByEvaluatingJavaScriptFromString:testPostMessageNative]
isEqualToString:@"true"
];
if (!postMessageIsNative) {
RCTLogError(@"Setting onMessage on a WebView overrides existing values of window.postMessage, but a previous value was defined");
}
#endif
NSString *source = [NSString stringWithFormat:
@"(function() {"
"window.originalPostMessage = window.postMessage;"
"var messageQueue = [];"
"var messagePending = false;"
"function processQueue() {"
"if (!messageQueue.length || messagePending) return;"
"messagePending = true;"
"window.location = '%@://%@?' + encodeURIComponent(messageQueue.shift());"
"}"
"window.postMessage = function(data) {"
"messageQueue.push(String(data));"
"processQueue();"
"};"
"document.addEventListener('message:received', function(e) {"
"messagePending = false;"
"processQueue();"
"});"
"})();", RCTJSNavigationScheme, kPostMessageHost
];
[webView stringByEvaluatingJavaScriptFromString:source];
}
if (_injectedJavaScript != nil) {
NSString *jsEvaluationValue = [webView stringByEvaluatingJavaScriptFromString:_injectedJavaScript];
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
event[@"jsEvaluationValue"] = jsEvaluationValue;
_onLoadingFinish(event);
}
// we only need the final 'finishLoad' call so only fire the event when we're actually done loading.
else if (_onLoadingFinish && !webView.loading && ![webView.request.URL.absoluteString isEqualToString:@"about:blank"]) {
_onLoadingFinish([self baseEvent]);
}
}
@end

View File

@@ -1,12 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTViewManager.h>
@interface RCTWebViewManager : RCTViewManager
@end

View File

@@ -1,158 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTWebViewManager.h"
#import "RCTBridge.h"
#import "RCTUIManager.h"
#import "RCTWebView.h"
#import "UIView+React.h"
@interface RCTWebViewManager () <RCTWebViewDelegate>
@end
@implementation RCTWebViewManager
{
NSConditionLock *_shouldStartLoadLock;
BOOL _shouldStartLoad;
}
RCT_EXPORT_MODULE()
- (UIView *)view
{
RCTWebView *webView = [RCTWebView new];
webView.delegate = self;
return webView;
}
RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL)
RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL)
RCT_REMAP_VIEW_PROPERTY(decelerationRate, _webView.scrollView.decelerationRate, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(scalesPageToFit, BOOL)
RCT_EXPORT_VIEW_PROPERTY(messagingEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onMessage, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
RCT_REMAP_VIEW_PROPERTY(allowsInlineMediaPlayback, _webView.allowsInlineMediaPlayback, BOOL)
RCT_REMAP_VIEW_PROPERTY(mediaPlaybackRequiresUserAction, _webView.mediaPlaybackRequiresUserAction, BOOL)
RCT_REMAP_VIEW_PROPERTY(dataDetectorTypes, _webView.dataDetectorTypes, UIDataDetectorTypes)
RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWebView *> *viewRegistry) {
RCTWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view goBack];
}
}];
}
RCT_EXPORT_METHOD(goForward:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWebView *> *viewRegistry) {
RCTWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view goForward];
}
}];
}
RCT_EXPORT_METHOD(reload:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWebView *> *viewRegistry) {
RCTWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view reload];
}
}];
}
RCT_EXPORT_METHOD(stopLoading:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWebView *> *viewRegistry) {
RCTWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view stopLoading];
}
}];
}
RCT_EXPORT_METHOD(postMessage:(nonnull NSNumber *)reactTag message:(NSString *)message)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWebView *> *viewRegistry) {
RCTWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view postMessage:message];
}
}];
}
RCT_EXPORT_METHOD(injectJavaScript:(nonnull NSNumber *)reactTag script:(NSString *)script)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTWebView *> *viewRegistry) {
RCTWebView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[RCTWebView class]]) {
RCTLogError(@"Invalid view returned from registry, expecting RCTWebView, got: %@", view);
} else {
[view injectJavaScript:script];
}
}];
}
#pragma mark - Exported synchronous methods
- (BOOL)webView:(__unused RCTWebView *)webView
shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
withCallback:(RCTDirectEventBlock)callback
{
_shouldStartLoadLock = [[NSConditionLock alloc] initWithCondition:arc4random()];
_shouldStartLoad = YES;
request[@"lockIdentifier"] = @(_shouldStartLoadLock.condition);
callback(request);
// Block the main thread for a maximum of 250ms until the JS thread returns
if ([_shouldStartLoadLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:.25]]) {
BOOL returnValue = _shouldStartLoad;
[_shouldStartLoadLock unlock];
_shouldStartLoadLock = nil;
return returnValue;
} else {
RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES");
return YES;
}
}
RCT_EXPORT_METHOD(startLoadWithResult:(BOOL)result lockIdentifier:(NSInteger)lockIdentifier)
{
if ([_shouldStartLoadLock tryLockWhenCondition:lockIdentifier]) {
_shouldStartLoad = result;
[_shouldStartLoadLock unlockWithCondition:0];
} else {
RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: "
"got %lld, expected %lld", (long long)lockIdentifier, (long long)_shouldStartLoadLock.condition);
}
}
@end