使用Swift在iOS WKWebview中捕获Javascript事件

29

我正在使用网页编程语言构建一个应用程序,并希望在用户点击HTML按钮时启动摄像头。由于我想要我的相机视图是一种自定义的,所以我需要使用Swift进行设计。因此,当用户点击此HTML按钮时,我想要在Swift中“捕获”此点击事件,以便我可以启动本地相机视图。

我知道可以使用WKWebview完成这个操作,但我不太清楚如何做到这一点。

例如,我的Javascript(jQuery)代码可能是这样的:

// User clicks to start the native camera with Swift
$(".camera_button").click(function() {
    // Function to call the camera view from JS to Swift
});

你能帮我做到那个吗?

谢谢。

3个回答

42

参考了@Alex Pelletier的答案后,我得到了很大的帮助,下面是解决我的问题的方法。

在我的“loadView()”函数中,以下是我的代码:

let contentController = WKUserContentController();
contentController.addScriptMessageHandler(
    self,
    name: "callbackHandler"
)

let config = WKWebViewConfiguration()
config.userContentController = contentController

webView = WKWebView(frame: CGRectZero, configuration: config)
webView.navigationDelegate = self
view = webView

处理发送到Swift的Javascript事件的函数:

func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage)
    {
        if(message.name == "callbackHandler") {
            print("Launch my Native Camera")
        }
    }

最后,当我的摄像头按钮(在HTML中)被点击时,我的JavaScript(jQuery)代码如下:

$(document).ready(function() {

    function callNativeApp () {
        try {
            webkit.messageHandlers.callbackHandler.postMessage("camera");
        } catch(err) {
            console.log('The native context does not exist yet');
        }
    }

    $(".menu-camera-icon").click(function() {
        callNativeApp();
    });
});

希望能对其他人有所帮助 :-) !


非常好,非常感谢!你有什么提示/解决方案可以获取相机并将每个图像发送回JS吗? - HR123
@HR123 我认为最好的方法是从本地iOs代码(Objective-C或Swift)处理相机视图,将其上传到某个地方(例如Amazon S3),获取已上传的URL并将此URL发送回JS;-)。 - fraxool
1
这非常有帮助。谢谢@fraxool! - Zack Shapiro

15

首先,让我们创建一个JS文件。在JS中,当您点击了一个元素,您可以发送如下消息:

varmessageToPost = {'ButtonId':'clickMeButton'};
window.webkit.messageHandlers.buttonClicked.postMessage(messageToPost);

在创建js文件和wkwebview后,您需要注入脚本:

  // Setup WKUserContentController instance for injecting user script
  var userController:WKUserContentController= WKUserContentController()

  // Get script that's to be injected into the document
  let js:String= GetScriptFromResources()

  // Specify when and where and what user script needs to be injected into the web document
  var userScript:WKUserScript =  WKUserScript(source: js,
                                         injectionTime: WKUserScriptInjectionTime.AtDocumentEnd
                                         forMainFrameOnly: false)

  // Add the user script to the WKUserContentController instance
  userController.addUserScript(userScript)

  // Configure the WKWebViewConfiguration instance with the WKUserContentController
  webCfg.userContentController= userController;

  //set the message handler
  userController.addScriptMessageHandler(self, name: "buttonClicked")  

最后您需要添加监听器函数:

func userContentController(userContentController: WKUserContentController,
                           didReceiveScriptMessage message: WKScriptMessage) {

        if let messageBody:NSDictionary= message.body as? NSDictionary{
            // Do stuff with messageBody
        }

    }

源代码


1
非常感谢您。您的回答真的帮了我很多。我将发布完整的解决方案来回答我的问题。 - fraxool
@fraxool 如果这个答案真的对你有帮助,请接受它。 - Nazmul Hasan

0

首先,设置HTML字符串:

var playerURL = """"
    https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/\(trackId)%3Fsecret_token%3D\(secretToken)&auto_play=false&hide_related=true&show_comments=false&show_user=false&show_reposts=false&show_teaser=false&visual=false
"""

其次,创建您的WKWebView并进行配置

private var webView: WKWebView?

override func awakeFromNib() {
    super.awakeFromNib()
    
    ...(1)...
    
    self.webView?.navigationDelegate = self
    self.webView?.isUserInteractionEnabled = true
    self.webView?.scrollView.isScrollEnabled = false
    self.webView?.allowsLinkPreview  = false
    self.webView?.contentMode = .scaleAspectFit
    self.webView?.loadHTMLString(self.playerUrl, baseURL: nil)

    DispatchQueue.main.async {
        self.webView = WKWebView(frame: self.viewSoundclound.bounds, configuration: config)
        guard let webView = self.webView else { return }
        self.viewSoundclound.addSubview(webView)
    }
}

第三步,设置你要添加到WKWebViewJavasScript脚本的配置。

 override func awakeFromNib() {
    super.awakeFromNib()
    let config = WKWebViewConfiguration()
    let script = WKUserScript(source: self.eventListenerScript, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
    config.userContentController.addUserScript(script)
    config.userContentController.add(self, name: "soundCloundEvents")

    ...(2)...
}

接下来,创建你的脚本。重要提示:在'messageHandler.(name).postMessage'中的名称必须与此行中的名称相同:

'config.userContentController.add(self, name: "soundCloundEvents")'

private var eventListenerScript = """
    var iframe = document.querySelector('iframe');
    widget = SC.Widget(iframe);
    widget.bind(SC.Widget.Events.PLAY, function() {
        window.webkit.messageHandlers.soundCloundEvents.postMessage('PLAY');
    });
    widget.bind(SC.Widget.Events.FINISH, function() {
        window.webkit.messageHandlers.soundCloundEvents.postMessage('FINISH');
    });
"""

最后,扩展Controller或Cell(在这种情况下)以侦听脚本。
extension PodcastsListTableViewCell: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    print(message)
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接