/** * 建行生活 JSBridge 集成库 * * 功能说明: * 1. 检测是否在建行生活 App 内运行 * 2. 获取建行用户信息 * 3. 调起建行支付 * 4. 处理 URL 参数解密 * * @author Billy * @date 2025-01-17 */ (function(window) { 'use strict'; // 建行生活 JSBridge 对象 var CcbLifeBridge = { // 配置信息 config: { // API 基础地址 apiBaseUrl: '/addons/shopro', // 调试模式 debug: false, // 超时时间(毫秒) timeout: 10000, // 重试次数 retryTimes: 3 }, // 初始化状态 isReady: false, readyCallbacks: [], /** * 初始化 * @param {Object} options 配置选项 */ init: function(options) { // 合并配置 if (options) { Object.assign(this.config, options); } // 监听 JSBridge 就绪事件 this.setupBridge(); // 自动登录(如果在建行 App 内) if (this.isInCcbApp()) { this.autoLogin(); } this.log('CcbLifeBridge 初始化完成'); }, /** * 设置 JSBridge */ setupBridge: function() { var self = this; // iOS WebViewJavascriptBridge if (window.WebViewJavascriptBridge) { self.bridge = window.WebViewJavascriptBridge; self.onBridgeReady(); } else { document.addEventListener('WebViewJavascriptBridgeReady', function() { self.bridge = window.WebViewJavascriptBridge; self.onBridgeReady(); }, false); } // Android 直接通过 window 对象调用 if (window.mbspay && !self.bridge) { self.bridge = window.mbspay; self.onBridgeReady(); } // 设置超时检查 setTimeout(function() { if (!self.isReady) { self.log('JSBridge 未就绪,可能不在建行 App 内'); } }, 3000); }, /** * Bridge 就绪回调 */ onBridgeReady: function() { this.isReady = true; this.log('JSBridge 已就绪'); // 执行所有等待的回调 this.readyCallbacks.forEach(function(callback) { callback(); }); this.readyCallbacks = []; }, /** * 等待 Bridge 就绪 * @param {Function} callback 回调函数 */ ready: function(callback) { if (this.isReady) { callback(); } else { this.readyCallbacks.push(callback); } }, /** * 检测是否在建行生活 App 内 * @returns {Boolean} */ isInCcbApp: function() { var ua = navigator.userAgent.toLowerCase(); // 检查 User-Agent if (ua.indexOf('ccblife') > -1 || ua.indexOf('ccb') > -1) { return true; } // 检查 URL 参数 var urlParams = this.getUrlParams(); if (urlParams.ccbParamSJ || urlParams.from === 'ccblife') { return true; } // 检查是否有 JSBridge if (window.WebViewJavascriptBridge || window.mbspay) { return true; } return false; }, /** * 获取 URL 参数 * @returns {Object} */ getUrlParams: function() { var params = {}; var search = window.location.search.substring(1); if (search) { var pairs = search.split('&'); pairs.forEach(function(pair) { var parts = pair.split('='); if (parts.length === 2) { params[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); } }); } return params; }, /** * 获取建行用户信息 * @param {Function} callback 回调函数 */ getUserInfo: function(callback) { var self = this; if (!this.isInCcbApp()) { callback({ success: false, error: '不在建行生活 App 内' }); return; } this.ready(function() { self.callNative('getUserInfo', {}, function(result) { if (result && result.userid) { callback({ success: true, data: { ccb_user_id: result.userid, mobile: result.mobile || '', nickname: result.nickname || '', avatar: result.avatar || '' } }); } else { callback({ success: false, error: '获取用户信息失败' }); } }); }); }, /** * 自动登录 */ autoLogin: function() { var self = this; // 检查是否已登录 if (localStorage.getItem('ccb_token')) { this.log('用户已登录'); return; } // 获取用户信息并登录 this.getUserInfo(function(result) { if (result.success) { self.doLogin(result.data); } else { self.log('获取用户信息失败:' + result.error); } }); }, /** * 执行登录 * @param {Object} userInfo 用户信息 */ doLogin: function(userInfo) { var self = this; // 调用后端登录接口 this.ajax({ url: this.config.apiBaseUrl + '/ccblife/autoLogin', method: 'POST', data: userInfo, success: function(response) { if (response.code === 1) { // 保存 Token localStorage.setItem('ccb_token', response.data.token); localStorage.setItem('ccb_user_info', JSON.stringify(response.data.userInfo)); self.log('自动登录成功'); // 触发登录成功事件 self.triggerEvent('ccb:login:success', response.data); } else { self.log('登录失败:' + response.msg); } }, error: function(error) { self.log('登录请求失败:' + error); } }); }, /** * 调起建行支付 * @param {Object} options 支付参数 * @param {Function} callback 回调函数 */ payment: function(options, callback) { var self = this; if (!this.isInCcbApp()) { callback({ success: false, error: '不在建行生活 App 内' }); return; } // 必需参数检查 if (!options.payment_string) { callback({ success: false, error: '缺少支付串参数' }); return; } this.ready(function() { // 区分 iOS 和 Android if (self.isIOS()) { // iOS 使用 URL Scheme self.paymentForIOS(options, callback); } else { // Android 使用 JSBridge self.paymentForAndroid(options, callback); } }); }, /** * iOS 支付 */ paymentForIOS: function(options, callback) { var paymentUrl = 'comccbpay://pay?' + options.payment_string; // 尝试打开支付页面 window.location.href = paymentUrl; // 设置回调检查 setTimeout(function() { callback({ success: true, message: '已调起支付,请在建行 App 内完成支付' }); }, 1000); }, /** * Android 支付 */ paymentForAndroid: function(options, callback) { var self = this; // 调用原生支付方法 this.callNative('payment', { payment_string: options.payment_string }, function(result) { if (result && result.success) { callback({ success: true, data: result }); } else { callback({ success: false, error: result ? result.error : '支付失败' }); } }); }, /** * 调用原生方法 * @param {String} method 方法名 * @param {Object} params 参数 * @param {Function} callback 回调函数 */ callNative: function(method, params, callback) { var self = this; try { if (this.isIOS() && this.bridge && this.bridge.callHandler) { // iOS WebViewJavascriptBridge this.bridge.callHandler(method, params, callback); } else if (window.mbspay && window.mbspay[method]) { // Android 直接调用 var result = window.mbspay[method](JSON.stringify(params)); if (callback) { callback(typeof result === 'string' ? JSON.parse(result) : result); } } else { self.log('原生方法不存在:' + method); if (callback) { callback({ success: false, error: '原生方法不存在' }); } } } catch (e) { self.log('调用原生方法失败:' + e.message); if (callback) { callback({ success: false, error: e.message }); } } }, /** * 判断是否 iOS */ isIOS: function() { return /iPhone|iPad|iPod/i.test(navigator.userAgent); }, /** * 触发事件 */ triggerEvent: function(eventName, data) { var event = new CustomEvent(eventName, { detail: data }); window.dispatchEvent(event); }, /** * AJAX 请求 */ ajax: function(options) { var xhr = new XMLHttpRequest(); var self = this; xhr.open(options.method || 'GET', options.url, true); xhr.setRequestHeader('Content-Type', 'application/json'); // 添加 Token var token = localStorage.getItem('ccb_token'); if (token) { xhr.setRequestHeader('token', token); } xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { var response = JSON.parse(xhr.responseText); if (options.success) { options.success(response); } } else { if (options.error) { options.error('请求失败:' + xhr.status); } } }; xhr.onerror = function() { if (options.error) { options.error('网络错误'); } }; xhr.send(options.data ? JSON.stringify(options.data) : null); }, /** * 日志输出 */ log: function(message) { if (this.config.debug) { console.log('[CcbLifeBridge] ' + message); } } }; // 暴露到全局 window.CcbLifeBridge = CcbLifeBridge; })(window);