diff --git a/README.md b/README.md index 2c015b10..705e524d 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,10 @@ You can also use the `require` syntax (sendCookies and userAgent will be ignored Set a custom user agent for WKWebView. Note this only works on iOS 9+. Previous version will simply ignore this props. +- **inputAccessoryViewID** + +An optional identifier which links a React Native [InputAccessoryView](https://facebook.github.io/react-native/docs/inputaccessoryview) to this webview. The InputAccessoryView is rendered above the keyboard when this webview is focused. + - **hideKeyboardAccessoryView** This will hide the keyboard accessory view (`<` `>` and `Done`). Default is false. diff --git a/WKWebView.ios.js b/WKWebView.ios.js index a24024a2..66e73681 100644 --- a/WKWebView.ios.js +++ b/WKWebView.ios.js @@ -237,6 +237,13 @@ class WKWebView extends React.Component { * of new window. Default is false to be backward compatible. */ openNewWindowInWebView: PropTypes.bool, + /** + * An optional identifier which links a custom InputAccessoryView to + * this webview. The InputAccessoryView is rendered above the + * keyboard when this webview is focused. + * @platform ios + */ + inputAccessoryViewID: PropTypes.string, /** * Hide the accessory view when the keyboard is open. Default is false to be * backward compatible. @@ -354,6 +361,7 @@ class WKWebView extends React.Component { allowsBackForwardNavigationGestures={this.props.allowsBackForwardNavigationGestures} automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets} openNewWindowInWebView={this.props.openNewWindowInWebView} + inputAccessoryViewID={this.props.inputAccessoryViewID} hideKeyboardAccessoryView={this.props.hideKeyboardAccessoryView} keyboardDisplayRequiresUserAction={this.props.keyboardDisplayRequiresUserAction} allowsLinkPreview={this.props.allowsLinkPreview} diff --git a/ios/RCTWKWebView/CRAWKWebView.h b/ios/RCTWKWebView/CRAWKWebView.h index fe6e2346..acdd2e9d 100644 --- a/ios/RCTWKWebView/CRAWKWebView.h +++ b/ios/RCTWKWebView/CRAWKWebView.h @@ -3,6 +3,7 @@ #import @class CRAWKWebView; +@class RCTBridge; /** * Special scheme used to pass messages to the injectedJavaScript @@ -24,6 +25,7 @@ shouldStartLoadForRequest:(NSMutableDictionary *)request - (instancetype)initWithProcessPool:(WKProcessPool *)processPool; +@property (nonatomic, weak) RCTBridge *bridge; @property (nonatomic, weak) id delegate; @property (nonatomic, copy) NSDictionary *source; @@ -36,10 +38,10 @@ shouldStartLoadForRequest:(NSMutableDictionary *)request @property (nonatomic, assign) BOOL injectedJavaScriptForMainFrameOnly; @property (nonatomic, copy) NSString *injectJavaScript; @property (nonatomic, copy) NSString *injectedJavaScript; +@property (nonatomic, copy) NSString *inputAccessoryViewID; @property (nonatomic, assign) BOOL hideKeyboardAccessoryView; @property (nonatomic, assign) BOOL keyboardDisplayRequiresUserAction; - - (void)goForward; - (void)goBack; - (BOOL)canGoBack; diff --git a/ios/RCTWKWebView/CRAWKWebView.m b/ios/RCTWKWebView/CRAWKWebView.m index fdc27ce3..33e99fd9 100644 --- a/ios/RCTWKWebView/CRAWKWebView.m +++ b/ios/RCTWKWebView/CRAWKWebView.m @@ -5,22 +5,28 @@ #import #import +#import #import #import #import +#import #import #import #import #import -// runtime trick to remove WKWebView keyboard default toolbar +// runtime trick to remove or replace WKWebView keyboard default toolbar // see: http://stackoverflow.com/questions/19033292/ios-7-uiwebview-keyboard-issue/19042279#19042279 @interface _SwizzleHelperWK : NSObject @end @implementation _SwizzleHelperWK -(id)inputAccessoryView { - return nil; + UIView *webView = (UIView *)self; + while (webView && ![webView isKindOfClass:[CRAWKWebView class]]) { + webView = webView.superview; + } + return webView.inputAccessoryView; } @end @@ -37,6 +43,7 @@ @interface CRAWKWebView () *)changedProps +{ + if ([changedProps containsObject:@"inputAccessoryViewID"] && self.inputAccessoryViewID) { + [self setCustomInputAccessoryViewWithNativeID:self.inputAccessoryViewID]; + } else if (!self.inputAccessoryViewID) { + self.inputAccessoryView = nil; + } +} + - (void)setInjectJavaScript:(NSString *)injectJavaScript { _injectJavaScript = injectJavaScript; self.atStartScript = [[WKUserScript alloc] initWithSource:injectJavaScript @@ -174,12 +190,36 @@ -(void)setAllowsLinkPreview:(BOOL)allowsLinkPreview } } +- (void)setCustomInputAccessoryViewWithNativeID:(NSString *)nativeID +{ +#if !TARGET_OS_TV + __weak CRAWKWebView *weakSelf = self; + [self.bridge.uiManager rootViewForReactTag:self.reactTag withCompletion:^(UIView *rootView) { + CRAWKWebView *strongSelf = weakSelf; + if (rootView) { + UIView *accessoryView = [strongSelf.bridge.uiManager viewForNativeID:nativeID + withRootTag:rootView.reactTag]; + // For backwards compatibility with React Native 0.55.4, use the content view. + if ([accessoryView respondsToSelector:@selector(content)]) { + accessoryView = [accessoryView valueForKey:@"content"]; + } + if ([accessoryView respondsToSelector:@selector(inputAccessoryView)]) { + [strongSelf swizzleWebView]; + strongSelf.inputAccessoryView = [accessoryView valueForKey:@"inputAccessoryView"]; + } + } + }]; +#endif /* !TARGET_OS_TV */ +} + -(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView { - if (!hideKeyboardAccessoryView) { - return; - } - + [self swizzleWebView]; + self.inputAccessoryView.hidden = hideKeyboardAccessoryView; +} + +- (void)swizzleWebView +{ UIView* subview; for (UIView* view in _webView.scrollView.subviews) { if([[view.class description] hasPrefix:@"WKContent"]) diff --git a/ios/RCTWKWebView/CRAWKWebViewManager.m b/ios/RCTWKWebView/CRAWKWebViewManager.m index fcd88f3b..76ea21b0 100644 --- a/ios/RCTWKWebView/CRAWKWebViewManager.m +++ b/ios/RCTWKWebView/CRAWKWebViewManager.m @@ -44,6 +44,7 @@ @implementation CRAWKWebViewManager - (UIView *)view { CRAWKWebView *webView = [[CRAWKWebView alloc] initWithProcessPool:[WKProcessPool sharedProcessPool]]; + webView.bridge = self.bridge; webView.delegate = self; return webView; } @@ -69,6 +70,7 @@ - (UIView *)view RCT_EXPORT_VIEW_PROPERTY(onProgress, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onMessage, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock) +RCT_EXPORT_VIEW_PROPERTY(inputAccessoryViewID, NSString) RCT_EXPORT_VIEW_PROPERTY(hideKeyboardAccessoryView, BOOL) RCT_EXPORT_VIEW_PROPERTY(keyboardDisplayRequiresUserAction, BOOL) RCT_EXPORT_VIEW_PROPERTY(messagingEnabled, BOOL)