写点什么

开源 IM 聊天程序 HarmonyChat:基于鸿蒙 NEXT 的 WebSocket 协议

作者:JackJiang
  • 2025-01-03
    江苏
  • 本文字数:9814 字

    阅读完需:约 32 分钟

开源IM聊天程序HarmonyChat:基于鸿蒙NEXT的WebSocket协议

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 源码在以下托管仓库都是同步更新:

  • 1)Github:https://github.com/JackJiang2011/harmonychat 

    2)Gitee:https://gitee.com/jackjiang/harmonychat (* 国内仓库,速度快)

    3)Gitcode:https://gitcode.com/hellojackjiang2011/harmonychat(* 国内仓库,速度快)

    开源 MobileIMSDK 的源码托管仓库:

    1)Github:https://github.com/JackJiang2011/MobileIMSDK

    2)Gitee:https://gitee.com/jackjiang/MobileIMSDK

    3)Gitcode:https://gitcode.com/hellojackjiang2011/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 系统设计篇》

用户头像

JackJiang

关注

还未添加个人签名 2019-08-26 加入

开源IM框架MobileIMSDK、BeautyEye的作者。

评论

发布
暂无评论
开源IM聊天程序HarmonyChat:基于鸿蒙NEXT的WebSocket协议_即时通讯;IM;网络编程_JackJiang_InfoQ写作社区