zoukankan      html  css  js  c++  java
  • H5与原生交互

     H5与原生应用的交互都是通过原生应用中的WebView实现的。通过这个环境,H5可以调用原生应用注入其中的原生对象的方法,原生应用也可以调用H5暴露在这个环境中的JavaScript对象的方法,从而实现指令与数据的传输。

    原生应用和JS分别在WebView里注入/暴露的对象:

    • NativeBridge:原生应用注入到WebView中的对象

    • JSBridge:JS暴露在WebView中的对象

    并约定在这两个对象上分别可以调用什么方法:

    • NativeBridge.callNative(action, params, whoCare)

    • JSBridge.callJS(action, params, whoAmI)

    NativeBridge.callNative是由JS调用向Native传递指令或数据的方法,而JSBridge.callJS则是由Native调用向JS传递指令或数据的方法。方法签名中的参数含义如下:

    •  action:字符串,希望Native/JS执行的操作

    •  params:JSON对象,要传给Native/JS的数据

    •  whoCare:数值,表示JS希望哪个端响应

    • whoAmI:数值,表示哪个端调用的JS

    基础接口只有两个对象和两个方法,JS与App间的互操作则通过action和params来扩展和定义。

    由JS发起的单向调用App的操作,如加载URL和切换到原生界面,可对应的action为:loadUrl:加载另一个h5的URL;loadContent:跳转到相应的原生界面。

    这里NativeBridge是App的原生对象,其callNative方法被调用时,会收到一个对象(字典/映射)参数。根据这个参数的action属性的值,App可知需要执行的操作是加载URL或跳转到原生界面。

    一下代码App可知需要执行的操作是加载URL。于是再取得params属性中的url,发送请求即可:

    NativeBridge.callNative({
     action: 'loadUrl',
     params: { url },
     whoCare: 0
    })

    以下代码通过params向App传递了必要参数,App负责切换到相应的原生界面:

    NativeBridge.callNative({
        action: "loadContent",
        params: {
            type: "album",
            content: {
                album_id: "1"
            }
        },
        whoCare: 0
    })

    由App发起的单向调用JS的操作,如用户点击后退按钮(<)时,可对应的action为:can_back:询问JS是否返回前是否需要用户确认(即在返回上一级界面前,是否弹窗提示用户?)。参考协议如下:

    JSBridge.callJS({
     action: "can_back",
     params: {},
     whoAmI: 1/2
    })

    此调用返回的值示例如下:

    {
     can: true,
     target: "prev"
    }

    返回值中的can如果是true,则不提示直接返回;如果是false,则弹出一个确认框,请用户确认。另一个值target是与App约定的返回目标,比如prev表示返回上一级,top表示返回顶级,等等。

    WebViewJavascriptBridge

    使用WebViewJavascriptBridge和原生交互跳转

    页面代码

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=0.5,maximum-scale=0.5,user-scalable=no" />
            <script src="bridge.js"></script>
        </head>
        <body></body>
        <script>
            let paramsObj = getParamsObj(window.location.search);
             bridge.callHandler('callNative', {a: 1}, (data) => {
                 // 回调函数
                 console.log(data);
             });
        </script>
    </html>

    brige.js文件

    /**
     * android系统js桥接口设置
     * @param {Object} callback 桥接口回调函数 桥接方式固定写法
     */
    function setUpAndroidBridge(callback) {
        if (window.WebViewJavascriptBridge) {
            return callback(WebViewJavascriptBridge);
        } else {
            document.addEventListener(
                'WebViewJavascriptBridgeReady',
                function () {
                    return callback(WebViewJavascriptBridge);
                },
                false
            );
        }
    }
    
    /**
     * IOS系统js桥接口设置
     * @param {Object} callback 桥接口回调函数 桥接方式固定写法
     
     */
    function setUpIOSBridge(callback) {
        if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
        if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
        window.WVJBCallbacks = [callback];
        var WVJBIframe = document.createElement('iframe');
        WVJBIframe.style.display = 'none';
        WVJBIframe.src = 'https://__bridge_loaded__';
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(function () { document.documentElement.removeChild(WVJBIframe) }, 0)
    }
    
    
    let bridge = {
        callHandler(name, data, resultCallback) {
            var osType = getOSType();//获取系统类型
            //按系统类型 分别执行原生交互
            if (osType == 'IOS') {
                //苹果手机交互方式 消息体为字面量对象(json格式): action 代表执行的动作 data 代表传递的数据
                setUpIOSBridge(function (bridge) {
                    bridge.callHandler(name, data, function (response) {
                        if (typeof resultCallback == 'function') {
                            resultCallback(response);
                        }
                    });
                });
            } else if (osType == 'ANDROID') {
                //安卓手机交互方式
                setUpAndroidBridge(function (bridge) {
                    bridge.callHandler(name, data, function (response) {
                        if (typeof resultCallback == 'function') {
                            resultCallback(response);
                        }
                    });
                });
            } else {
                //其他类型
            }
        }
    }

     jsbridge实现原理

    js调用Native

    通过特定的参数转换方法,将传入的数据,方法名一起,拼接成一个url scheme,以下只介绍前两个方法,第三个和第二个比较类似用于触发这个url scheme:

    A. Native暴露一个含有通信方法的类给web调用

    B. Native拦截iframe请求

    C. Native拦截prompt弹出框

    Native调用JS

    Native调用Javascript语言,是通过UIWebView组件的stringByEvaluatingJavaScriptFromString方法来实现的,该方法返回js脚本的执行结果。

    // Swift
    webview.stringByEvaluatingJavaScriptFromString("Math.random()")
    // OC
    [webView stringByEvaluatingJavaScriptFromString:@"Math.random();"];

    从上面代码可以看出它其实就是调用了window下的一个对象,如果我们要让native来调用我们js写的方法,那这个方法就要在window下能访问到。但从全局考虑,我们只要暴露一个对象如JSBridge对native调用就好了

    原文:

    http://www.fly63.com/article/detial/2824

  • 相关阅读:
    CSS 层叠样式表
    一. 图论
    二. log4j配置文件
    三.注解
    3. Map与Tuple
    MappedByteBuffer读写文件
    2. scala中的数组
    1.scala语法
    二. 模式匹配
    一.算法的数学基础
  • 原文地址:https://www.cnblogs.com/xjy20170907/p/11023783.html
Copyright © 2011-2022 走看看