feat(WKWebView): Allow focus without user interaction (#540)

* [iOS] Allow focus without user interaction

* Add documentation for keyboardDisplayRequiresUserAction

* set keyboardDisplayRequiresUserAction default to true
This commit is contained in:
Eric Lewis 2019-04-29 11:46:07 -04:00 committed by Thibault Malbranche
parent c297e320d2
commit 455c30e000
5 changed files with 89 additions and 0 deletions

View File

@ -42,6 +42,7 @@ This document lays out the current public properties and methods for the React N
- [`useWebKit`](Reference.md#usewebkit)
- [`url`](Reference.md#url)
- [`html`](Reference.md#html)
- [`keyboardDisplayRequiresUserAction`](Reference.md#keyboardDisplayRequiresUserAction)
- [`hideKeyboardAccessoryView`](Reference.md#hidekeyboardaccessoryview)
- [`allowsBackForwardNavigationGestures`](Reference.md#allowsbackforwardnavigationgestures)
- [`incognito`](Reference.md#incognito)
@ -756,6 +757,16 @@ If true, use WKWebView instead of UIWebView.
---
### `keyboardDisplayRequiresUserAction`
If false, web content can programmatically display the keyboard when using the WKWebView. The default value is `true`.
| Type | Required | Platform |
| ------- | -------- | -------- |
| boolean | No | iOS |
---
### `hideKeyboardAccessoryView`
If true, this will hide the keyboard accessory view (< > and Done) when using the WKWebView.

View File

@ -37,6 +37,7 @@
#endif
@property (nonatomic, assign) UIEdgeInsets contentInset;
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
@property (nonatomic, assign) BOOL keyboardDisplayRequiresUserAction;
@property (nonatomic, assign) BOOL hideKeyboardAccessoryView;
@property (nonatomic, assign) BOOL allowsBackForwardNavigationGestures;
@property (nonatomic, assign) BOOL incognito;

View File

@ -41,6 +41,7 @@ static NSURLCredential* clientAuthenticationCredential;
{
UIColor * _savedBackgroundColor;
BOOL _savedHideKeyboardAccessoryView;
BOOL _savedKeyboardDisplayRequiresUserAction;
}
- (instancetype)initWithFrame:(CGRect)frame
@ -54,6 +55,7 @@ static NSURLCredential* clientAuthenticationCredential;
_directionalLockEnabled = YES;
_automaticallyAdjustContentInsets = YES;
_contentInset = UIEdgeInsetsZero;
_savedKeyboardDisplayRequiresUserAction = YES;
}
// Workaround for a keyboard dismissal bug present in iOS 12
@ -214,6 +216,7 @@ static NSURLCredential* clientAuthenticationCredential;
[self addSubview:_webView];
[self setHideKeyboardAccessoryView: _savedHideKeyboardAccessoryView];
[self setKeyboardDisplayRequiresUserAction: _savedKeyboardDisplayRequiresUserAction];
[self visitSource];
}
}
@ -364,6 +367,64 @@ static NSURLCredential* clientAuthenticationCredential;
}
}
-(void)setKeyboardDisplayRequiresUserAction:(BOOL)keyboardDisplayRequiresUserAction
{
if (_webView == nil) {
_savedKeyboardDisplayRequiresUserAction = keyboardDisplayRequiresUserAction;
return;
}
if (_savedKeyboardDisplayRequiresUserAction == true) {
return;
}
UIView* subview;
for (UIView* view in _webView.scrollView.subviews) {
if([[view.class description] hasPrefix:@"WK"])
subview = view;
}
if(subview == nil) return;
Class class = subview.class;
NSOperatingSystemVersion iOS_11_3_0 = (NSOperatingSystemVersion){11, 3, 0};
NSOperatingSystemVersion iOS_12_2_0 = (NSOperatingSystemVersion){12, 2, 0};
Method method;
IMP override;
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_12_2_0]) {
// iOS 12.2.0 - Future
SEL selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:changingActivityState:userObject:");
method = class_getInstanceMethod(class, selector);
IMP original = method_getImplementation(method);
override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
});
}
else if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_11_3_0]) {
// iOS 11.3.0 - 12.2.0
SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:");
method = class_getInstanceMethod(class, selector);
IMP original = method_getImplementation(method);
override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, BOOL arg3, id arg4) {
((void (*)(id, SEL, void*, BOOL, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3, arg4);
});
} else {
// iOS 9.0 - 11.3.0
SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:");
method = class_getInstanceMethod(class, selector);
IMP original = method_getImplementation(method);
override = imp_implementationWithBlock(^void(id me, void* arg0, BOOL arg1, BOOL arg2, id arg3) {
((void (*)(id, SEL, void*, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3);
});
}
method_setImplementation(method, override);
}
-(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView
{
if (_webView == nil) {

View File

@ -101,6 +101,10 @@ RCT_CUSTOM_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL, RNCWKWebView) {
view.showsVerticalScrollIndicator = json == nil ? true : [RCTConvert BOOL: json];
}
RCT_CUSTOM_VIEW_PROPERTY(keyboardDisplayRequiresUserAction, BOOL, RNCWKWebView) {
view.keyboardDisplayRequiresUserAction = json == nil ? true : [RCTConvert BOOL: json];
}
RCT_EXPORT_METHOD(injectJavaScript:(nonnull NSNumber *)reactTag script:(NSString *)script)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RNCWKWebView *> *viewRegistry) {

View File

@ -403,6 +403,18 @@ export interface IOSWebViewProps extends WebViewSharedProps {
*/
directionalLockEnabled?: boolean;
/**
* A Boolean value indicating whether web content can programmatically display the keyboard.
*
* When this property is set to true, the user must explicitly tap the elements in the
* web view to display the keyboard (or other relevant input view) for that element.
* When set to false, a focus event on an element causes the input view to be displayed
* and associated with that element automatically.
*
* The default value is `true`.
* @platform ios
*/
keyboardDisplayRequiresUserAction?: boolean;
}
export interface AndroidWebViewProps extends WebViewSharedProps {