最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JSBridge——如何与原生打交道

    正文概述 掘金(随风丶逆风)   2021-03-12   1209

    导语

    随着移动端领域的快速发展,业务场景愈发复杂,为减少开发量和投入成本,混合应用(Hybrid App)占据了不少市场。混合应用承载H5页面的容器就是webview,前端人员在开发过程中或多或少都需要与原生(Native App)之间交互,这个交互的桥梁就叫做JSBridge。同样也有一套通用的调试方法来确保JSB通信顺利。

    什么是WebView

    WebView是原生应用用来展示网页的view组件,本质上就是一款内置了webkit内核的无头浏览器(headless browser),提供了例如页面前进后退、放大缩小、音频控制等一般浏览器具备的功能。

    可以将WebView想象成html里面的iframe标签,h5页面与原生应用的通信过程就像是iframe父子页面之间的通信,只不过iframe使用postMessage和message事件处理,而WebView使用的是JSBridge。

    什么是JSBridge

    JSBridge是支持原生应用与H5应用双向通信的“桥梁”。

    JSBridge——如何与原生打交道

    • 原生->h5:向h5应用通知原生应用的相关状态,触发h5页面的内容更新、消息发送、音频播放等
    • h5->原生:向原生应用通知h5应用需要使用的功能,比如使用摄像头、使用gps、唤起app等

    因为原生应用与h5应用各自运行在独立的环境中,他们通信的方式就像前端JSONP跨域请求一样,通过原生暴露的一些特性让双端进行联系。

    JSBridge——如何与原生打交道

    Android WebView

    Android WebView以4.4为分界点,采用了不同的内核:

    • Android 4.4前:基于Webkit内核,H5的很多新特性不支持,且存在适配成本高、不安全、不稳定、耗流量、速度慢、视频播放差、文件能力差等问题。
    • Android 4.4后:基于Chromium内核(google在webkit上的fork出来的项目),很多新的规范被支持,例如WebGL,Canvas2D,CSS3以及其他很多的HTML5特性,同时大大提升了WebView组件的性能。

    js调用java

    Android Webview共提供过三种JS调用java的接口:

    • JavascriptInterface
    • WebViewClient.shouldOverrideUrlLoading() 【官方已废弃】
    • WebChromeClient.onXXX()

    JavascriptInterface

    这是 Android 提供的 JS 与 Native 通信的官方解决方案。

    • 首先Android RD需要实现一个类给 JavaScript 调用。
    public class WebAppInterface {
        @JavascriptInterface
        public void foo(String str) {
            // doing something
        }
    }
    
    • 将这个WebAppInterface类添加到 WebView 的 JavaScriptInterface 中。
    WebView webView = (WebView) findViewById(R.id.webview); 
    // 这里的Android会被当做一个变量,注入到页面的window中。
    webView.addJavascriptInterface(new WebAppInterface(this), "Android"); 
    
    • 最后就可以在 JS 中调用 Native 的方法了。
    function callFoo(str: string) {
        Android.foo(str);
    }
    

    WebViewClient.shouldOverrideUrlLoading()

    拦截webview内的url变更,例如iframe.src或location.href,若设置WebViewClient且该方法返回true,则可由代码自定义逻辑。

    一般采用URL Scheme的方式,它一种类似于URL的链接,原本用于唤起各类app而设计,主要特征是protocol和host一般是自定义的。

    所以可以事先约定好特殊格式的 URL Scheme,触发shouldOverrideUrlLoading拦截后,判断其格式是否符合,然后 Native 执行其特定逻辑。

    public class CustomWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(
          WebView view,
          String url
         ) {
          if (isJsBridgeUrl(url)) {
            // JSbridge的处理逻辑
            return true;
          }
          return super.shouldOverrideUrlLoading(view, url);
        }
    }
    

    WebChromeClient.onXXX()

    WebChromeClient支持监听浏览器的很多方法,比如:

    • Alert -> WebChromeClient.onJsAlert
    • Confirm -> WebChromeClient.onJsConfirm
    • Prompt -> WebChromeClient.onJsPrompt
    • console.xxx -> WebChromeClient.onConsoleMessage
    /**
     * 当网页调用alert()来弹出alert弹出框前回调,用以拦截alert()函数
     */
    public boolean onJsAlert(WebView view, String url, String message,JsResult result)
    /**
     * 当网页调用confirm()来弹出confirm弹出框前回调,用以拦截confirm()函数
     */
    public boolean onJsConfirm(WebView view, String url, String message,JsResult result)
    /**
     * 当网页调用prompt()来弹出prompt弹出框前回调,用以拦截prompt()函数
     */
     public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result) 
     /**
     * 打印 console 信息
     */
     public boolean onConsoleMessage(ConsoleMessage consoleMessage)
    

    以alert为例:

    • H5页面调用alert方法
    window.alert(message); 
    
    • 触发执行WebChromeClient.onJsAlert(),alert方法的入参message就是onJsAlert中的message参数
    public class CustomWebChromeClient extends WebChromeClient {
      @Override
      public boolean onJsAlert(
        WebView view,
        String url,
        String message,
        JsResult result
        ) {
            // doing something
            // 返回值true,表示拦截成功,false表示拦截失败,继续弹窗
            return true;
      }
    }
    

    Java 调用 js

    根据android版本,有2种方式:

    • loadUrl:全部支持
    • evaluateJavascript:安卓4.4版本之后

    loadUrl(String)

    webView.loadUrl("javascript:" + javaScriptString); 
    

    WebView.evaluateJavascript(String, IValueCallback)

    webView.evaluateJavascript("javascript:" + javaScriptString, new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String value) {
          // 执行完成后的回调
        }
    });
    

    IOS WebView

    IOS8 以前使用的是UIWebview,但是它存在不少问题:加载速度慢、内存泄漏、内存占用高、超出内存限制会被kill掉或者强制触发gc。感兴趣可阅读《IOS混合应用切换app闪屏bug总结》

    所以在WWDC 2014 大会上,推出了WKWebView。它代替了 UIKit 中的 UIWebView 和 AppKit 中的 WebView,提供了统一的跨双平台 API。拥有 60fps 滚动刷新率、内置手势、高效的 app 和 web 信息交换通道、和 Safari 相同的 JavaScript 引擎。

    使用messageHandlers 调用swift

    • 设置messageHandler
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"showAlert"];
    
    // 为了避免循环引用,导致控制器无法被释放,还需要移除
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"showAlert"];
    
    • webview会向window全局对象上注入webkit,调用messageHandlers即可实现调用swift
    window.webkit.messageHandlers.showAlert.postMessage()
    

    使用UserScript来注入 JavaScript

    WKUserScript 允许在正文加载之前或之后注入到页面中,它以 JavaScript 源码形式初始化,初始化时还可以传入是在加载之前还是结束时注入,以及脚本影响的是这个布局还是仅主要布局。举一个简单例子:

    let source = "document.body.innerHTML = 'helloWorld'";
    // 注入脚本 在文档加载完成后执行
    let userScript = WKUserScript()
    let userScript = WKUserScript(source: source, injectionTime: WKUserScriptInjectionTimeAtDocumentStart, forMainFrameOnly: true)
    let userContentController = WKUserContentController()
    userContentController.addUserScript(userScript)
    
    let configuration = WKWebViewConfiguration()
    configuration.userContentController = userContentController
    self.webView =WKWebView(frame: self.view.bounds, configuration: configuration)
        // url scheme
        this.sendMessageQueue.push(msgJSON);
    
        this._dispatchUrlMsg("" + this.bridgeScheme + this.dispatchMsgPath);
      }
    } catch (e) {
      console.error(e);
    }
    

    Webview以及JSBridge调试

    安卓

    安装chrome

    Google Chrome 网络浏览器

    启动开发者选项

    1. 谷歌手机开启「开发者选项」的方式,以小米为例是多次点击miui版本号开启
    2. 在「开发者选项中」打开「USB调试」

    打开chrome的检查器

    1. 数据线连接至mac上
    2. 打开Chrome, 地址栏输入chrome://inspect
    3. 在Devices选项, 打开发现USB设备选择

    JSBridge——如何与原生打交道

    1. 打开待调试webview页面,即可看到出现在设备列表中
    2. 点击其下方的inspect按钮,即可进入「控制台」调试

    ios

    下载安装Safari Technology Preview

    直接在官网下载安装即可,Safari Technology Preview - Safari - Apple Developer

    手机或pad开启web检查器

    1. 连接数据线到mac上。
    2. 在「设置」当中找到「Safari浏览器」,点击进入。

    JSBridge——如何与原生打交道

    1. 下滑找到「高级」,开启「web检查器」

    JSBridge——如何与原生打交道

    (写文档的时候没有真机,用模拟器截图,理解意思就行~~~)

    使用Safari开发工具调试

    1. 打开Safari Technology Preview,点击菜单中的「开发」,找到自己连接的机型

    JSBridge——如何与原生打交道

    1. 「信任」设备连接

    真机设备会弹出对话框,选择「信任」。再进行第一步的操作。 3. 进入「控制台」愉快的调试

    JSBridge调试

    在控制台「console」中,通过JSBridge.trigger(event, params)触发jsb,可以判断jsb是否通畅。

    注意事项

    • 老旧设备可能无法这样调试,可以使用vconsole
    • 确保连接线是数据线,而不是充电线
    • 安卓可能需要安装「ADB」拓展程序
    • 如果还不行,很大概率是你没有科学上网

    相关文档

    • 前端工程师所需要了解的WebView
    • 关于shouldOverrideUrlLoading方法的一些考证
    • 理解WebKit和Chromium: WebKit, WebKit2, Chromium和Chrome
    • WebViewClient.ShouldOverrideUrlLoading Method
    • IOS混合应用切换app闪屏bug总结

    起源地下载网 » JSBridge——如何与原生打交道

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元