From 3d3362e4300d49db23de48575d26c8d501fdbfd8 Mon Sep 17 00:00:00 2001
From: Tevin <tingquanren@163.com>
Date: Fri, 20 Aug 2021 18:52:00 +0800
Subject: [PATCH] 优化跨端通讯机制,实现从全局接收App通知,并通知页面

---
 bases/Pilot.js          |   29 +++++++++
 common/BridgeTelling.js |   79 ++++++++++++++++++++++++++
 bases/Fetcher.js        |    8 +-
 common/Bridge.js        |   47 +++++++++++----
 4 files changed, 147 insertions(+), 16 deletions(-)

diff --git a/bases/Fetcher.js b/bases/Fetcher.js
index e76073e..5d6c443 100644
--- a/bases/Fetcher.js
+++ b/bases/Fetcher.js
@@ -464,7 +464,7 @@
      * @return {String}
      * @private
      */
-    _stringToCamel(str) {
+    stringToCamel(str) {
         let str2 = '';
         if (str.indexOf('_') <= 0) {
             str2 = str;
@@ -484,7 +484,7 @@
      * @return {String}
      * @private
      */
-    _stringToUnderline(str) {
+    stringToUnderline(str) {
         let str2 = '';
         if ((/[A-Z]/).test(str)) {
             str2 = str.replace(/([A-Z])/g, ($1) => {
@@ -514,9 +514,9 @@
                     // 字符串键名进行转换
                     else {
                         if (type === 'camel') {
-                            key = this._stringToCamel(p);
+                            key = this.stringToCamel(p);
                         } else if (type === 'underline') {
-                            key = this._stringToUnderline(p);
+                            key = this.stringToUnderline(p);
                         }
                     }
                     // 属性为对象时,递归转换
diff --git a/bases/Pilot.js b/bases/Pilot.js
index babc9de..d7d3966 100644
--- a/bases/Pilot.js
+++ b/bases/Pilot.js
@@ -3,6 +3,7 @@
  * @author Tevin
  */
 
+import Taro, { getCurrentInstance } from '@tarojs/taro';
 import { Fetcher } from './Fetcher';
 import { Tools } from '@components/common/Tools';
 import project from '@project';
@@ -52,9 +53,37 @@
                 options.methods[name] = this[name];
             }
         });
+        this._bindTaroPage(options);
         return options;
     }
 
+    _bindTaroPage(options) {
+        // 非App内嵌模式,不执行
+        if (!project.appHybrid) {
+            return;
+        }
+        // 绑定页面实例到Page
+        const { onLoad, onUnload, onBridge } = options;
+        const option2 = {
+            onLoad() {
+                const instance = getCurrentInstance();
+                instance.page.$component = this;
+                onLoad && onLoad.call(this);
+                // 绑定 onBridge 到页面实例
+                this.$onBridge = onBridge || (() => {
+                });
+            },
+            onUnload() {
+                const instance = getCurrentInstance();
+                delete instance.page.$component;
+                onUnload && onUnload.call(this);
+            },
+        };
+        options.onLoad = option2.onLoad;
+        options.onUnload = option2.onUnload;
+        delete options.onBridge;
+    }
+
     /**
      * 转换静态图片引用
      * @param assets
diff --git a/common/Bridge.js b/common/Bridge.js
index 1c1c5e8..9729423 100644
--- a/common/Bridge.js
+++ b/common/Bridge.js
@@ -22,6 +22,9 @@
  *          window.linking('{method:\'methodName\', param:{key2:\'value2\'}, marker:\'mk222at1541994536008\'}');
  */
 
+import { Fetcher } from '@components/bases/Fetcher';
+import { Tools } from '@components/common/Tools';
+
 export class Bridge {
 
     constructor() {
@@ -84,16 +87,20 @@
      */
     _sendLinking(method, param, callback) {
         // 数据检查
-        if (Object.prototype.toString.call(param) !== '[object Object]') {
+        if (!Tools.isObject(param)) {
             console.error('$bridge.invoking 需要接受 JSON 对象!');
             return;
         }
+        // 转换发送参数键名为下划线
+        param = this.transKeyName('underline', param);
         // 如果有回调,转存回调
         const name = 'cb' + this._data.count++ + 'at' + Date.now();
         this[name] = (res) => {
-            if (callback && Object.prototype.toString.call(callback) === '[object Function]') {
+            if (callback && Tools.isFunction(callback)) {
                 if (res) {
-                    const data = typeof res === 'string' ? JSON.parse(res) : res;
+                    let data = typeof res === 'string' ? JSON.parse(res) : res;
+                    // 转换接收参数键名为驼峰
+                    data = this.transKeyName('camel', data);
                     callback(data);
                 } else {
                     callback();
@@ -117,9 +124,8 @@
      */
     invoking(method, param, callback) {
         // param 为函数时
-        const trans = param;
-        if (trans && Object.prototype.toString.call(trans) === '[object Function]') {
-            callback = trans;
+        if (param && Tools.isFunction(param)) {
+            callback = param;
             param = {};
         }
         if (this._checkLinking()) {
@@ -139,20 +145,26 @@
         window.telling = (res) => {
             const data = typeof res === 'string' ? JSON.parse(res) : res;
             const { method, param, marker } = data;
+            // 转换接收参数键名为驼峰
+            const param2 = this.transKeyName('camel', param);
             if (this._receives[method]) {
+                // 有通知回调
                 if (marker) {
-                    this._receives[method](param, (param2) => {
+                    this._receives[method](param2, (param2) => {
+                        debugger;
                         this._sendTelling(method, param2 || {}, marker);
                     });
-                } else {
-                    this._receives[method](param);
+                }
+                // 无通知回调
+                else {
+                    this._receives[method](param2);
                 }
             }
         };
     }
 
     /**
-     * 发送响应
+     * 回发App通知的响应
      * @param {string} method
      * @param {object} param
      * @param {string} marker
@@ -160,10 +172,12 @@
      */
     _sendTelling(method, param, marker) {
         // 数据检查
-        if (Object.prototype.toString.call(param) !== '[object Object]') {
+        if (!Tools.isObject(param)) {
             console.error('$bridge.register 注册的函数需要接受 JSON 对象!');
             return;
         }
+        // 转换发送参数键名为下划线
+        param = this.transKeyName('underline', param);
         // 发送
         window.aisim.linking(JSON.stringify({
             method,
@@ -173,7 +187,7 @@
     }
 
     /**
-     * 注册接收指令,可供 app 查询
+     * 注册接收指令,可接收 app 通知
      * @param method
      * @param callback
      */
@@ -189,6 +203,15 @@
         return platform === 'android' || platform === 'iOS';
     }
 
+    /**
+     * 键名转换
+     * @param type
+     * @param json
+     */
+    transKeyName(type, json) {
+        return Fetcher.prototype.transKeyName(type, json);
+    }
+
 }
 
 // 全局服务实例
diff --git a/common/BridgeTelling.js b/common/BridgeTelling.js
new file mode 100644
index 0000000..3517b71
--- /dev/null
+++ b/common/BridgeTelling.js
@@ -0,0 +1,79 @@
+/**
+ * BridgeTelling - 跨端通讯,通知接收基类
+ * @author Tevin
+ */
+
+import Taro from '@tarojs/taro';
+import { $bridge } from '@components/common/Bridge';
+import { Fetcher } from '@components/bases/Fetcher';
+
+export class BridgeTelling {
+    constructor(tellings) {
+        this._init(tellings);
+    }
+
+    _init(tellings) {
+        tellings.forEach(method => {
+            const name = Fetcher.prototype.stringToCamel(method);
+            if (typeof this[name] === 'undefined') {
+                console.warn('BridgeTelling:未发现“' + method + '”对于接收器!');
+            } else {
+                // 注册App通知接收器
+                $bridge.register(method, (res, callback) => {
+                    this[name](method, res, callback);
+                });
+            }
+        });
+    }
+
+    $getCurrentPage() {
+        const pages = Taro.getCurrentPages();
+        return pages[pages.length - 1];
+    }
+
+    $getCurrentPageUrl() {
+        return this.$getCurrentPage().path;
+    }
+
+    $isCurrentPage(url) {
+        const pages = Taro.getCurrentPages();
+        const curPage = pages[pages.length - 1];
+        if (curPage.path.split('?')[0] === url.split('?')[0]) {
+            return curPage;
+        } else {
+            return null;
+        }
+    }
+
+    _checkPage(url, callback) {
+        let curPage = this.$isCurrentPage(url);
+        if (curPage) {
+            callback(curPage);
+        } else {
+            setTimeout(() => {
+                this._checkPage(url, callback);
+            }, 100);
+        }
+    }
+
+    $openPage(url, callback) {
+        const curPage = this.$isCurrentPage(url);
+        // 需打开的是当前页面
+        if (curPage) {
+            callback(curPage);
+        } else {
+            Taro.navigateTo({
+                url,
+                success: () => {
+                    this._checkPage(url, callback);
+                },
+            });
+        }
+    }
+
+    $pageBridge(page, method, res, callback) {
+        page.$component.$onBridge(method, res, callback);
+    }
+
+}
+

--
Gitblit v1.9.1