Programmatically focus on a form in a webview (WKWebView)

前端 未结 6 1316
说谎
说谎 2020-12-09 03:50

It\'s possible with UIWebView with following:

[webView setKeyboardDisplayRequiresUserAction:NO]
Call some JS function

How can you do the sa

6条回答
  •  离开以前
    2020-12-09 04:34

    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.

提交回复
热议问题