UNPKG

fastman3-dfyjapp-jsbridge

Version:

a jsbridge module for dfyj app

473 lines 16.6 kB
/* * @Author: shenzhiwei * @Date: 2021-04-11 08:19:09 * @Company: orientsec.com.cn * @Description: jsbridge(h5) */ import { setStorageSync } from "fastman3-dfyjapp-syncstorage"; // 必须这么导入,不要使用全局 Taro 导入 import { ready as bridgeReady, onBack, onPushView, // @ts-ignore subscribeNotify, // @ts-ignore onNavigationBar, onDynamicLink, onRequest as bridgeOnRequest, // 原生生命周期相关事件 // @ts-ignore pageWillAppear } from "./core"; import { isFromApp, isFromWeiXin, compareVersion, detect, getQueryString, extend, systemlog as log, errorlog } from "fastman3-common-helper"; import { isEmpty } from "./util.web"; import AppAuthorize from "./models/appAuthorize.h5"; import { TOKEN_KEY, DEVICE_ID_KEY } from "fastman3-dfyjapp-request/es/constants"; import storeWxLocalstorage from "./storeWxLocalstorage"; import { asyncResizeBase64 } from "./resizeBase64"; // 是否来自于鸿蒙 var isFromHarmonyOS = function isFromHarmonyOS() { return !!navigator.userAgent.toLowerCase().match(/ArkWeb/i); }; var isRegisterOk = false; var OPENID = "openid"; var NICKNAME = "nickname"; /** * 桥接准备,在使用桥接指令前需要先注册成功 * 客户端:建立桥接模式后直接执行回调 * 小程序端:目前直接执行回调 * 微信:直接执行回调(还额外包含微信用户信息恢复的逻辑处理) */ var GlobalReadyInstanceForFastman3; var ready = function ready() { log("[ready] ->"); return GlobalReadyInstanceForFastman3 ? GlobalReadyInstanceForFastman3 : GlobalReadyInstanceForFastman3 = new Promise(function (resolve) { bridgeReady(function () { log("[ready] <-"); resolve("ready ok"); }); }); }; /** * 通信鉴权 * 客户端:向客户端获取token等用户信息凭证后执行回调,并将必要的用户信息存储在 AppAuthorize 实例中 * 小程序端:目前直接执行回调 * 微信端:必要时调用 IF156008 恢复用户信息,并将必要的用户信息存储在 AppAuthorize 实例中,可额外获取 openid 和用户微信昵称 */ var oauth = function oauth() { log("[oauth] ->"); return new Promise(function (resolve) { var _a, _b; // 处理返回结果 var dealResponse = function dealResponse(response, resolve) { log("[oauth] <- ".concat(JSON.stringify(response))); if (typeof response == "string") { response = JSON.parse(response); } // 成功处理 if (response.code == "0") { // 2020-12-29: 增加 refreshToken 处理 var IF018020Resp = {}; if (!isEmpty(response.refreshTokenJson)) { if (typeof response.refreshTokenJson === "string") { IF018020Resp = JSON.parse(response.refreshTokenJson); } } // 同步并刷新最新的服务端 认证code 一次性授权票据,有效期1分钟 可用于兑换accessToken if (!!IF018020Resp.ticket) { AppAuthorize.ticket = IF018020Resp.ticket; } // 同步并刷新最新的服务端loginUser,可能是资金账户或手机号 if (!!IF018020Resp.loginUser) { AppAuthorize.loginUser = IF018020Resp.loginUser; } // 同步并刷新最新的服务端refreshToken if (!!IF018020Resp.refreshToken) { AppAuthorize.refreshToken = IF018020Resp.refreshToken; } // 同步并刷新最新的服务端accessToken if (!!IF018020Resp.accessToken) { AppAuthorize.accessToken = IF018020Resp.accessToken; } // 同步并刷新最新的服务端logon,数据类型boolean if (IF018020Resp.logon !== undefined) { AppAuthorize.logon = IF018020Resp.logon; } // 为APP授权模块标志授权标识token和虚拟设备ID AppAuthorize.token = response.token; // 同步并刷新最新的服务端token if (!!IF018020Resp.token) { AppAuthorize.token = IF018020Resp.token; } AppAuthorize.vtDeviceId = response.vtDeviceId; // 账户类信息授权 AppAuthorize.clientType = response.auth.clientType; // 同步并刷新最新的服务端clientType if (!!IF018020Resp.clientType) { AppAuthorize.clientType = IF018020Resp.clientType; } AppAuthorize.fundAccount = response.auth.fundAccount; AppAuthorize.regAccount = response.auth.regAccount; // 同步并刷新最新的服务端regAccount if (!!IF018020Resp.regAccount) { AppAuthorize.regAccount = IF018020Resp.regAccount; } AppAuthorize.bizSysId = response.auth.bizSysId; AppAuthorize.clientName = isEmpty(response.auth.clientName) ? "-" : response.auth.clientName; // 增加authSign(服务端通过该字段进行会话脏数据检查) AppAuthorize.authSign = isEmpty(response.authSign) ? "" : response.authSign; // 刷新并覆盖原来可能失效的授权凭证token setStorageSync(TOKEN_KEY, AppAuthorize.token); // 同时刷新vtDeviceId(用于机制调整后的恢复) setStorageSync(DEVICE_ID_KEY, response.vtDeviceId); resolve("oauth ok"); } // 失败处理 else { // // alert('似乎网络开小差了!') // if (typeof failCallback === 'function') { // failCallback() // } // 2020-12-29:当网络超时或无网情况下保证页面非白屏展示 resolve("oauth ok"); } isRegisterOk = false; }; // 微信端处理 if (isFromWeiXin()) { // 获取微信openid授权信息 if (!AppAuthorize.openId) { AppAuthorize.openId = (_a = getQueryString(OPENID)) !== null && _a !== void 0 ? _a : ""; } if (!AppAuthorize.nickName) { AppAuthorize.nickName = (_b = getQueryString(NICKNAME)) !== null && _b !== void 0 ? _b : ""; } AppAuthorize.archive(); storeWxLocalstorage(function () { resolve("ok"); }); } // 鸿蒙原生应用处理 else if (isFromApp() && isFromHarmonyOS()) { // 首先建立js桥接模式 if (!isRegisterOk) { // @ts-ignore HmJsBridge.oauth().then(function (response) { dealResponse(response, resolve); }); } } // APP端处理 else if (isFromApp()) { // 首先建立js桥接模式 if (!isRegisterOk) { // 是否小于APP 4.11.0 版本 var isLessThan4110 = compareVersion("4.11.0") < 0; // 注:iOS从4.11.0开始不使用isRegisterOk进行防重发 // iOS4.11.0前oauth的请求和回调并不是一一对应的,之后的修复成和安卓一样 var isIOS = detect.os.ios; isRegisterOk = isIOS && isLessThan4110; // @ts-ignore if (WebViewJavascriptBridge) { // @ts-ignore WebViewJavascriptBridge.callHandler("refreshToken", {}, function (response) { dealResponse(response, resolve); }); } } } // 其它端 else { log("[oauth] <-"); resolve("ok"); } }); }; /** * 页面前进 * 客户端:打开一个新的 webview 容器打开页面 * 小程序端:调用自建路由模块 * 微信端:使用原生函数 location.href 进行跳转 */ var go = function go(params) { var context = extend({ title: "", // 0-不需要手势密码;1-手势密码锁屏;2-资金账号锁屏; locktype: 0, isFullScreen: false, isStatusBarLight: true, ver: "v1" }, params); log("[go] -> ".concat(JSON.stringify(context))); if (isFromApp()) { context.uri = context.uri; log("[go] <-"); onPushView(context); } else { log("[go] <-"); location.href = context.uri; } }; /** * 页面后退 * 客户端:调用后将返回到栈的最外层,它并不会返回到前一个栈,如果需要返回前一个栈请使用history.back()来实现 * 小程序端:使用 Taro.navigateBack API 来实现 * 微信端:当step没有定义时调用history.back(), 否则调用history.go(-1 * step) */ var back = function back(params) { var context = extend({ step: 0 }, params); try { context.step = Math.abs(context.step); } catch (e) { context.step = 0; } log("[back] -> ".concat(JSON.stringify(context))); if (isFromApp()) { log("[back] <- ".concat(JSON.stringify(context))); onBack(context); } else { log("[back] <- ".concat(JSON.stringify(context))); history.go(context.step * -1); } }; /** * 原生跳转 * 客户端:以一个新的 webview 方式打开原生开发的功能 * 小程序端:触发 fail 失败回调 * 微信端:触发 fail 失败回调 */ var dynamicLink = function dynamicLink(params) { var context = extend({ url: "" }, params); log("[dynamicLink] -> ".concat(JSON.stringify(context))); if (isFromApp()) { log("[dynamicLink] <-"); onDynamicLink(context); } else { // 该功能在该端不支持时 if (typeof params.fail === "function") { log("[dynamicLink] <- 当前端不支持该指令"); params.fail(); } } }; /** * 业务指令调用 * @param type Request消息类型 * @param payload Request消息结构,即输入参数 * @param success 用于处理成功回调的函数,success(输出消息结构中的payload) * @param error 用于处理失败回调的函数,error(输出消息结构中的info) */ var onRequest = function onRequest(type, payload, success, error) { if (!payload) { payload = {}; } if (!success) { // @ts-ignore success = function success() {}; } if (!error) { // @ts-ignore error = function error() {}; } log("[onRequest] -> ".concat(JSON.stringify(payload))); if (isFromApp()) { bridgeOnRequest(type, payload, function (res) { if (type != "9") { log("[onRequest] <- ".concat(JSON.stringify(res))); } if (success) { success(res); } }, function (err) { errorlog("[onRequest] <- ".concat(JSON.stringify(err))); if (error) { error(err); } }); } else { // 浏览器中的情况 log("[onRequest] <-"); } }; /** * APP: 通过客户端NavigationBar来构建 * 其它:不实现,由前端自行实现 */ var navigationBar = function navigationBar(params) { var context = Object.assign({ title: "", type: "0", rightButtonTitle: "", onRightButtonPress: function onRightButtonPress() { return void 0; }, isShowBackButton: true, rightButtonIcon: "" }, params); if (isFromApp()) { if (isFromHarmonyOS()) { // harmony 直接在navigationBar桥接指令里实现onRightButtonPress } else { // @ts-ignore if (WebViewJavascriptBridge) { // @ts-ignore WebViewJavascriptBridge.registerHandler("onRightButtonPress", context.onRightButtonPress); } } // 异步处理DataURI,赢家图标尺寸为:50 * 50 if (context.rightButtonIcon) { // 如果右上角有图标,优先使用图标 context.rightButtonTitle = ""; try { asyncResizeBase64("data:image/png;base64,".concat(context.rightButtonIcon), 50, 50, function (newDataURI) { context.rightButtonIcon = newDataURI.replace("data:image/png;base64,", ""); log("[navigationBar] -> ".concat(JSON.stringify(context))); onNavigationBar(context); log("[onNavigateBar] <-"); }); } catch (err) { errorlog("[navigationBar] <- ".concat(JSON.stringify(err))); log("[onNavigateBar]报错继续恢复使用,不影响主流程"); log("[onNavigateBar] -> ".concat(JSON.stringify(context))); onNavigationBar(context); log("[onNavigateBar] <-"); } } else { log("[onNavigateBar] -> ".concat(JSON.stringify(context))); onNavigationBar(context); log("[onNavigateBar] <-"); } } else { log("[onNavigateBar] -> ".concat(JSON.stringify(context))); // 非 APP 中的 H5 设置 document.title if (document && Reflect.has(document, "title")) { document.title = context.title; } log("[onNavigateBar] <-"); } }; /** * APP: view将于出现时触发的回调函数(v3使用) * 小程序端: 直接调用Taro.useDidShow * 其它: 马上回调 * 该指令中如果调用服务接口请务必自行处理接口的onAuthError回调 * @supported — dfyjapp */ var willAppear = function willAppear(_callback) { if (_callback === void 0) { _callback = function _callback() {}; } log("[willAppear] ->"); var callback = function callback() { if (typeof _callback == "function") { // @ts-ignore log("[willAppear] <- \u56E0\u7528\u6237\u767B\u5F55\u64CD\u4F5C\u5EF6\u8FDF\u56DE\u8C03: ".concat(window.willAppearDeferSeconds | 0, "ms")); // @ts-ignore setTimeout(_callback, window.willAppearDeferSeconds | 0); } }; if (typeof callback == "function") { if (isFromApp()) { // 只能作用于authReady模式下,如果是noAuthReady可直接使用框架自身提供的pageWillAppear事件 ready().then(function () { pageWillAppear(function () { if (document.readyState[0] !== "l") { log("[willAppear]:document.readyState"); callback(); } else { document.addEventListener("DOMContentLoaded", function () { log("[willAppear]:DOMContentLoaded"); if (callback) { callback(); } }); } }); }); } else { callback(); } } }; /** * 检查App通知权限开启状态 */ var onCheckAppNotification = function onCheckAppNotification(options) { var defaultOptions = { success: function success() {}, fail: function fail() {} }; options = extend({}, defaultOptions, options); log("[onCheckAppNotification] -> ".concat(JSON.stringify(options))); if (isFromApp()) { onRequest('11', options, function (res) { log("[onCheckAppNotification] <- ".concat(JSON.stringify(res))); options.success(res); }, function (err) { errorlog("[onCheckAppNotification] <- ".concat(JSON.stringify(err))); options.fail(err); }); } else { log("[onCheckAppNotification] <-"); options.fail("非App端暂不支持该桥接指令[onCheckAppNotification]"); } }; /** * 跳转至App通知权限系统页 */ var onGoToCheckAppNotification = function onGoToCheckAppNotification(options) { var defaultOptions = { success: function success() {}, fail: function fail() {} }; options = extend({}, defaultOptions, options); log("[onGoToCheckAppNotification] -> ".concat(JSON.stringify(options))); if (isFromApp()) { onRequest('12', options, function (res) { log("[onGoToCheckAppNotification] <- ".concat(JSON.stringify(res))); options.success(res); }, function (err) { errorlog("[onGoToCheckAppNotification] <- ".concat(JSON.stringify(err))); options.fail(err); }); } else { log("[onGoToCheckAppNotification] <-"); options.fail("非App端暂不支持该桥接指令[onGoToCheckAppNotification]"); } }; /** * 订阅视频结果通知 * @param params - 订阅请求参数,包含视频检查结果类型和回调函数 * @remarks 当运行在App环境时,会通过subscribeNotify订阅指定类型的结果通知 */ var subscribeVideoResult = function subscribeVideoResult(params) { var context = extend({ type: "result_video", callback: function callback() {} }, params); log("[subscribeVideoResult] -> ".concat(JSON.stringify(context))); if (isFromApp()) { subscribeNotify(context.type, function (data) { log("[subscribeVideoResult] <-"); if (context.callback) { var // type, payload = data.payload; var errorNo = payload.error_no, errorInfo = payload.error_info, rejectReasons = payload.reject_reasons, _a = payload.witness_type, witnessType = _a === void 0 ? "" : _a; var resultVideo = { errorNo: errorNo, rejectReasons: rejectReasons, witnessType: witnessType, errorInfo: errorInfo }; context.callback(resultVideo); } }); } else { log("非App端暂不支持该桥接指令[subscribeVideoResult]"); } }; // h5端额外导出 onRequest 原始指令给上层应用层自行进行处理 export { AppAuthorize, ready, oauth, go, back, dynamicLink, onRequest, navigationBar, willAppear, onCheckAppNotification, onGoToCheckAppNotification, subscribeVideoResult };