<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jack Jiang

    我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
    posts - 494, comments - 13, trackbacks - 0, articles - 1

    1、HarmonyChat是什么?

    HarmonyChat是一個簡潔的鴻蒙NEXT上的基于WebSocket協議的聊天客戶端 ,它基于MobileIMSDK通信庫, 有完善的網絡通信通力、簡潔的聊天界面UI、合理的代碼拆分和邏輯實現,非常適合學習研究或直接用于簡單的鴻蒙NEXT單頁聊天項目中 。

    HarmonyChat的源碼下載請見本文:5、源碼的開源倉庫地址”。

    2、為什么有HarmonyChat?

    我本身是MobileIMSDK開源框架的作者,正好近期趁著開發MobileIMSDK的鴻蒙NEXT端演示界面的機會,把相關的UI代碼整理出來,希望在當前鴻蒙有質量的資料比較少的情況下,能帶給需要的人一點啟發或幫助。

    你如果在HarmonyChat中看到有關MobileIMSDK的資料和字眼也不要奇怪,因為本工程中的代碼、資料、想法,都是從MobileIMSDK的鴻蒙NEXT端工程中整理和抽取出來的,目的是方便需要的人從單獨的UI界面和功能來學習和使用。

    3、誰需要HarmonyChat?

    目前高質量的鴻蒙NEXT端IM聊天方面的開源代碼還非常少(幾乎找不到有價值的開源分享),所以我希望能把自已編寫的相關代碼抽取出來供需要的人借鑒和使用,共同進步。

    HarmonyChat特別適合以下開發者學習、研究或直接使用:

    • 1) 想學習使用ArkTS和ArkUI開發聊天界面的;
    • 2) 想學習如果在鴻蒙NEXT中對接網絡通信代碼的;
    • 3) 想學習IM聊天程序如何在鴻蒙NEXT中實現UI和網絡數據的邏輯分離的;
    • 4) 想得到可以直接使用的單頁聊天界面的;
    • 5) 想要開發IM聊天應用,但需要一個腳手架作為起點的。

    4、實現了哪些特性?

    1) 實現了一個UI簡潔、代碼清晰、邏輯分層合理的聊天界面(可以直接復制到一些單頁聊天產中品用,比如客服聊天);

    2) 消息的送達狀態在UI界面上會自動更新顯示(包括發送中、已送達、送達失敗);

    3) 網絡連接狀態的UI顯示(含心跳呼吸燈效果);

    4) 實現了真正的網絡通信和聊天(包括完整的多端互踢、網絡心跳、掉線重連、消息重傳、消息應答、消息去重等),這是基于MobileIMSDK通信庫實現的;

    5) 實現了隱私提醒、閃屏、登錄界面的判斷和跳轉邏輯(可以直接復制這幾個界面到你的產品中去用用);

    6)• 鴻蒙NEXT的List列表在LazyForEach帶來的性能優化情況下的動態UI刷新;

    7) 利用DataSource和一個全局消息緩存管理機制實現網絡數據與UI的解偶(這是IM消息和UI解偶的關鍵);

    8) 實現了跟微信基本一致的消息時間計算和顯示邏輯(人性化時間、超過2分鐘才顯示時間);

    9) 合理的拆分了不同消息類型組件式擴展的實現邏輯,方便擴展更多消息類型的UI顯示;

    10) 解決了消息文本超長導致Row()組件被擠出屏幕可視區顯示的問題(這可能是鴻蒙的bug);

    11) 一些鴻蒙NEXT簡單動畫的應用;

    12) 適配全面屏;

    13) 詳細的代碼注釋,便于學習研究。

    5、源碼的開源倉庫地址

    HarmonyChat源碼在以下托管倉庫都是同步更新:

    開源MobileIMSDK的源碼托管倉庫:

    6、HarmonyChat工程概覽

    7、實際運行截圖

    1)Demo 的登陸界面運行截圖(點擊可看大圖 ▼):

    2)Demo 的主界面運行截圖點擊可看大圖 ▼):

    3)Demo 運行的同時,可以查看詳細的 log 輸出(方便調試):

    8、技術要點1:關于服務端的部署和運行

    HarmonyChat中默認連接的是MobileIMSDK開源工程的測試服務端,因條件有限,建議你自已部署服務端。資料請參考:《MobileIMSDK開源服務端的部署指南》。

    你也可以直接拉取MobileIMSDK開源服務端的源碼自行編譯和運行,就像下面這樣:

    PS: MobileIMSDK開源服務端的源碼可以在這個目錄下找到:點此查看 ◄,也可以直接用編譯好的程序雙擊run.bat就可以運行(點此查看 ◄)。

    如上圖所示: HarmonyChat中因為用到的是鴻蒙Next的WebSocket協議,所以請確保MobileIMSDK開源服務端的WebSocket端口是開啟的哦。

    9、技術要點2:關于消息文本超長導致Row()組件被擠出屏幕可視區的問題

    問題描述: 這是我在編寫文本聊天消息組件的過程中遇到的,原圖我沒有截出來,問題大致是下圖這樣(這圖是我在網上找的)。

    問題的原因就是: 為了實現聊天消息氣泡中的超長文本能自適應長度和高度,所以是無法使用layoutWeight屬性的,這會導致Text()所在在Row()父組件,無法正確的計算自已的寬度。

    解決辦法: 就是用Flext()替代Row(),如下圖所示。

    10、技術要點3:關于仿微信消息時間顯示的代碼實現

    大家平時使用微信比較多,它的消息時間顯示是很人性化的,所以現在開發IM聊天應用時,這個消息時間的人性化顯示是必做的。

    以下是本工程中實現的效果(跟微信幾乎一樣):

    如上圖所示,主要實現的是: 對消息時間進行了人性化處理(比如昨天上午xx、今天下午xx、星期x等),以有超過2分鐘才顯示時間的這種邏輯。

    完整代碼涉及到幾個方法,關鍵代碼如下 (具體大家可以看 /entry/src/main/ets/pages/utils/ToolKits.ets 中的相關方法):

    /**

     * 仿照微信中的消息時間顯示邏輯,將時間戳(單位:毫秒)轉換為友好的顯示格式.

     *

     * 1)7天之內的日期顯示邏輯是:今天、昨天(-1d)、前天(-2d)、星期?(只顯示總計7天之內的星期數,即<=-4d);

     * 2)7天之外(即>7天)的邏輯:直接顯示完整日期時間。

     

     * @param timestamp 時間戳(單位:毫秒),形如:1550789954260

     * @param mustIncludeTime true表示輸出的格式里一定會包含“時間:分鐘”

     * ,否則不包含(參考微信,不包含時分的情況,用于首頁“消息”中顯示時)

     * @param timeWithSegmentStr 本參數僅在mustIncludeTime=true時有生效,表示在時間字符串前帶上“上午”、“下午”、“晚上”這樣的描述

     *

     * @return 輸出格式形如:“剛剛”、“10:30”、“昨天 12:04”、“前天 20:51”、“星期二”、“2019/2/21 12:09”等形式

     * @author Jack Jiang([url=http://www.52im.net/thread-2792-1-1.html]http://www.52im.net/thread-2792-1-1.html[/url])

     */

    static getTimeStringAutoShort2(timestamp: number, mustIncludeTime: boolean, timeWithSegmentStr: boolean): string {

      // 當前時間

      let currentDate: Date = new Date();

      // 目標判斷時間

      let srcDate: Date = new Date(timestamp);

     

      let currentYear: number = currentDate.getFullYear();

      let currentMonth: number = (currentDate.getMonth()+1);

      let currentDateD: number = currentDate.getDate();

     

      let srcYear: number = srcDate.getFullYear();

      let srcMonth: number = (srcDate.getMonth()+1);

      let srcDateD: number = srcDate.getDate();

     

      let ret: string = '';

     

      // 要額外顯示的時間分鐘

      let timeExtraStr = '';

      if(mustIncludeTime) {

        // let timeExtraStr = (mustIncludeTime ? " " + _formatDate(srcDate, "hh:mm") : "");

        timeExtraStr = " "+ToolKits.getTimeHH24Human(srcDate, timeWithSegmentStr);

      }

     

      // 當年

      if(currentYear === srcYear) {

        let currentTimestamp: number = currentDate.getTime();

        let srcTimestamp: number = timestamp;

        // 相差時間(單位:毫秒)

        let deltaTime: number = (currentTimestamp-srcTimestamp);

     

        // 當天(月份和日期一致才是)

        if(currentMonth === srcMonth && currentDateD === srcDateD) {

          // // 時間相差60秒以內

          // if(deltaTime < 60 * 1000)

          //     ret = "剛剛";

          // // 否則當天其它時間段的,直接顯示“時:分”的形式

          // else

          //     ret = _formatDate(srcDate, "hh:mm");

     

          // 當天只需要顯示時間分鐘,且必須顯示“上午”、“下午”這樣的時間段描述

          ret = ToolKits.getTimeHH24Human(srcDate, true);

        }

        // 當年 && 當天之外的時間(即昨天及以前的時間)

        else {

          // 昨天(以“現在”的時候為基準-1天)

          let yesterdayDate:Date = new Date();

          yesterdayDate.setDate(yesterdayDate.getDate()-1);

     

          // 前天(以“現在”的時候為基準-2天)

          let beforeYesterdayDate: Date = new Date();

          beforeYesterdayDate.setDate(beforeYesterdayDate.getDate()-2);

     

          // 用目標日期的“月”和“天”跟上方計算出來的“昨天”進行比較,是最為準確的(如果用時間戳差值

          // 的形式,是不準確的,比如:現在時刻是2019年02月22日1:00、而srcDate是2019年02月21日23:00,

          // 這兩者間只相差2小時,直接用“deltaTime/(3600 * 1000)” > 24小時來判斷是否昨天,就完全是扯蛋的邏輯了)

          if(srcMonth === (yesterdayDate.getMonth()+1) && srcDateD === yesterdayDate.getDate()) {

            ret = "昨天"+timeExtraStr;// -1d

          }

          // “前天”判斷邏輯同上

          else if(srcMonth === (beforeYesterdayDate.getMonth()+1) && srcDateD === beforeYesterdayDate.getDate()) {

            ret = "前天" + timeExtraStr; // -2d

          } else{

            // 跟當前時間相差的小時數

            let deltaHour: number = (deltaTime/(3600 * 1000));

     

            // 如果小于或等 7*24小時就顯示星期幾

            if (deltaHour <= 7*24){

              let weekday = new Array<string>(7);

              weekday[0]="星期日";

              weekday[1]="星期一";

              weekday[2]="星期二";

              weekday[3]="星期三";

              weekday[4]="星期四";

              weekday[5]="星期五";

              weekday[6]="星期六";

     

              // 取出當前是星期幾

              let weedayDesc: string = weekday[srcDate.getDay()];

              ret = weedayDesc + timeExtraStr;

            }

            // 否則直接顯示完整日期時間

            else

              ret = ToolKits.formatDate(srcDate, "M月d日")+timeExtraStr;

          }

        }

      }

      // 往年

      else{

        ret = ToolKits.formatDate(srcDate, "yy年M月d日")+timeExtraStr;

      }

     

      return ret;

    }

    11、技術要點4:關于網絡數據與UI界面解偶的實現

    在IM聊天應用中,網絡數據與UI界面解偶是非常關鍵的,否則網絡代碼的復雜性跟應用層邏輯的復雜性合并在一起,那代碼會越寫越困難。

    HarmonyChat中主要是借助了一個全局的消息數據管理器和IDataSource,實現了與聊天列表UI界面的解偶。

    全局的消息數據管理器代碼實現 (詳見 /entry/src/main/ets/pages/utils/MessagesProvider.ets):

    /**

     * 聊天消息的緩存數據管理提供者(集中管理所有的聊天消息和指令,消息來源為網絡層通信數據包和本地發出的包

     * ,消息顯示方式通過MessagesDataSource與UI界面進行解偶顯示)。

     *

     * 代碼參考自IM產品RainbowChat:[url=http://www.52im.net/thread-19-1-1.html]http://www.52im.net/thread-19-1-1.html[/url]

     *

     * @author Jack Jiang([url=http://www.52im.net/thread-2792-1-1.html]http://www.52im.net/thread-2792-1-1.html[/url])

     */

    export default class MessagesProvider {

     

      /** 聊天界面中,消息的顯示時間間隔(單位:毫秒):默認是2分鐘內的消息只在第一條消息上顯示時間,否則會再次顯示時間 */

      // 參考資料:[url=http://www.52im.net/thread-3008-1-1.html#40]http://www.52im.net/thread-3008-1-1.html#40[/url]

      private static readonly CHATTING_MESSAGE_SHOW_TIME_INTERVAL: number = 2 * 60 * 1000;

     

      /** 真正的聊天軟件中,此處應改造為<key=uid, value=Array<Message> >這樣的Map集合,用于按uid分別存儲與各好友的聊天消息 */

      private messages: Array<Message> = [];

     

      /**

       * 加入一條新消息。

       *

       * @param m 消息對象

       */

      putMessage(m: Message): void {

        // 以下代碼用于判斷并實現仿微信的只顯示2分鐘內聊天消息的時間標識(參考資料:[url=http://www.52im.net/thread-3008-1-1.html#40]http://www.52im.net/thread-3008-1-1.html#40[/url])

        let previousMessage: Message | undefined = undefined;

        let messagesSize: number = this.messages.length;

        if (messagesSize > 0) {

          previousMessage = this.messages[messagesSize - 1];

        }

        MessagesProvider.setMessageShowTopTime(m, previousMessage);

     

        // 將此新消息對象放入數據模型(列表)

        this.messages.push(m);

     

        // 通知應用層更新ui

        IMClientManager.getInstance().getEmitter().emit(UIEvent.UIEVENT_messageAdded, this.messages.length - 1);

      }

     

      /**

       * 獲得消息數據緩存集合。

       *

       * @returns 消息數據緩存集合

       */

      getMessages(): Array<Message> {

        return this.messages;

      }

     

      /**

       * 添加一條系統消息(顯示在聊天列表中)。

       *

       * @param content 消息內容

       */

      addSystemMessage(content: string): void {

        let m: Message = Message.createChatMsgEntity_INCOME_SYSTEAMINFO('0', content, 0);

        this.putMessage(m);

      }

     

      /**

       * 更新指定指紋碼的消息的發送狀態(更新單條消息)。

       *

       * @param fingerPrint 消息指紋碼(消息id)

       * @param sendStatus 發送狀態,see {@link MsgSendStatus}

       */

      updateMessageSendStatus(fingerPrint: string, sendStatus: MsgSendStatus): void {

        // 遍歷消息列表

        for(let i = 0; i < this.messages.length; i++) {

          let m = this.messages[i ];

          // 對符合條件的消息對象進行消息發送狀態的設置

          if(m && m.isOutgoing() && m.fingerPrintOfProtocal === fingerPrint) {

            // 更新狀態

            m.sendStatus = sendStatus;

            // 通知應用層更新ui(參數就是消息所在索引)

            IMClientManager.getInstance().getEmitter().emit(UIEvent.UIEVENT_messageUpdate, i);

          }

        }

      }

     

      /**

       * 更新指定指紋碼的消息的發送狀態(更新多條消息)。

       * 目前用于QoS送達機制中告訴應用層有哪些原始消息報文未成功送達給對方。

       *

       * @param  protocals 原始消息報文對象數組,數組中Protocal對象指紋碼(消息id)就是本次要更新的對象,這個數組目前來自于SDK的 EventType.onMessagesLost 事件通知

       * @param sendStatus 發送狀態,see {@link MsgSendStatus}

       */

      updateMessagesSendStatus(protocals: Protocal[], sendStatus: MsgSendStatus): void {

        let updateIndexes: number[] = [];

     

        // 遍歷消息列表

        // this.messages.forEach((m: Message) => {

        for(let mi = 0; mi < this.messages.length; mi++) {

          let m = this.messages[mi];

          for(let i = 0; i < protocals.length; i++){

            let p = protocals[i ];

            // 對符合條件的消息對象進行消息發送狀態的設置

            if(m && m.isOutgoing() && m.fingerPrintOfProtocal === p.fp) {

              // 更新狀態

              m.sendStatus = sendStatus;

              // 加入已更新索引列表集合

              updateIndexes.push(mi);

              break;

            }

          }

        }

     

        if(updateIndexes.length > 0) {

          // 通知應用層更新ui(參數就是消息所在索引)

          IMClientManager.getInstance().getEmitter().emit(UIEvent.UIEVENT_messagesUpdate, updateIndexes);

        }

      }

     

      /**

       * 清空所有消息。

       */

      clear(): void {

        this.messages = [];

      }

     

      /**

       * 為當前的消息對象,設置是否顯示消息時間標識。

       *

       * 此時間顯示邏輯是與微信保持一致的:即只顯示5分鐘內聊天消息的時間標識,參考資料:[url=http://www.52im.net/thread-3008-1-1.html#40]http://www.52im.net/thread-3008-1-1.html#40[/url]

       *

       * @param theMessage 當前消息對象,不可為null

       * @param previousMessage 當前消息的自然時間的上一條消息,此消息可為空(此為空即表示當前消息就是消息集合中的第一條消息)

       */

      private static setMessageShowTopTime(theMessage: Message, previousMessage: Message | undefined): void {

        if(theMessage) {

          if(previousMessage === undefined) {

            theMessage.showTopTime = true;

            return;

          }

     

          // 以下代碼用于判斷并實現仿微信的只顯示5分鐘內聊天消息的時間標識(參考資料:[url=http://www.52im.net/thread-3008-1-1.html#40]http://www.52im.net/thread-3008-1-1.html#40[/url])

          if(theMessage.date - previousMessage.date > MessagesProvider.CHATTING_MESSAGE_SHOW_TIME_INTERVAL)

            theMessage.showTopTime = true;

        }

      }

    }

    IDataSource實現類 (詳見 /entry/src/main/ets/pages/utils/MessagesDataSource.ets):

    /**

     * 聊天界面(ChatPage.ets)中的List列表對應的數據源實現類(負責聊天消息數據的UI顯示)。

     *

     * 注意:本類中的數據來源為全局消息緩存管理類 MessageProvider 中緩存消息集合的對象引用(淺拷貝),相當于共用同一個緩存,無需單

     * 獨維護數據,實現了聊天消息數據的管理(MessageProvider負責)和UI界面顯示(MessagesDataSource負責)的解偶。

     *

     * @author JackJang

     * @since 1.0

     */

    export default class MessagesDataSource extends BasicDataSource<Message> {

     

      /** 引用全局消息緩存管理類 MessageProvider 中緩存消息集合(淺拷貝)*/

      private messages: Array<Message> = IMClientManager.getInstance().getMessageProvider().getMessages();

     

      notifyDataReload(): void {

        super.notifyDataReload();

      }

     

      totalCount(): number {

        return this.messages.length

      }

     

      getData(index: number): Message {

        return this.messages[index]

      }

     

      /**

       * 在List中使用LazyForEach時,響應式ui需要key變化才會更新,本方法就是按可變的內容計算key,從而在DataSource更新時,

       * 能讓ui感知到,不然UI是不會刷新顯示的。

       *

       * @param m 消息對象

       * @returns 計算出的key

       */

      static messageItemKey(m: Message) {

        // 優化點:給更新的消息對象加個最近更新時間戳,這應該是個更通用的key計算項,不然一旦變更內容多了,這個key的計算就不那么優雅了

        return m.msgType + '-' + m.fingerPrintOfProtocal + '-' + m.sendStatus;

      }

    }

    12、技術要點5:關于網絡通信層與UI層的聯動

    HarmonyChat中的網絡通信層與UI層的聯動,主要是通過MobileIMSDK鴻蒙客戶端SDK的事件通知實現的聯動,從而解決了應用層與通信層的代碼解偶。

    MobileIMSDK鴻蒙客戶端SDK提供的事件有下面這些:

    export default class SocketEvent {

        /** 網絡事件:登錄連接或掉線重連響應反饋 */

        static readonly SOCKET_EVENT_ON_LOGIN_RESPONSE: string;

        /** 網絡事件:網絡斷開(掉線了) */

        static readonly SOCKET_EVENT_ON_LINK_CLOSE: string;

        /** 網絡事件:收到新的消息 */

        static readonly SOCKET_EVENT_ON_RECIEVE_MESSAGE: string;

        /** 網絡事件:服務端反饋的錯誤信息(這種錯誤出現即表示連接不可恢復,SDK框架將會自動進入重連動作) */

        static readonly SOCKET_EVENT_ON_ERROR_RESPONSE: string;

        /** 網絡事件:發出的消息沒有成功被送達(沒有收到應答確認包) */

        static readonly SOCKET_EVENT_MESSAGE_LOST: string;

        /** 網絡事件:發出的消息已成功被送達(收到應答確認包) */

        static readonly SOCKET_EVENT_MESSAGE_BE_RECIEVED: string;

        /** 網絡事件:正在嘗試掉線重連動作 */

        static readonly SOCKET_EVENT_RECONNECT_ATTEMPT: string;

        /** 網絡事件:心跳包(客戶端發出的) */

        static readonly SOCKET_EVENT_PING: string;

        /** 網絡事件:心跳包(客戶端收到的) */

        static readonly SOCKET_EVENT_PONG: string;

        /** 網絡事件:客戶端已被強行踢出 */

        static readonly SOCKET_EVENT_KICKOUT: string;

    }

    HarmonyChat中通過監聽以上事件并處理后,拋給UI應用層的事件就非常簡單了,暫時僅僅需要以下幾個事件就實現了當前的UI刷新等任務:

    /**

     * 應用層的各種通知事件類型,這些事件主要用于通知UI界面的更新等。

     *

     * @author Jack Jiang([url=http://www.52im.net/thread-2792-1-1.html]http://www.52im.net/thread-2792-1-1.html[/url])

     */

    export default class UIEvent {

      /** UI事件:登錄或掉線重連完成 */

      static readonly UIEVENT_onIMAfterLoginComplete: string = "uievent.onIMAfterLoginComplete";

      /** UI事件:掉線了 */

      static readonly UIEVENT_onIMDisconnected: string = "uievent.onIMDisconnected";

      /** UI事件:心跳了一次(發出的) */

      static readonly UIEVENT_onIMPing: string = "uievent.onIMPing";

      /** UI事件:心跳了一次(收到的應答包) */

      static readonly UIEVENT_onIMPong: string = "uievent.onIMPong";

      /** UI事件:你被踢了 */

      static readonly UIEVENT_onKickout: string = "uievent.onKickout";

     

      /** UI事件:增加了聊天消息 */

      static readonly UIEVENT_messageAdded = 'uievent.messageAdded';

      /** UI事件:更新了聊天消息(單條聊天消息) */

      static readonly UIEVENT_messageUpdate = 'uievent.messageUpdate';

      /** UI事件:更新了聊天消息(多條聊天消息) */

      static readonly UIEVENT_messagesUpdate = 'uievent.messagesUpdate';

    }

    HarmonyChat中注冊和監聽這些事件的具體代碼邏輯位于 /entry/src/main/ets/pages/utils/IMClientManager.ets類中,代碼有點長就不貼了,請自行查看。

    13、相關資料

    [1] 華為鴻蒙Next官方開發資料

    [2]  MobileIMSDK開源框架的API文檔

    [3]  MobileIMSDK開源IM框架源碼Github地址點此

    [4]  MobileIMSDK-鴻蒙Next端開發手冊(* 推薦)

    [5]  MobileIMSDK-服務端部署手冊

    14、更多IM學習和實踐代碼

    一種Android端IM智能心跳算法的設計與實現探討(含樣例代碼)

    Java NIO基礎視頻教程、MINA視頻教程、Netty快速入門視頻 [有源碼]

    輕量級即時通訊框架MobileIMSDK的iOS源碼(開源版)[附件下載]

    開源IM工程“蘑菇街TeamTalk”2015年5月前未刪減版完整代碼 [附件下載]

    微信本地數據庫破解版(含iOS、Android),僅供學習研究 [附件下載]

    NIO框架入門(一):服務端基于Netty4的UDP雙向通信Demo演示 [附件下載]

    NIO框架入門(二):服務端基于MINA2的UDP雙向通信Demo演示 [附件下載]

    NIO框架入門(三):iOS與MINA2、Netty4的跨平臺UDP雙向通信實戰 [附件下載]

    NIO框架入門(四):Android與MINA2、Netty4的跨平臺UDP雙向通信實戰 [附件下載]

    用于IM中圖片壓縮的Android工具類源碼,效果可媲美微信 [附件下載]

    高仿Android版手機QQ可拖拽未讀數小氣泡源碼 [附件下載]

    一個WebSocket實時聊天室Demo:基于node.js+socket.io [附件下載]

    Android聊天界面源碼:實現了聊天氣泡、表情圖標(可翻頁) [附件下載]

    高仿Android版手機QQ首頁側滑菜單源碼 [附件下載]

    開源libco庫:單機千萬連接、支撐微信8億用戶的后臺框架基石 [源碼下載]

    分享java AMR音頻文件合并源碼,全網最全

    一個基于MQTT通信協議的完整Android推送Demo [附件下載]

    Android版高仿微信聊天界面源碼 [附件下載]

    高仿手機QQ的Android版鎖屏聊天消息提醒功能 [附件下載]

    高仿iOS版手機QQ錄音及振幅動畫完整實現 [源碼下載]

    Android端社交應用中的評論和回復功能實戰分享[圖文+源碼]

    Android端IM應用中的@人功能實現:仿微博、QQ、微信,零入侵、高可擴展[圖文+源碼]

    仿微信的IM聊天時間顯示格式(含iOS/Android/Web實現)[圖文+源碼]

    Android版仿微信朋友圈圖片拖拽返回效果 [源碼下載]

    跟著源碼學IM(一):手把手教你用Netty實現心跳機制、斷線重連機制

    跟著源碼學IM(二):自已開發IM很難?手把手教你擼一個Andriod版IM

    跟著源碼學IM(三):基于Netty,從零開發一個IM服務端

    跟著源碼學IM(四):拿起鍵盤就是干,教你徒手開發一套分布式IM系統

    跟著源碼學IM(五):正確理解IM長連接、心跳及重連機制,并動手實現

    跟著源碼學IM(六):手把手教你用Go快速搭建高性能、可擴展的IM系統

    跟著源碼學IM(七):手把手教你用WebSocket打造Web端IM聊天

    跟著源碼學IM(八):萬字長文,手把手教你用Netty打造IM聊天

    跟著源碼學IM(九):基于Netty實現一套分布式IM系統

    跟著源碼學IM(十):基于Netty,搭建高性能IM集群(含技術思路+源碼)

    跟著源碼學IM(十一):一套基于Netty的分布式高可用IM詳細設計與實現(有源碼)

    跟著源碼學IM(十二):基于Netty打造一款高性能的IM即時通訊程序

    手把手教你實現網頁端社交應用中的@人功能:技術原理、代碼示例等

    SpringBoot集成開源IM框架MobileIMSDK,實現即時通訊IM聊天功能

    基于Netty,徒手擼IM(一):IM系統設計篇



    作者:Jack Jiang (點擊作者姓名進入Github)
    出處:http://www.52im.net/space-uid-1.html
    交流:歡迎加入即時通訊開發交流群 215891622
    討論:http://www.52im.net/
    Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
    本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
    主站蜘蛛池模板: 亚洲伊人久久大香线蕉啊| 在线人成免费视频69国产| 国产精品亚洲一区二区三区在线观看| 亚洲日产乱码一二三区别| 免费无码一区二区| 三年片在线观看免费观看大全一| a级成人免费毛片完整版| 鲁丝片一区二区三区免费| 国产又大又粗又长免费视频| 亚洲国产黄在线观看| 亚洲高清中文字幕综合网| 羞羞网站免费观看| 最近中文字幕免费mv在线视频| 全部免费a级毛片| 亚洲国产成人va在线观看网址| 特级毛片aaaa级毛片免费| 91成人免费在线视频| 亚洲乱码精品久久久久..| 亚洲日本成本人观看| 18pao国产成视频永久免费| 久久亚洲AV无码西西人体| 亚洲国产精品无码观看久久| 免费人成视频在线观看网站| 亚洲人成电影在线播放| 亚洲日韩精品国产3区| 免费能直接在线观看黄的视频| 亚洲综合国产一区二区三区| 日韩久久无码免费毛片软件| 好男人www免费高清视频在线| 亚洲va国产va天堂va久久| aa在线免费观看| 亚洲精品乱码久久久久久蜜桃不卡 | 99爱免费观看视频在线| 亚洲中文字幕在线观看| 91成人免费观看在线观看| 亚洲综合伊人久久综合| 在线看片免费人成视频播 | 国产成人3p视频免费观看| 在线观看亚洲网站| 狠狠综合久久综合88亚洲| 成人久久免费网站|