UNPKG

fastman3-dfyjapp-jsbridge

Version:

a jsbridge module for dfyj app

656 lines (631 loc) 25.7 kB
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /* * @Author: shenzhiwei * @Date: 2021-04-11 08:09:42 * @Company: orientsec.com.cn * @Description: 核心逻辑(来自 Fastman1.0 Lib 源码,因此无需修改,请在源码库中对该脚本进行维护工作) */ /*eslint-disable*/ import { getAbsoluteUrl, isEmpty } from './util.web'; import { log } from './log'; import { extend } from "fastman3-common-helper"; import { compareVersion } from './version'; // 区分设备系统 var ua = navigator.userAgent; var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); var isFromApp = !!ua.toLowerCase().match(/DFYJ/i); // 是否来自于鸿蒙 var isFromHarmonyOS = !!ua.toLowerCase().match(/ArkWeb/i); // 初始化桥接对象 var init = function init(bridge) { bridge.init(function (message, responseCallback) { if (responseCallback) responseCallback(data); }); return bridge; }; /** * 初始化桥接对象 * connectWebViewJavascriptBridge * @param callback */ var ready = function ready(callback) { var __cb___ = function __cb___(__bridge___) { callback(__bridge___); }; if (isFromApp) { if (ipad || iphone || ipod) { // 新版本兼容IOS if (window.WebViewJavascriptBridge) { return __cb___(WebViewJavascriptBridge); } if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(__cb___); } window.WVJBCallbacks = [__cb___]; 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); } else if (android) { // 旧版本兼容Android if (window.WebViewJavascriptBridge) { __cb___(init(WebViewJavascriptBridge)); } else { document.addEventListener('WebViewJavascriptBridgeReady', function () { // 以异步形式加载 __cb___(init(WebViewJavascriptBridge)); }, false); } } else { __cb___(); } } else { __cb___(); } }; // 空函数 var noop = function noop() {}; /** * 成功消息体的包装 * @param payload 成功对象 */ // const wrapOkPayload = (payload = {}) => ({ // error: false, // info: 'ok', // payload: payload, // }) var wrapOkPayload = function wrapOkPayload() { var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return payload; }; /** * 失败消息体的包装 * @param info 错误描述 */ var wrapNotOkPayload = function wrapNotOkPayload() { var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : -1; var info = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'error'; return { // error: true, code: code, info: info }; }; /** * APP WebView后退,后退到栈的最外层 * @param options */ var onBack = function onBack(options) { // 默认配置 var _options = { complete: noop }; // 复制 _options = extend({}, _options, options); log('onBack->' + JSON.stringify(_options)); if (isFromHarmonyOS) { // HmJsBridge.back(_options); // window.LightSDK.native.back({ // number: _options.step // }, (resp) => { // log(`onBack <- ${JSON.stringify(resp)}`); // }); window.LightSDK.native.close(null, function (resp) { log("onBack <- ".concat(JSON.stringify(resp))); }); } else { WebViewJavascriptBridge.callHandler('back', _options, function (response) { log('onBack<-' + JSON.stringify(response)); _options.complete(response); }); } }; /** * APP WebView刷新 * @param options */ var onRefresh = function onRefresh(options) { var _options = { complete: noop }; _options = extend({}, _options, options); log('onRefresh->' + JSON.stringify(_options)); if (isFromHarmonyOS) { console.warn('onRefresh Harmony 暂未实现'); } else { WebViewJavascriptBridge.callHandler('refresh', _options, function (response) { log('onRefresh<-' + JSON.stringify(response)); _options.complete(response); }); } }; /** * 设置原生导航条 * @param options * { * "title": "xxxxx", * "type": "0" // 0-默认 1-切换类 * } */ var onNavigationBar = function onNavigationBar(options) { var _options = { complete: noop }; _options = extend({}, _options, options); log('onNavigationBar->' + JSON.stringify(_options)); if (isFromHarmonyOS) { // HmJsBridge.navigationBar(_options); // 设置导航标题 if (window.LightSDK.native.setTitle && !!_options.title) { log("[Harmony setTitle] -> ".concat(JSON.stringify(_options))); window.LightSDK.native.setTitle({ "title": _options.title }, function (resp) { log("[Harmony setTitle] <- ".concat(JSON.stringify(resp))); }); } else { console.error("[Harmony setTitle] LightSDK or setTitle is not available"); } // 清空右侧按钮 if (window.LightSDK.native.removeButton) { log("[Harmony removeButton] -> "); window.LightSDK.native.removeButton({ "position": "right" }, function (resp) { log("[Harmony removeButton] <- ".concat(JSON.stringify(resp))); }); } // 设置右侧按钮 if (window.LightSDK.native.addButton && (!!_options.rightButtonTitle || !!_options.rightButtonIcon)) { log("[Harmony addButton] -> "); // 两者不可兼得 if (!!_options.rightButtonIcon) { _options.rightButtonIcon = "base64://" + _options.rightButtonIcon; _options.rightButtonTitle = ""; } if (!!_options.rightButtonTitle) { _options.rightButtonIcon = ""; } window.LightSDK.native.addButton({ "title": _options.rightButtonTitle, "icon": _options.rightButtonIcon, "position": "right", "action": _options.onRightButtonPress }, function (resp) { log("[Harmony addButton] <- ".concat(JSON.stringify(resp))); }); } } else { WebViewJavascriptBridge.callHandler('navigationBar', _options, function (response) { log('onNavigationBar<-' + JSON.stringify(response)); _options.complete(response); }); } }; /** * 打开一个新的webview * @param options * { * "title": "xxxxx", // 导航名称,如果html设置title,以html为主 * "uri": "xxxxxxx", // webview请求的路由地址,目前只支持http协议,今后可支持shema协议 * "locktype": 0, // 0-不需要手势密码;1-手势密码锁屏;2-资金账号锁屏; * } */ var onPushView = function onPushView(options) { var _options = { title: '', isFullScreen: false, isStatusBarLight: true, ver: 'v1' }; _options = extend({}, _options, options); if (_options.isFullScreen == true) { _options.ver = 'v2'; } if (!!_options.uri) { if (_options.uri.indexOf('http') != -1 || _options.uri.indexOf('https') != -1) {} else { _options.uri = getAbsoluteUrl(_options.uri); } } log('onPushView->' + JSON.stringify(_options)); if (isFromHarmonyOS) { // HmJsBridge.go(_options); _options.url = _options.uri; log('onPushView->' + JSON.stringify(_options)); window.LightSDK.native.callNative("winner_base.router", _options, function (response) { log('onPushView <-' + JSON.stringify(response)); }); } else { WebViewJavascriptBridge.callHandler('pushView', _options, function (response) { log('onPushView<-' + JSON.stringify(response)); }); } }; /** * 原生页面将要出现时触发的事件 * @param callback */ var pageWillAppear = function pageWillAppear(callback) { if (typeof callback == 'function') { if (isFromHarmonyOS) { // HmJsBridge.willAppear(callback); window.LightSDK.event.on("viewappear", function () { log('pageWillAppear 被回调'); if (typeof callback == 'function') { callback(); } }); } else { WebViewJavascriptBridge.registerHandler("pageWillAppear", callback); } } }; /** * H5发送通知给客户端 * @param options */ var onNotify = function onNotify(options) { var _options = { type: 'javascriptNotify' }; _options = extend({}, _options, options); log('onNotify->' + JSON.stringify(_options)); if (isFromHarmonyOS) { console.warn('onNotify Harmony 暂未实现'); } else { WebViewJavascriptBridge.callHandler('notify', _options, function (response) { log('onNotify<-' + JSON.stringify(response)); }); } }; /** * H5注册通知,由客户端进行通知 * @param type 事件类型名称 * @param callback 回调处理 */ var notifyQueue = {}; var subscribeNotify = function subscribeNotify(type, callback) { if (typeof callback == 'function') { //回调函数存在队列中 var _type = type; // sae_video: v3思迪视频见证订阅事件名 // result_video: v5思迪视频见证订阅事件名(2025-05-30Added) if (_type == 'sae_video' || _type == 'result_video') { _type = 'notify'; } notifyQueue[_type] = callback; log('subscribeNotify->' + type); if (isFromHarmonyOS) { console.log('subscribeNotify Harmony 触发了'); window.LightSDK.event.on(_type, function (data) { log('[harmony]subscribeNotify<-' + JSON.stringify(data)); // 获取data.type才是H5定义的type if (Object.prototype.toString.call(data).toLocaleLowerCase() == '[object String]'.toLocaleLowerCase()) { data = JSON.parse(data); } var result = {}; result.type = type; result.payload = data; if (type == 'result_video' && data) { log('[harmony]subscribeNotify detail<-' + JSON.stringify(result)); // 如有驳回样本结果返回,则生成扁平化数组reject_reasons var rejectReasons = []; if (result.payload.result && result.payload.result.length) { // //var rejectReasonSample = [{fields: ["wt_witness_video_reject"], reasons: ["无法接收您的声音或画面,请您确认设备权限后重新连接;目前您的网络环境不太好,请您切换流量和无线网,确定网络环境正常后重新连接"], step: "witness_video", reasontitle: ["无法接收您的声音或画面,请您确认设备权限后重新连接;目前您的网络环境不太好,请您切换流量和无线网,确定网络环境正常后重新连接"]}]; var rejectReasonSample = result.payload.result; rejectReasonSample.forEach(function (fieldElement) { if (fieldElement.reasons && Object.prototype.toString.call(fieldElement.reasons) == "[object Array]") { rejectReasons = rejectReasons.concat(fieldElement.reasons); } }); } result.payload.reject_reasons = rejectReasons.reduce(function (acc, item) { return acc.concat(item.split(";")); }, []); } if (notifyQueue[_type]) { log('[harmony]subscribeNotify final<-' + JSON.stringify(result)); notifyQueue[_type](result); } }); } else { WebViewJavascriptBridge.registerHandler(_type, function (data) { log('subscribeNotify<-' + JSON.stringify(data)); // //获取data.type才是H5定义的type if (Object.prototype.toString.call(data).toLocaleLowerCase() == '[object String]'.toLocaleLowerCase()) { data = JSON.parse(data); } // 2025-05-30Added:针对5.0视频见证的输出对象payload对安卓端进行Object转换的兼容处理 if (type == 'result_video' && data.payload) { if (Object.prototype.toString.call(data.payload).toLocaleLowerCase() == '[object String]'.toLocaleLowerCase()) { data.payload = JSON.parse(data.payload); } // 兼容代码:处理iOS和安卓端返回结构不同的兼容 if (ipad || iphone || ipod) { data.payload = _objectSpread({}, data.payload.params); } // 如有驳回样本结果返回,则生成扁平化数组reject_reasons var rejectReasons = []; if (data.payload.result && data.payload.result.length) { // //var rejectReasonSample = [{fields: ["wt_witness_video_reject"], reasons: ["无法接收您的声音或画面,请您确认设备权限后重新连接;目前您的网络环境不太好,请您切换流量和无线网,确定网络环境正常后重新连接"], step: "witness_video", reasontitle: ["无法接收您的声音或画面,请您确认设备权限后重新连接;目前您的网络环境不太好,请您切换流量和无线网,确定网络环境正常后重新连接"]}]; var rejectReasonSample = data.payload.result; rejectReasonSample.forEach(function (fieldElement) { if (fieldElement.reasons && Object.prototype.toString.call(fieldElement.reasons) == "[object Array]") { rejectReasons = rejectReasons.concat(fieldElement.reasons); } }); } data.payload.reject_reasons = rejectReasons.reduce(function (acc, item) { return acc.concat(item.split(";")); }, []); } if (notifyQueue[_type]) { if (android) { // 解决安卓端request=1会调用type=notify的问题 if (data.type == 'sae_video' || data.type == 'result_video') { log('安卓notify被调用.'); notifyQueue['notify'](data); } else if (data.type == _type) { log("\u5B89\u5353".concat(data.type, "\u88AB\u8C03\u7528!")); notifyQueue[_type](data); } } else { log('iOS notify被调用;'); notifyQueue[_type](data); } } }); } } }; /** * 调用Schema Url * @param options */ var onDynamicLink = function onDynamicLink(options) { var _options = { url: '' }; _options = extend({}, _options, options); log('onDynamicLink->' + JSON.stringify(_options)); if (isFromHarmonyOS) { // location.href = _options.url; if (_options.url.indexOf('https') == 0 || _options.url.indexOf('http') == 0) { window.LightSDK.native.openURL({ url: _options.url }, function () { console.log('通过外部浏览器打开链接'); }); } else { location.href = _options.url; } } else { var $versionCompare = compareVersion('5.22.2'); // 小于5.22.2版本不再支持拉起视频见证,提示升级 if ($versionCompare < 0 && _options.url.indexOf('dl/videoreview') != -1) { alert("您当前的APP版本过低,请升级至V5.22.2以上版本后,再进行使用"); return; } WebViewJavascriptBridge.callHandler('dynamicLink', _options, function (response) { log('onDynamicLink<-' + JSON.stringify(response)); }); } }; // 存储Request指令订阅Handlers var requestHandlerMap = {}; // 是否注册了Request指令订阅Handlers var requestHandlerRegisterFlag = false; // 生成从minNum到maxNum的随机数,防 callback 重患 var randomNum = function randomNum(minNum, maxNum) { switch (arguments.length) { case 1: return parseInt(Math.random() * minNum + 1, 10); break; case 2: return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10); //或者 Math.floor(Math.random()*( maxNum - minNum + 1 ) + minNum ); break; default: return 0; break; } }; var callbackIds = []; var _generateCallbackId = function generateCallbackId() { var callbackId = randomNum(1000, 9999); if (callbackIds.indexOf(callbackId) !== -1) { return _generateCallbackId(callbackId); } else { callbackIds.push(callbackId); } return callbackId; }; /** * 调用Request指令(通常作用在一些原生和客户端之间比较特殊的操作) * @param operationType 操作指令(见文档) * @param payloadOptions 消息体结构 */ var onRequest = function onRequest(operationType, payloadOptions, okCallBack, notOkCallBack) { var _options = { type: !operationType ? '1' : operationType, payload: !payloadOptions ? {} : payloadOptions, callbackId: _generateCallbackId() }; // 兼容老方案 requestHandlerMap[operationType + '-ok'] = typeof okCallBack === 'function' ? okCallBack : noop; requestHandlerMap[operationType + '-notok'] = typeof notOkCallBack === 'function' ? notOkCallBack : noop; // 2020-5-2:修复 callback 在队列中重复的致命缺陷 requestHandlerMap[operationType + '_' + _options.callbackId + '-ok'] = typeof okCallBack === 'function' ? okCallBack : noop; requestHandlerMap[operationType + '_' + _options.callbackId + '-notok'] = typeof notOkCallBack === 'function' ? notOkCallBack : noop; // 处理Request指令 回复 var dealRequestResponse = function dealRequestResponse(response) { if (typeof response == 'string') { response = JSON.parse(response); } // 由于该指令输出的图片base64过长会导致vconsole假死,因此去除输出 if (operationType != "9") { log('onRequest<-' + JSON.stringify(response)); } if (response.error || response.error === 'true') { if (response.callbackId && typeof requestHandlerMap[response.type + '_' + response.callbackId + '-notok'] === 'function') { requestHandlerMap[response.type + '_' + response.callbackId + '-notok'](wrapNotOkPayload(-1, response.info)); } else if (typeof requestHandlerMap[response.type + '-notok'] === 'function') { requestHandlerMap[response.type + '-notok'](wrapNotOkPayload(-1, response.info)); } } else { if (response.callbackId && typeof requestHandlerMap[response.type + '_' + response.callbackId + '-ok'] === 'function') { // 防止安卓指令调用成功同步进入的控制 if (ipad || iphone || ipod || isFromHarmonyOS || response.payload) { requestHandlerMap[response.type + '_' + response.callbackId + '-ok'](wrapOkPayload(response.payload)); } } else if (typeof requestHandlerMap[response.type + '-ok'] === 'function') { // 防止安卓指令调用成功同步进入的控制 if (ipad || iphone || ipod || isFromHarmonyOS || response.payload) { requestHandlerMap[response.type + '-ok'](wrapOkPayload(response.payload)); } } } }; // 鸿蒙处理 if (isFromHarmonyOS) { // HmJsBridge.request(_options,function(response){ // dealRequestResponse(response); // }); return; } // IOS同步回调处理 log('onRequest->' + JSON.stringify(_options)); WebViewJavascriptBridge.callHandler('request', _options, function (response) { dealRequestResponse(response); }); if (!requestHandlerRegisterFlag) { // Android异步回调处理 WebViewJavascriptBridge.registerHandler('request', function (response) { if (typeof response == 'string') { response = JSON.parse(response); } if (response.error || response.error === 'true') { if (response.callbackId && typeof requestHandlerMap[response.type + '_' + response.callbackId + '-notok'] === 'function') { requestHandlerMap[response.type + '_' + response.callbackId + '-notok'](wrapNotOkPayload(-1, response.info)); } else if (typeof requestHandlerMap[response.type + '-notok'] === 'function') { requestHandlerMap[response.type + '-notok'](wrapNotOkPayload(-1, response.info)); } } else { if (response.callbackId && typeof requestHandlerMap[response.type + '_' + response.callbackId + '-ok'] === 'function') { requestHandlerMap[response.type + '_' + response.callbackId + '-ok'](wrapOkPayload(response.payload)); } else if (typeof requestHandlerMap[response.type + '-ok'] === 'function') { requestHandlerMap[response.type + '-ok'](wrapOkPayload(response.payload)); } } }); requestHandlerRegisterFlag = true; } }; /** * 提供给第三方调用中台接口的函数 * @param functionNo 中台功能号 * @param payloadOptions 中台消息体 * @param okCallBack 成功回调函数 * @param notOkCallBack 失败回调函数 */ var onApiRequest = function onApiRequest(functionNo, payloadOptions, okCallBack, notOkCallBack) { if (isEmpty(functionNo)) { throw new Error('functionNo is required ...'); } else { var _options = { funcId: functionNo, payload: !payloadOptions ? {} : payloadOptions }; } log('onApiRequest->' + JSON.stringify(_options)); if (isFromHarmonyOS) { console.warn('onApiRequest Harmony 暂未实现'); return; } WebViewJavascriptBridge.callHandler('apiRequest', _options, function (response) { log('onApiRequest<-' + JSON.stringify(response)); if (typeof response == 'string') { response = JSON.parse(response); } // 2017-12-26:对脚本逻辑做兼容,IOS认为业务异常和系统异常response.error都是true,ANDROID认为业务异常和业务成功时response.error是false,而系统异常response.error是true // IOS认为业务异常和系统异常response.error都是true,业务成功response.error是false if (ipad || iphone || ipod) { if (response.error || response.error === 'true') { // 接口业务异常 if (response.payload) { if (typeof notOkCallBack === 'function') { notOkCallBack(wrapNotOkPayload(response.payload.code, response.payload.info)); } } // 客户端自身应用级别错误(ios不给payload字段) else { if (typeof notOkCallBack === 'function') { notOkCallBack(wrapNotOkPayload(-1, response.info)); } } } else { if (typeof okCallBack === 'function') { var re = {}; if (response.payload) { if (typeof response.payload.data == 'string') { re = JSON.parse(response.payload.data); } else { re = response.payload.data; } } okCallBack(wrapOkPayload(re)); } } } // ANDROID认为业务异常和业务成功时response.error是false,而系统异常response.error是true else { if (response.error || response.error === 'true') { if (typeof notOkCallBack === 'function') { notOkCallBack(wrapNotOkPayload(-1, response.info)); } } else { var _re = {}; if (typeof response.payload.data == 'string') { _re = JSON.parse(response.payload.data); } else { _re = response.payload.data ? response.payload.data : {}; } // 业务异常 if (response.payload.code != '0') { if (typeof notOkCallBack === 'function') { notOkCallBack(wrapNotOkPayload(response.payload.code, response.payload.info)); } } // 业务成功 else { if (typeof okCallBack === 'function') { okCallBack(wrapOkPayload(_re)); } } } } }); }; export { wrapOkPayload, wrapNotOkPayload, // ready是一个异步操作,如果需要在页面加载时就调用相关接口,则需把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可直接调用,不需要放在ready函数中 // 该函数中有一个bridge变量,与下面的bridge使用上一致,只是调用顺序需要额外注意 ready, onBack, onRefresh, onNavigationBar, onPushView, onNotify, // H5发送通知给客户端 subscribeNotify, // 客户端发送通知给H5 onDynamicLink, onRequest, // 原生生命周期相关事件 pageWillAppear, // 第三方接口调用 onApiRequest };