| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- (function (window) {
- 'use strict';
- /**
- * ColorMapRun JSBridge SDK (Compatible Version)
- * 用于 H5 页面与 Flutter App 进行交互
- * 兼容性说明:
- * - 优先检测 uni.webView 标准通道
- * - 降级适配旧版 App 的 action:// 协议拦截和 window.share_wx 注入对象
- */
- var Bridge = {
- version: '1.0.2',
-
- /**
- * 内部核心发送方法
- */
- _post: function (action, data) {
- data = data || {};
- console.log('[Bridge] Call:', action, data);
- // 1. 优先尝试标准 uni 通道 (新版 App)
- if (window.uni && window.uni.postMessage) {
- window.uni.postMessage({
- data: {
- action: action,
- data: data
- }
- });
- return;
- }
- // 2. 降级适配 (旧版 App)
- this._fallback(action, data);
- },
- /**
- * 旧版 App 适配逻辑
- */
- _fallback: function (action, data) {
- var url = '';
- switch (action) {
- case 'back':
- // 尝试关闭页面或返回
- window.history.back();
- break;
-
- case 'toHome':
- // 协议: action://to_home/
- url = 'action://to_home/';
- break;
- case 'toLogin':
- // 协议: action://to_login/
- url = 'action://to_login/';
- break;
- case 'openMap':
- // 协议: action://to_map_app?title=xxx&latitude=xxx&longitude=xxx
- url = 'action://to_map_app?title=' + encodeURIComponent(data.name || '') +
- '&latitude=' + data.latitude +
- '&longitude=' + data.longitude;
- break;
- case 'openMatch':
- // 协议: action://to_detail/?id=xxx&matchType=xxx
- url = 'action://to_detail/?id=' + data.id +
- '&matchType=' + (data.type || 1);
- break;
-
- case 'openActivityList':
- // 协议: action://to_activity_list/?id=xxx&mapName=xxx
- url = 'action://to_activity_list/?id=' + data.id +
- '&mapName=' + encodeURIComponent(data.mapName || '');
- break;
- case 'shareWx':
- // 旧版使用注入对象 share_wx
- if (window.share_wx && window.share_wx.postMessage) {
- window.share_wx.postMessage(JSON.stringify(data));
- } else {
- console.error('[Bridge] share_wx injection not found');
- alert('微信分享功能不可用(环境不支持)');
- }
- return; // shareWx 不需要走 URL 拦截
- case 'launchWxMini':
- // 旧版使用注入对象 wx_launch_mini
- if (window.wx_launch_mini && window.wx_launch_mini.postMessage) {
- window.wx_launch_mini.postMessage(JSON.stringify(data));
- } else {
- console.error('[Bridge] wx_launch_mini injection not found');
- }
- return;
- case 'saveImage':
- // 旧版使用注入对象 save_base64
- if (window.save_base64 && window.save_base64.postMessage) {
- window.save_base64.postMessage(data.base64);
- } else {
- console.error('[Bridge] save_base64 injection not found');
- }
- return;
- case 'makePhoneCall':
- url = 'tel:' + data.phoneNumber;
- break;
-
- case 'showToast':
- // 降级为 alert,体验稍差但保证可见
- // setTimeout 避免阻塞当前执行流
- setTimeout(function() { alert(data.title); }, 10);
- return;
-
- case 'showModal':
- setTimeout(function() {
- var result = confirm(data.content || data.title);
- // 无法同步返回结果给 App 逻辑,仅做展示
- }, 10);
- return;
- default:
- console.warn('[Bridge] No legacy fallback for action:', action);
- }
- if (url) {
- console.log('[Bridge] Legacy URL jump:', url);
- // 触发 URL 拦截
- window.location.href = url;
- }
- },
- // ==============================
- // Ported from common/tools.js
- // ==============================
- /**
- * 对url追加项目版本号
- */
- urlAddVer: function(url) {
- var newUrl = url;
- try {
- if (window.uni && window.uni.getSystemInfoSync) {
- var systemInfo = window.uni.getSystemInfoSync();
- var version_number = systemInfo.appVersion;
- if (version_number) {
- if (newUrl.indexOf('_v=') !== -1) {
- return newUrl;
- }
- if (newUrl.indexOf('?') !== -1) {
- newUrl += "&_v=" + version_number;
- } else {
- newUrl += "?_v=" + version_number;
- }
- }
- }
- } catch (e) {
- console.warn('[Bridge] urlAddVer error:', e);
- }
- console.log("[Bridge] urlAddVer newUrl:", newUrl);
- return newUrl;
- },
- /**
- * 导航到APP内的某个页面或执行APP内部的某些功能
- */
- appAction: function(url, actType) {
- actType = actType || "";
- console.log("[Bridge] appAction:", url, "actType:", actType);
- if (url.indexOf('http') !== -1) {
- window.location.href = this.urlAddVer(url);
- } else if (url == "reload") {
- window.location.reload();
- } else if (actType == "uni.navigateTo" && window.uni && window.uni.navigateTo) {
- window.uni.navigateTo({
- url: this.urlAddVer(url)
- });
- } else {
- window.location.href = url;
- }
- },
- // ==============================
- // 公开 API
- // ==============================
- back: function () {
- this._post('back');
- },
-
- toHome: function() {
- this._post('toHome');
- },
-
- toLogin: function() {
- this._post('toLogin');
- },
- setTitle: function (title) {
- this._post('setTitle', { title: title });
- },
- openMap: function (latitude, longitude, name) {
- this._post('openMap', {
- latitude: latitude,
- longitude: longitude,
- name: name
- });
- },
- openMatch: function (id, type) {
- this._post('openMatch', {
- id: id,
- type: type
- });
- },
-
- openActivityList: function(id, mapName) {
- this._post('openActivityList', {
- id: id,
- mapName: mapName
- });
- },
- shareWx: function (options) {
- this._post('shareWx', options);
- },
- launchWxMini: function (username, path) {
- this._post('launchWxMini', { username: username, path: path });
- },
-
- saveImage: function (base64Str) {
- this._post('saveImage', { base64: base64Str });
- },
-
- // --- 新增完善功能 ---
-
- /**
- * 预览图片
- * @param {Array} urls 图片地址数组
- * @param {String} current 当前显示图片的地址
- */
- previewImage: function(urls, current) {
- this._post('previewImage', { urls: urls, current: current });
- },
- /**
- * 拨打电话
- * @param {String} phoneNumber 电话号码
- */
- makePhoneCall: function(phoneNumber) {
- this._post('makePhoneCall', { phoneNumber: phoneNumber });
- },
- /**
- * 设置剪贴板内容
- * @param {String} data 文本内容
- */
- setClipboardData: function(data) {
- this._post('setClipboardData', { data: data });
- },
- /**
- * 显示 Toast 提示
- * @param {String} title 提示内容
- * @param {String} icon 图标 (success/loading/none)
- * @param {Number} duration 持续时间(ms)
- */
- showToast: function(title, icon, duration) {
- this._post('showToast', {
- title: title,
- icon: icon || 'none',
- duration: duration || 1500
- });
- },
- /**
- * 显示 Loading 提示框
- * @param {String} title 提示内容
- */
- showLoading: function(title) {
- this._post('showLoading', { title: title || '加载中' });
- },
- /**
- * 隐藏 Loading 提示框
- */
- hideLoading: function() {
- this._post('hideLoading');
- },
-
- /**
- * 显示模态确认框
- * @param {Object} options { title, content, showCancel, confirmText, cancelText }
- * @param {Function} successCallback 点击确定/取消的回调 (仅在支持的双向通信环境有效)
- */
- showModal: function(options, successCallback) {
- // TODO: 这里的 callback 在单向 Bridge 中难以实现,通常需要 App 回调 JS 方法
- this._post('showModal', options);
- },
-
- // ------------------
- getToken: function () {
- this._post('getToken');
- },
-
- _tokenCallback: null,
- onToken: function(callback) {
- this._tokenCallback = callback;
- },
- receiveToken: function(token) {
- console.log('[Bridge] Received token:', token);
- if (this._tokenCallback) {
- this._tokenCallback(token);
- }
- }
- };
- window.Bridge = Bridge;
- })(window);
|