UIWebView可以使用以下内容:
[webView setKeyboardDisplayRequiresUserAction:NO]
Call some JS function
Run Code Online (Sandbox Code Playgroud)
WKWebView相反,如何在webview中执行相同的操作?
Ale*_*tau 24
由于WebKit方法签名已更改,因此接受的答案在iOS 11.3下不再有效.这是一个解决方法(在Obj-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};
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
Run Code Online (Sandbox Code Playgroud)
Pra*_*kar 14
更新:此解决方案适用于iOS 13.0、12.2、11。*和10. *。此外,该解决方案还适用于iPadOS 13.1。
我写了一个扩展(在Swift 4中为WKWebView类添加了keyboardDisplayRequiresUserAction一个计算属性,就像在UIWebView中一样)。
在参考了Apple的WebKit官方开源文档之后,我想到了以下运行时问题:
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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
确保像这样在WKWebView上调用媒体资源,
let webView = WKWebView()
webView.keyboardDisplayRequiresUserAction = false
Run Code Online (Sandbox Code Playgroud)
另外,请确保您的HTML TextArea元素将AutoFocus设置为,true否则将无法使用。
这个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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
深入挖掘WebKit的来源了几个星期后,我已经成功通过交叉混合以获得在iOS 9这个工作_startAssistingNode:userIsInteracting:blurPreviousNode:userObject就WKContentView和重写userIsInteracting值:
伪代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
干杯!
我不得不将@Mark 的答案从扩展更改为子类,因为 Swift 4.2 在keyboardDisplayRequiresUserActiongetter上给了我“通过此函数的所有路径都将调用自身”警告。
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
setKeyboardRequiresUserInteraction(_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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
在 iOS 11.2 和 12.0 上测试
随着方法再次更改,针对 iOS 13 进行更新:
目标-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};
NSOperatingSystemVersion iOS_13_0_0 = (NSOperatingSystemVersion){13, 0, 0};
char * methodSignature = "_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:";
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_13_0_0]) {
methodSignature = "_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:";
} else 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
Run Code Online (Sandbox Code Playgroud)
迅速:
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:")
let ios13Selector: Selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges: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)
}
if let method = class_getInstanceMethod(wkc, ios13Selector) {
self.swizzleAutofocusMethod(method, ios13Selector, 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)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7753 次 |
| 最近记录: |