干貨!手把手教你如何使用第三方通訊服務實現LayIM Socket組件開發。


前言

  之前寫了一系列的文章,是關於使用ASP.NET SignalR技術實現LayIM的功能對接,有興趣的同學移步:http://www.cnblogs.com/panzi/p/5767095.html

  此篇會從頭到尾詳細介紹開發流程,和對接方法。文章會比較長,准備點小零食,細細品讀吧,如果只能夠跟着實踐最好。

  本篇文章主要講解內容如下:

  • 融雲服務WebSDK的對接
  • LayIM接口的對接
  • 如何將外網js模塊化,使其符合layui標准
  • 其他細節等

准備工作

  首先,LayIM不多介紹了,想了解的同學移步:http://www.layui.com/doc/modules/layim.html 。已經了解過的同學可以忽略。因為這次用的是第三方融雲服務實現,所以,我們先去官網注冊一個賬號吧。融雲官網地址:http://rongcloud.cn.先注冊一個賬號,然后選擇創建應用。創建應用之后,不用上線,我們選擇測試環境即可。我們要的就是拿到appkeyappsecret

js模塊化

  為什么叫js模塊化呢,一般正常情況下,我們直接按照融雲所給的文檔里面那么調用即可。文檔地址,如果不想去看融雲文檔的話,可以直接看開發完成后的源代碼即可。融雲Web開發文檔地址:http://www.rongcloud.cn/docs/web.html 。文檔中的調用方式如下:

  其實如上圖調用也完全沒問題,但是我們要開發layui組件的話,就必須要改一下了。因為我們最終想使用 layui.use的方式,而不是直接像上圖那樣引用js。看一下文檔結構:

  

  首先,rmlib對應RongIMLib-2.2.4.min.js,protobuf對應protobuf.2.1.5.min.js,socket 就是業務封裝層了。

  rmlib的改造比較簡單,直接將js內容粘貼下來,然后根據layui語法exports即可。

  

  為什么要加protobuf這個js呢,說一下原因,首先在原生的融雲js調用的時候,會加載一個protobuf.min.js

  

  而由於公司網絡不好的原因,經常會出現加載該js卡住的情況,而導致通訊失敗,那么我們將他同樣復制粘貼下來,改造一下。同樣:

  

  當我們美滋滋的執行程序的時候,會發現,這玩意還是會被加載,就會導致出現加載兩次的情況,當然這是由於rmlib.js中某段代碼加載了該js,我們要做的就是找到那段代碼,然后不讓它加載就可以了。如下圖:

  

  當我們取查代碼的時候,哇,忘記了,是壓縮過的代碼。從何查起呢,查找protobuf,不起作用,后來我就查找了2.1.5,就找到如下這段代碼

