UIWebView可以实现以下功能:
[webView setKeyboardDisplayRequiresUserAction:NO]
Call some JS function
当webview为WKWebView
时,你怎么能这样做?
相关:How can I get a UIWebView to focus on a form input and bring up the keyboard?
答案 0 :(得分:16)
由于for (let k=0;k<teacherLength;k++) //notice < instead of <=
方法签名已更改,因此已接受的答案在iOS 11.3中不再有效。这是一个解决方法(在Obj-C中):
(更新:方法签名在iOS 12.2中再次更改,以下代码已更新以反映此更改)
WebKit
答案 1 :(得分:7)
这个Swift扩展完成了这项工作,并且与11.3以及早期的版本兼容。
import Foundation
import WebKit
typealias OlderClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Any?) -> Void
typealias NewerClosureType = @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 WKContentViewClass: AnyClass = NSClassFromString("WKContentView") else {
print("Cannot find the WKContentView class")
return
}
let olderSelector: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:")
let newerSelector: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:")
if let method = class_getInstanceMethod(WKContentViewClass, olderSelector) {
let originalImp: IMP = method_getImplementation(method)
let original: OlderClosureType = unsafeBitCast(originalImp, to: OlderClosureType.self)
let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3) in
original(me, olderSelector, arg0, !value, arg2, arg3)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}
if let method = class_getInstanceMethod(WKContentViewClass, newerSelector) {
let originalImp: IMP = method_getImplementation(method)
let original: NewerClosureType = unsafeBitCast(originalImp, to: NewerClosureType.self)
let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in
original(me, newerSelector, arg0, !value, arg2, arg3, arg4)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}
}
}
答案 2 :(得分:5)
在深入了解Webkit源代码几周之后,我已经设法通过_startAssistingNode:userIsInteracting:blurPreviousNode:userObject
上的WKContentView
调整并覆盖userIsInteracting值来设法在iOS 9上运行:
伪代码:
swizzle_intercept("WKContentView", "_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:", &hackAssist);
void hackAssist (id self, SEL _cmd, void* arg0, BOOL arg1, BOOL arg2, id arg3) {
((void (*)(id,SEL,void*,BOOL,BOOL,id))swizzle_interceptee(hackAssist))(self, _cmd, arg0, TRUE, arg2, arg3);
}
干杯!
答案 3 :(得分:5)
更新:此解决方案适用于iOS 12.2,11 *和10。*
我写了一个扩展(在Swift 4中为web.config
类添加WKWebView
作为计算属性,就像在UIWebView中一样。
在参考Apple的WebKit官方开源文档后,我提出了以下运行时调优:
keyboardDisplayRequiresUserAction
确保您在WKWebView上调用属性,
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:")
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)
}
}
}
此外,请确保您的HTML TextArea element 自动对焦设置为let webView = WKWebView()
webView.keyboardDisplayRequiresUserAction = false
,否则无法正常工作。
答案 4 :(得分:4)
我不得不将@Mark's answer从扩展名更改为子类,因为Swift 4.2在keyboardDisplayRequiresUserAction
getter上给了我“通过此函数的所有路径都将自行调用”的警告。
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
class WebView: WKWebView {
private var _keyboardDisplayRequiresUseraction = true
var keyboardDisplayRequiresUserAction: Bool? {
get {
return _keyboardDisplayRequiresUseraction
}
set {
_keyboardDisplayRequiresUseraction = newValue ?? true
setKeyboardRequiresUserInteraciton(_keyboardDisplayRequiresUseraction)
}
}
private func setKeyboardRequiresUserInteraciton(_ value: Bool) {
guard let WKContentViewClass: AnyClass = NSClassFromString("WKContentView") else {
return print("Cannot find WKContentView class")
}
let oldSelector: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:")
let newSelector: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:")
if let method = class_getInstanceMethod(WKContentViewClass, oldSelector) {
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, oldSelector, arg0, !value, arg2, arg3)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}
if let method = class_getInstanceMethod(WKContentViewClass, newSelector) {
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, newSelector, arg0, !value, arg2, arg3, arg4)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}
}
}
在iOS 11.2和12.0上测试
答案 5 :(得分:1)
随着方法的再次更改,更新了iOS 12.2:
Objective-C
#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};
char * methodSignature = "_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:";
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_12_2_0]) {
methodSignature = "_elementDidFocus:userIsInteracting:blurPreviousNode:changingActivityState:userObject:";
}
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_11_3_0]) {
SEL selector = sel_getUid(methodSignature);
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
迅速:
func setKeyboardRequiresUserInteraction( _ value: Bool) {
guard
let WKContentViewClass: AnyClass = NSClassFromString("WKContentView") else {
print("Cannot find the WKContentView class")
return
}
let olderSelector: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:userObject:")
let newSelector: Selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:")
let newerSelector: Selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:changingActivityState:userObject:")
if let method = class_getInstanceMethod(WKContentViewClass, olderSelector) {
let originalImp: IMP = method_getImplementation(method)
let original: OlderClosureType = unsafeBitCast(originalImp, to: OlderClosureType.self)
let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3) in
original(me, olderSelector, arg0, !value, arg2, arg3)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}
if let method = class_getInstanceMethod(wkc, newSelector) {
self.swizzleAutofocusMethod(method, newSelector, value)
}
if let method = class_getInstanceMethod(wkc, newerSelector) {
self.swizzleAutofocusMethod(method, newerSelector, value)
}
}
func swizzleAutofocusMethod(_ method: Method, _ selector: Selector, _ value: Bool) {
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, selector, arg0, !value, arg2, arg3, arg4)
}
let imp: IMP = imp_implementationWithBlock(block)
method_setImplementation(method, imp)
}
答案 6 :(得分:0)
@jcesarmobile 的 P.S 答案,该答案适用于以下平台:iPhone SE 1 iOS 14.1、iPhone 6s 以及 iOS 14.4.2;
对于那些遭受跳跃或大小不匹配的人,当第二次加载混合的WKWebview中的内容时; 您可以使用下面的示例避免上述混乱:
setTimeout(function(){
document.getElementById("myTextElementId").focus();
},250);
/* 在 mount 或 onload 方法中;*/
想一想:为什么第二次出现烂摊子? 可能是这样:webview第一次缓存css样式和文件,所以第二次webview加载内容更快;键盘直接跳出来,同时窗口大小合适,渲染等;所以混乱就出来了;这就是为什么我们需要延迟;