mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-01-12 22:50:10 +08:00
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:
committed by
Facebook Github Bot
parent
06cf7face2
commit
6ca438a7f4
@@ -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"
|
||||
|
||||
@@ -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 */,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user