细谈hybrid模式中js与ios交互

JavaScriptCore(适用于UIWebview,具有模块化思想)

JavaScriptCore库里主要包括JSContext、JSValue、JSExport等几个一般使用的就是列举的三个。关键有两步:获取js的运行上下文,将继承JSExport的模块注入js。JSContext是js的运行上下文,用来执行js代码;JSValue是JSContext执行后的返回结果,JSExport是用来将native对象暴漏给js。

  • 从native调用js
jsContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as? JSContext
jsContext.evaluateScript("var a = 1;")
jsContext?.objectForKeyedSubscript("jsMethod")
  • 从js调用native函数
    利用JSExport是一个协议,通过实现它可以完成把一个native对象暴漏给js,就可以用js来调用native
@objc protocol BridgeDelegate: JSExport {
    func jsCallNative(_ arg: String)    
}

WKScriptMessageHandler(适用于WKWebview,没有模块化思想)

WKScriptMessageHandler 是一个协议,这个协议提供一个方法可以接收 JS 传过来的消息,这个协议方法里面有两个类 WKScriptMessage(包含方法名以及参数) 和 WKUserContentController(调用方法)。

//可以理解为注册方法以便js调用
func add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)
//用于接受js消息调用native方法
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        switch message.name {
        }
}

一个使用广泛的第三方轮子WebViewJavascriptBridge

简介:WebViewJavascriptBridge适用于UIWebview与WKWebview,他通过webview的代理拦截特定的scheme。

  • 首先三重判断
    //是否来自该库的消息
    if ([_base isWebViewJavascriptBridgeURL:url]) {
   //是否以及注入js
        if ([_base isBridgeLoadedURL:url]) {
            [_base injectJavascriptFile];
   //是否是要处理的消息
        } else if ([_base isQueueMessageURL:url]) {
            [self WKFlushMessageQueue];
  • 执行js获取消息字符串,剖析消息
  • 通过messageHandlers来执行消息,利用callbackID来进行回掉
        //设置回调
          WVJBResponseCallback responseCallback = NULL;
            NSString* callbackId = message[@"callbackId"];
            if (callbackId) {
                responseCallback = ^(id responseData) {
                    if (responseData == nil) {
                        responseData = [NULL];
                    }
                    WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData };
                    //执行js根据callbackId执行对应的回调
                    [self _queueMessage:msg];
                };
            }
          //根据之前注册的处理函数进行处理
            WVJBHandler handler = self.messageHandlers[message[@"handlerName"]];
            if (!handler) {
                NSLog(@"WVJBNoHandlerException, No handler for message from JS: %@", message);
                continue;
            }
            
            handler(message[@"data"], responseCallback);

里面还有很多细节,网上资料众多这里不进行赘述有问题可以留言一起探讨。总体来说就是WebViewJavascriptBridge是截获Webview的代理方法,执行js获取js调用native的消息再通过函数名称调用注册的函数。它的callbackid,注册的函数等是通过数组、字典保存起来了因此可以省去反射的步骤。整体还是比较繁琐没有模块化管理。


最后我们可以举一反三以下是我的一个列子

  • 从native调用js直接使用
self.AS_WKWebview?.evaluateJavaScript(item, completionHandler: nil)
  • 从js调用native函数
    总体流程应该是这样的:
  • 约定好规范,名称,模块
  • native端注入js使得web端可以通过模块名加方法名发出讯号
  • web发出讯号(常用的有alert、confirm、Prompt)
  • native端拦截讯号判断是需要处理还是正常执行
  • 对讯号进行解析判断模块名、方法名、参数合法性(包括回调函数)
  • 利用反射执行方法、调用回调函数
  • 自己还可以进行其他的处理比如白名单、权限处理

由于只是讲了流程很多地方没有讲清楚,欢迎大家留言一起探讨细节。

你可能感兴趣的:(细谈hybrid模式中js与ios交互)