Interaction between web and Js in iOS

  • problem

    Feeling that the uni-app framework has a pit, the company’s brother who pushed the framework forcibly shuts up. Considering that the overall replacement cycle and cost are quite large, it can be packaged into H5 based on uni-app, and integrated in the native way of webview+js.

    Basic structure: native shell + webview[iOS & Android] + js

  • Program

    After determining the basic framework, the main problem is the interaction between web and js, limited to technical capabilities, only the iOS direction

    First of all, UIWebView is not used much, it is already iOS14+, if you use UIWebView to not be dissed, probably your team will be like that, and its corresponding interaction framework is JavaScriptCore. Pass does not speak

    Third, the redirected url can be intercepted and parsed, and the original method can be called with the agreed key/value. This interactive method meets simple functional requirements, and only the web can invoke iOS calls, depending on the situation.

    Then, in WKWebview, JS calls the native method through the WKScriptMessageHandler protocol, the core is: window.webkit.messageHandlers. Method name.postMessage (parameter), native calling JS is much simpler, the core is: [weblview evaluateJavaScript:xxx completionHandler: ^( id object, NSError * _Nullable error) {}];

    As above: What if there is asynchronous operation? Wouldn't it be better if the block was implemented?

    Finally: WebViewJavascriptBridge, come on, you deserve it

  • Analyze
    1.js call native method

    - html中web中按钮点击,
    - bridge调用callHandler, 
    - 调用_doSend()
    - 赋值messagingIframe.src = xxx://__wvjb_queue_message__
    - native的webview执行代理方法decidePolicyForNavigationAction
    - 获取url, native执行WKFlushMessageQueue
    - webview执行evaluateJavaScript, 调用js的_fetchQueue(),把_doSend()调用时写入sendMessageQueue中的值取出来,即获取js传递过来的参数
    - native方法flushMessageQueue,处理js传递过来的参数,封装在block中
    - 注意:js传递过来的参数,有可能还有function回调的存在,function是解决js调用native之后,native的执行结果回调给js,形成一个js->native->js的过程。

    2.native call js method

    - native中的bridge调用callHandler方法
    - BridgeBase中调用-(void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName
    - BridgeBase中调用_queueMessage
    - 这里有个判断,当startupMessageQueue!=nil时,消息放在数组中,当=nil时,直接调用_dispatchMessage
    - native中startupMessageQueue在执行injectJavascriptFile方法后会被设置为nil
    - injectJavascriptFile追溯可知当decidePolicyForNavigationAction中判断url的host=__bridge_loaded__时调用,
    - 而在js中设置的bridge时设置的WVJBIframe.src = 'https://__bridge_loaded__', 到此应该不用多问,剖析_dispatchMessage
    - _dispatchMessage中执行_evaluateJavascript, 执行的js中的方法_handleMessageFromObjC(xxx)
    - Bridge_JS中查询_dispatchMessageFromObjC, 接着调用_dispatchMessageFromObjC
    - 此时设置回调A-block, 里面的数据是js中的执行结果,js在开始的时候注册registerHandler,是key/block,此时通过key可以找到对应的B-block,将message传递过来的data跟设置的A-block当做对应的key/block的B-block的参数,直接执行该B-block即可。能够在js的registerHandler中获取到native传递过来的参数,同时也能够通过A-block将js的执行结果回调给native

    3. Summary

    初始化时给web注入不少料,核心是 1.拦截url, 2.回调实现基于初始化注入字典便于key/value方式管理block 3.evaluateJavaScript执行js

    4. Extension

    如上的做法适合UIWebView&WKWebView。实际上如果只针对WKWebView的话,可在_doSend方法中直接调用window.webkit.messageHandlers.xxx.postMessage(null),而非设置src的方式。可参照WKWebViewJavascriptBridge
  • Game Over。

Guess you like

Origin blog.51cto.com/15070994/2640311