j=e.1o.iq(s,{a5:r+"5b.4e.2Z/a5-2.1.5.9n.js","ds":r+"5b.4e.2Z/sg.js"

  可以分析一下,r應該是http或者https,而5b.4e.2z對應cdn.ronghub.com,a5應該就是protobuf了,剛開始我是直接把a5刪掉,后來發現會出現請求undefined的情況,后來將代碼中的,a5改成空值。即 a5:''.大功告成,終於不用再加載cdn的代碼了。如下圖,只會加載我們自己定義的protobuf.js

  

  最后一個js,socket.由於它是直接封裝業務的,所以,我們將依賴加上,然后暴漏socket。到這里的我們的基本准備工作就算結束了,下面就是業務開發了。

  

核心業務-連接服務器

  由於這里呢,我不想把太多.NET的東西帶進來,所以,LayIM的對接后台這次就不在闡述了,主要目的是讓大家拿到這個東西直接運行通訊功能。主要是前端的開發工作。首先呢,我們知道,既然使用了融雲,那就有必要了解一下它是怎么工作的。直接進入代碼階段。(里面內容不懂得可以看融雲官方文檔,下文中的lib即官網中的RongIMLib)

  很簡單,先來一段 init,初始化,很簡單吧,這里用到了我們之前拿到的 appkey。

 lib.RongIMClient.init(conf.key);
 this.initListener();
 this.defineMessage();

  下面呢,我們要監聽融雲的連接狀況,就用到了initListener,詳細代碼如下,直接從官網文檔copy即可。里面會監聽到各種狀態,包括監聽消息接收。

       // 設置連接監聽狀態 ( status 標識當前連接狀態 )
            // 連接狀態監聽器
            log('注冊服務連接監聽事件');
            var code = im.code.errorUnKnown;
            RongIMClient.setConnectionStatusListener({
                onChanged: function (status) {
                    switch (status) {
                        case lib.ConnectionStatus.CONNECTED:
                            break;
                        case lib.ConnectionStatus.CONNECTING:
                            break;
                        case lib.ConnectionStatus.DISCONNECTED:
                            break;
                        case lib.ConnectionStatus.KICKED_OFFLINE_BY_OTHER_CLIENT:
                            break;
                        case lib.ConnectionStatus.DOMAIN_INCORRECT:
                            break;
                        case lib.ConnectionStatus.NETWORK_UNAVAILABLE:
                            break;
                    }
                    listener(code);
                }
            });

            // 消息監聽器
            RongIMClient.setOnReceiveMessageListener({
                // 接收到的消息
                onReceived: function (message) {
                    log(message);
                    // 判斷消息類型
                    switch (message.messageType) {
                     
                    }
                }
            });

  最后一個defineMessage,這個有點意思,就是說,融雲給我們提供了多種數據類型,但是都不滿足我們的需求,所以我們就要自己定義消息類型了。這里呢,我們需要的消息類型是什么呢?先不要看下文,想一下,這里接受消息要定義什么樣的類型,根據什么來定義?

  想到了沒有?當然是layim想要的消息格式。根據文檔可知,就是如下消息類型:

layim.getMessage({
  username: "紙飛機" //消息來源用戶名
  ,avatar: "http://tp1.sinaimg.cn/1571889140/180/40030060651/1" //消息來源用戶頭像
  ,id: "100000" //消息的來源ID(如果是私聊,則是用戶id,如果是群聊,則是群組id)
  ,type: "friend" //聊天窗口來源類型,從發送消息傳遞的to里面獲取
  ,content: "嗨,你好!本消息系離線消息。" //消息內容
  ,cid: 0 //消息id,可不傳。除非你要對消息進行一些操作(如撤回)
  ,mine: false //是否我發送的消息,如果為true,則會顯示在右方
  ,fromid: "100000" //消息的發送者id(比如群組中的某個消息發送者),可用於自動解決瀏覽器多窗口時的一些問題
  ,timestamp: 1467475443306 //服務端動態時間戳
});

  為了方便,我只加了其中幾個必要的屬性。注冊自定義消息方法如下:

       var defineMsg = function (obj) {
                RongIMClient.registerMessageType(obj.msgName, obj.objName, obj.msgTag, obj.msgProperties);
            }
            //注冊普通消息
            var textMsg = {
                msgName: 'LAYIM_TEXT_MESSAGE',//自己定義的名稱
                objName: 'LAYIM:CHAT',
                msgTag: new lib.MessageTag(false, false),
                msgProperties: ["username", "avatar", "id", "type", "content"]
            };
            //注冊
            defineMsg(textMsg);

  init完了之后我們要做什么呢,就需要用戶連接服務器了,那么融雲連接服務器是需要根據用戶id生成一個token的,涉及到服務端的東西。這里怎么避免先不用服務端的呢,我們可以在融雲接口調試里面自己根據用戶id生成token,因為token是永久性的(可以設置),所以,我們如果想做測試,可以直接生成兩個token即可,不過,因為后台我已經完成了token的生成功能,所以,自己生成token需要大家自行去官網找一下。找到API調試,輸入用戶id得到token復制即可。

  

  當我們拿到token之后呢,我們連接一下服務器:

  

         RongIMClient.connect(token, {
                    onSuccess: function (userId) {
                        //連接成功
                    },
                    onTokenIncorrect: function () {
              //token錯誤,如果出現token錯誤,我們重新生成一個即可
}, onError: function (errorCode) { var info = ''; var code = im.code.errorUnKnown; switch (errorCode) { case RongIMLib.ErrorCode.TIMEOUT: //超時break; case RongIMLib.ErrorCode.UNKNOWN_ERROR: //未知錯誤break; case RongIMLib.ErrorCode.UNACCEPTABLE_PaROTOCOL_VERSION: //版本不正確break; case RongIMLib.ErrorCode.IDENTIFIER_REJECTED: //被拒絕break; case RongIMLib.ErrorCode.SERVER_UNAVAILABLE: //服務不可用break; } } });

  我們連接之后呢,打開調試看一下network,可以看到,websocket連接,已經成功了。

  

  看一下日志打印:

  

核心業務-發送消息

  那么上一步已經連接成功了,下一步,我們就要發送消息了。之前已經定義好了消息類型,根據融雲文檔提供的方法,我們將消息組織好,發送即可。首先呢,這里要用到layim的 sendMessage監聽方法了。

                layim.on('sendMessage', function (data) {
                    //調用socket方法,發送消息
                    im.sendMsg(data);
                });

  是不是很簡單,先看一下 layim提供的data是神馬東東:

  

  里面的內容不用我多解釋了吧,我們只要將mine和to解析一下,然后轉換成我們想要的格式即可,這里要注意,group 和 friend 有些區別。請看代碼:

sendMsg: function (data) {
            //根據layim提供的data數據,進行解析
            var mine = data.mine;
            var to = data.to;
            var id = conf.uid || mine.id;//當前用戶id
            var group = to.type == 'group';
            if (group) {
                id = to.id;//如果是group類型,id就是當前groupid,切記不可寫成 mine.id否則會出現一些問題。
            }
            //構造消息
            var msg = {
                username: mine.username
                      , avatar: mine.avatar
                      , id: id
                      , type: to.type
                      , content: mine.content
            }
            //這里要判斷消息類型
            var conversationType = group ? lib.ConversationType.GROUP : lib.ConversationType.PRIVATE; //私聊,其他會話選擇相應的消息類型即可。
            var targetId = to.id;
            //構造消息體,這里就是我們剛才已經注冊過的自定義消息
            var detail = new RongIMClient.RegisterMessage.LAYIM_TEXT_MESSAGE(msg);
            //發送消息
            RongIMClient.getInstance().sendMessage(conversationType, targetId, detail, {
                onSuccess: function (message) {
                    log('發送消息成功');
                },
                onError: function (errorCode) {
                }
            });
        },

  當我們發送消息之后,對方肯定會收到。(除了初始化有問題之外可能收不到,第三方還是比較穩定的,消息都能送達)我們看一下接收到的消息格式,一大堆,其實對我們有用的有timestamp和content里面的內容。

  

  因為之前我們已經初始化了消息接收監聽事件。所以,后邊我們簡單的一句調用就可以了。

   layim.getMessage(message.content);

效果預覽

  

  效果雖然有了,但是和真正的應用還有很大的差距,不過,那些都可以在修改socket.js來滿足需求,同樣,新手可以引用此組件輕松實現聊天功能對接,而且不用寫很多代碼。下面看一下最終的代碼編寫方式:

  

  現在你無需關心layim是怎么接收消息的,以及他的消息格式類型是什么,你只要引入相應的組件,然后做一下簡單的配置,即可完成通訊功能,對於想快速開發並且,不需要保存消息歷史記錄的需求,這個東西就很方便了。對接起來也容易,因為並不是他簡單,而是核心內容已經給封裝好了,做一個簡單的配置即可使用。

細節補充

  日志打印是否開放:

  //記錄日志
    var log = function (msg) {
        conf.log && console.log(msg);
    }

  監聽方法的實現,抄襲layim 嘿嘿。

 //事件監聽
    var listener = function (code) {
        code && (call['status'] ? call['status'](code) : log(code));

    }

  如果初始化比較慢,為了不影響消息發送,采用臨時數組保存。

  sendMsgWithQueue: function (data) {
            if (!im.connected) {
                log('當前服務器未連接,將消息加入到未發送隊列');
                msgQueue.push(data);
            } else {
                this.sendMsg(data);
            }
        },

  連接成功之后,消息發送

 connectSuccess: function (uid) {
            im.code.usuccess.uid = uid;
            im.connected = true;//連接成功

            listener(im.code.usuccess);
            if (msgQueue.length) {
                //隊列中有消息,發送出去
                for (var i = 0; i < msgQueue.length; i++) {
                    im.sendMsg(msgQueue[i]);
                }
                msgQueue = [];
            }
        },

  其他細節有興趣的同學可以看看代碼,並給出修改意見,謝謝大家。請注意,本文依賴於Layim3.0+版本。

 

總結

  寫一篇文章比我開發時間都多了,不過總結一下也是好的,希望能幫到一些需要的同學。同時,完整開發版我會繼續開發下去,由於使用了第三方,所以通訊邏輯我就不會在去關心,重點放在項目的架構上,以及其他東西的研究。如果你讀到了這里,非常感謝。

  github地址:https://github.com/fanpan26/LayIM_NetClient/blob/master/LayIM_RongCloud_Chat/Scripts/im/rc/socket.js


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM