JSBridge 实现网页与原生应用之间的通信

混合开发
混合开发(Hybrid)是一种开发模式,指使用多种开发模型开发App,通常会涉及到两大类技术:原生 Native、Web H5

JSBridge 的概念和作用

  • 通信桥梁:JSBridge 充当了 Web 应用和原生应用之间的通信桥梁。通过 JSBridge,我们可以在 web和原生代码之间进行双向通信,使这两者能够互相调用和传递数据。 原生功能调用:使用 JSBridge,我们可以在 JavaScript中调用原生应用中的功能。我们可以通过 web 来触发原生应用中的特定操作,如打开相机、发送通知、调用硬件设备等。

  • 数据传递:JSBridge 使得 JavaScript 和原生代码之间可以方便地传递数据。意味着我们可以在 web 和原生代码之间传递复杂的数据结构,如对象、数组等,以满足应用的功能需求。

  • 回调机制:JSBridge支持回调机制,使得在原生代码执行完某些操作后可以通知 JavaScript,并传递相应的结果。 JSBridge 做了什么

在Hybrid模式下,H5会需要使用Native的功能,比如打开二维码扫描、调用原生页面、获取用户信息等,同时Native也需要向Web端发送推送、更新状态等,而JavaScript是运行在单独的 JS Context 中(Webview容器)与原生有运行环境的隔离,所以需要有一种机制实现Native端和Web端的 双向通信 ,这就是JSBridge:以JavaScript引擎或Webview容器作为媒介,通过协定协议进行通信,实现Native端和Web端双向通信的一种机制

/* eslint-disable */
/* eslint no-use-before-define: ["error", { "functions": false }] */
let CALLBACK_NAME = 'koolearnApp2jsBridge.callback';
let TRIGGER_NAME = 'koolearnApp2jsBridge.trigger';
let ua = navigator.userAgent.toLowerCase();
let isIOS = /iphone|ipad|ipod/.test(ua);
let isAndroid = /android/.test(ua);

let send = function(name, params) {
    let data = JSON.stringify(params);
    switch (true) {
        case isIOS:
            sendIOS(name, data);
            break;
        case isAndroid:
            sendAndroid(name, data);
            break;
        default:
            console.log('不是移动端', name, params);
    }
};

let getToken = (function() {
    let num = 0;
    return function() {
        num++;
        return `${num}`;
    };
})();

function clone(base, obj) {
    if (arguments.length === 1) {
        obj = base;
        base = {};
    }
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            base[key] = obj[key];
        }
    }
    return base;
}

window[CALLBACK_NAME] = function(args) {
    let name = args.__name;
    let token = args.__token;
    if (!name || !token) return;
    if (window[CALLBACK_NAME][name] && window[CALLBACK_NAME][name][token]) {
        window[CALLBACK_NAME][name][token](args);
        delete window[CALLBACK_NAME][name][token];
    }
};

// app主动触发js,把方法放到数组中
window[TRIGGER_NAME] = function(args) {
    let name = args.__name;
    let token = args.__token;
    if (!name || !token) return;
    if (window[TRIGGER_NAME][name]) {
        window[TRIGGER_NAME][name].forEach((fn) => {
            fn && fn(args);
        });
    }
};

function sendIOS(name, params) {
    try {
        window.webkit.messageHandlers[name].postMessage(params);
    } catch (e) {
        console.log('ios消息发送失败', e.message);
    }
}

function sendAndroid(name, params) {
    try {
        params ? window.AndroidInterface[name](params) : window.AndroidInterface[name]();
    } catch (e) {
        console.log('android消息发送失败', e.message);
    }
}

/**
 * js向app发送详细
 * @name<String>: 接口名
 * @params<Object>:参数对象,不需要传空对象
 * @needCallback<Boolean>: 是否需要Promise回调
 * */
export function js2app(name, params, needCallback) {
    if (!!needCallback === false) {
        return send(name, params);
    }
    let token = getToken();
    return new Promise((resolve, reject) => {
        window[CALLBACK_NAME][name] = window[CALLBACK_NAME][name] || {};
        window[CALLBACK_NAME][name][token] = function(args) {
            if (name == 'checkPermission') {
                console.log('js2app: ', args);
                if (args.__status === 1) {
                    resolve(args);
                } else {
                    reject(args);
                }
                return;
            }
            args = args || {};
            if (args.__status === 0) {
                delete args.__name;
                delete args.__token;
                delete args.__status;
                delete args.__message;
                resolve(args);
            } else {
                reject(args.__message);
            }
        };
        send(name, clone({ __token: token }, params));
    });
}

/**
 * app调用js中的方法
 * @name<String>: js中的方法名给app标识用
 * @callback<Function>: js使用的回调方法,如果回调方法返回一个Primose,会自动通知app端
 * */
export function app2js(name, callback) {
    window[TRIGGER_NAME][name] = window[TRIGGER_NAME][name] || [];
    window[TRIGGER_NAME][name].push((args) => {
        let token = args.__token;
        // var data = clone({}, args);
        let promise;
        delete args.__name;
        delete args.__token;
        promise = callback(clone({}, args));
        promise && promise.then && promise.then(
            (data) => {
                let result = clone({
                    __token: token,
                    __status: 0,
                }, data);
                send(name, result);
            },
            (message) => {
                let sendData = {};
                let status = 1;
                let result;
                if (typeof message === 'object') {
                    sendData = message;
                    status = sendData.status || status;
                    message = sendData.message;
                    sendData = sendData.data || {};
                }
                result = clone({
                    __token: token,
                    __status: status,
                    __message: message,
                }, sendData);
                send(name, result);
            },
        );
    });
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

临夏_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值