Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 8 additions & 0 deletions WKWebView.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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}
Expand Down
4 changes: 3 additions & 1 deletion ios/RCTWKWebView/CRAWKWebView.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#import <React/RCTView.h>

@class CRAWKWebView;
@class RCTBridge;

/**
* Special scheme used to pass messages to the injectedJavaScript
Expand All @@ -24,6 +25,7 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request

- (instancetype)initWithProcessPool:(WKProcessPool *)processPool;

@property (nonatomic, weak) RCTBridge *bridge;
@property (nonatomic, weak) id<CRAWKWebViewDelegate> delegate;

@property (nonatomic, copy) NSDictionary *source;
Expand All @@ -36,10 +38,10 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)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;
Expand Down
52 changes: 46 additions & 6 deletions ios/RCTWKWebView/CRAWKWebView.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,28 @@
#import <UIKit/UIKit.h>

#import <React/RCTAutoInsetsProtocol.h>
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTLog.h>
#import <React/RCTUIManager.h>
#import <React/RCTUtils.h>
#import <React/RCTView.h>
#import <React/UIView+React.h>

#import <objc/runtime.h>

// 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

Expand All @@ -37,6 +43,7 @@ @interface CRAWKWebView () <WKNavigationDelegate, RCTAutoInsetsProtocol, WKScrip
@property (assign) BOOL sendCookies;
@property (nonatomic, strong) WKUserScript *atStartScript;
@property (nonatomic, strong) WKUserScript *atEndScript;
@property (nonatomic, strong) UIView *inputAccessoryView;

@end

Expand Down Expand Up @@ -91,6 +98,15 @@ - (instancetype)initWithProcessPool:(WKProcessPool *)processPool
return self;
}

- (void)didSetProps:(NSArray<NSString *> *)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
Expand Down Expand Up @@ -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"])
Expand Down
2 changes: 2 additions & 0 deletions ios/RCTWKWebView/CRAWKWebViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ @implementation CRAWKWebViewManager
- (UIView *)view
{
CRAWKWebView *webView = [[CRAWKWebView alloc] initWithProcessPool:[WKProcessPool sharedProcessPool]];
webView.bridge = self.bridge;
webView.delegate = self;
return webView;
}
Expand All @@ -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)
Expand Down