It's possible with UIWebView with following:
[webView setKeyboardDisplayRequiresUserAction:NO] Call some JS function
How can you do the same when the webview is WKWebView
instead?
related: How can I get a UIWebView to focus on a form input and bring up the keyboard?
The accepted answer no longer works in iOS 11.3, since WebKit
method signature has changed. Here is a workaround (in Obj-C):
(UPDATE: Method signature has changed a few more times in iOS 12.2 and iOS 13, code below has been updated to reflect these changes)
#import <objc/runtime.h> @implementation WebViewInjection + (void)allowDisplayingKeyboardWithoutUserAction { Class class = NSClassFromString(@"WKContentView"); NSOperatingSystemVersion iOS_11_3_0 = (NSOperatingSystemVersion){11, 3, 0}; NSOperatingSystemVersion iOS_12_2_0 = (NSOperatingSystemVersion){12, 2, 0}; NSOperatingSystemVersion iOS_13_0_0 = (NSOperatingSystemVersion){13, 0, 0}; if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_13_0_0]) { SEL selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:"); Method method = class_getInstanceMethod(class, selector); IMP original = method_getImplementation(method); IMP 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); }); method_setImplementation(method, override); } else if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_12_2_0]) { SEL selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:changingActivityState:userObject:"); Method method = class_getInstanceMethod(class, selector); IMP original = method_getImplementation(method); IMP 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); }); method_setImplementation(method, override); } else if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_11_3_0]) { SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:"); Method method = class_getInstanceMethod(class, selector); IMP original = method_getImplementation(method); IMP 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); }); method_setImplementation(method, override); } else { SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:"); Method method = class_getInstanceMethod(class, selector); IMP original = method_getImplementation(method); IMP 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); } } @end
Update: This solution works for iOS 13.0, 12.2, 11.* and 10.* Also, works on iPadOS 13.1
I wrote an extension (in Swift 4 for WKWebView
class that adds keyboardDisplayRequiresUserAction
as a computed property, just like in UIWebView.
After referring to the Apple’s official open source documents for WebKit, I came up with the following runtime swizzling:
import Foundation import WebKit typealias OldClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void typealias NewClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void extension WKWebView{ var keyboardDisplayRequiresUserAction: Bool? { get { return self.keyboardDisplayRequiresUserAction } set { self.setKeyboardRequiresUserInteraction(newValue ?? true) } } func setKeyboardRequiresUserInteraction( _ value: Bool) { guard let WKContentView: AnyClass = NSClassFromString("WKContentView") else { print("keyboardDisplayRequiresUserAction extension: Cannot find the WKContentView class") return } // For iOS 10, * let sel_10: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:") // For iOS 11.3, * let sel_11_3: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:") // For iOS 12.2, * let sel_12_2: Selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:changingActivityState:userObject:") // For iOS 13.0, * let sel_13_0: Selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:") if let method = class_getInstanceMethod(WKContentView, sel_10) { let originalImp: IMP = method_getImplementation(method) let original: OldClosureType = unsafeBitCast(originalImp, to: OldClosureType.self) let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3) in original(me, sel_10, arg0, !value, arg2, arg3) } let imp: IMP = imp_implementationWithBlock(block) method_setImplementation(method, imp) } if let method = class_getInstanceMethod(WKContentView, sel_11_3) { let originalImp: IMP = method_getImplementation(method) let original: NewClosureType = unsafeBitCast(originalImp, to: NewClosureType.self) let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in original(me, sel_11_3, arg0, !value, arg2, arg3, arg4) } let imp: IMP = imp_implementationWithBlock(block) method_setImplementation(method, imp) } if let method = class_getInstanceMethod(WKContentView, sel_12_2) { let originalImp: IMP = method_getImplementation(method) let original: NewClosureType = unsafeBitCast(originalImp, to: NewClosureType.self) let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in original(me, sel_12_2, arg0, !value, arg2, arg3, arg4) } let imp: IMP = imp_implementationWithBlock(block) method_setImplementation(method, imp) } if let method = class_getInstanceMethod(WKContentView, sel_13_0) { let originalImp: IMP = method_getImplementation(method) let original: NewClosureType = unsafeBitCast(originalImp, to: NewClosureType.self) let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in original(me, sel_13_0, arg0, !value, arg2, arg3, arg4) } let imp: IMP = imp_implementationWithBlock(block) method_setImplementation(method, imp) } } }
Make sure you call property on your WKWebView like this,
let webView = WKWebView() webView.keyboardDisplayRequiresUserAction = false
Also, make sure your HTML TextArea element has AutoFocus set to true
otherwise this won't work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With