即时通讯

即时通讯

一把双刃剑 -- 融云即时通讯sdk中的自定义消息使用心得&指南 (下)

IM即时通讯王叫兽 发表了文章 • 0 个评论 • 15 次浏览 • 3 天前 • 来自相关话题

背景:最近公司新上的app要加上即时通讯的功能, 自己快速实现一个当然是不可能的了(项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的不足.最后点兵点将,选了融云家的SDK(老板说了算hhhh).他家的官网和文档地址:... ...查看全部

微信截图_20210224192919.png

背景:

最近公司新上的app要加上即时通讯的功能, 自己快速实现一个当然是不可能的了(项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的不足.最后点兵点将,选了融云家的SDK(老板说了算hhhh).

他家的官网和文档地址: 官网:https://www.rongcloud.cn/ 文档:https://docs.rongcloud.cn/v4

这个任务当然还是落在我的头上. 我是使用的他们家的带UI的sdk,(他们家有带UI和不带UI的两种sdk, 不带UI的sdk就是只有即时通讯能力, 所有的UI都需要开发者自定实现, 带UI的sdk封装了一些基本的界面,例如会话列表, 和别人聊天的会话界面).

心得 (下)

自定义小视频消息

接上篇对自定义消息的开发心得哈.

因为融云家自带的小视频消息是需要收费的, 需要在服务端开通小视频服务后, 同时在端上做一下配置, 才可以使用小视频消息. 我一看这还得了, 想方设法收我钱呢不是. 不过他家只是对小视频类型的消息在服务端做了限制, 而不是完全不让在消息中携带视频链接. 自定义消息是随便自定义的, 那么我自定义一个小视频消息不就好啦.

大概实现思路如下:

自定义小视频消息继承MediaMessageContent,其中mLocalPath是小视频文件本地的存放路径,mMediaUrl是小视频文件上传到文件服务器后的http/https地址。

小视频的拍摄,播放我们RongCloud SDK没有接口,开发者自己实现。

当拍摄完成,发送小视频消息时使用方法

sendMediaMessage(final Message message, final String pushContent, final String pushData, final IRongCallback.ISendMediaMessageCallback callback)或者

sendMediaMessage(final Message message, final String pushContent, final String pushData, final IRongCallback.ISendMediaMessageCallbackWithUploader callback)

这两个方法的不同是后者开发者负责小视频文件的上传到指定的服务器,前者使用我们RongCloud默认的文件服务器

以上是大致步骤,小视频开发过程中可能遇到的问题,说明如下:

1.关于缩略图的处理,我们SDK没有直接上传一张图片返回一个url地址的接口,开发者可以把缩略图上传到自己的服务器,这样缩略图跟mMediaUrl类似,小视频消息展示显示缩略图时加载一张网络图片即可。

另一种缩略图处理方式类似我们SDK发送图片消息时的缩略图处理,把缩略图做base64编码,放到自定义消息体中直接传输,这种方式涉及到消息发送时把缩略图转化为base64数据和接收到消息时还原为缩略图,在我们SDK内部使用的是MessageHandler。

关于MessageHandler,我们RongCloud的每个消息都有一个MessageHandler,此前我们文档从没有介绍过这个

MessageHandler,对用户透明的,用户的自定义消息没有指定它是因为有个默认的DefaultMessageHandler。

自定义消息时可以指定自己的MessageHandler,例如图片消息的定义如下

ImageMessage.png

MessageHandler在消息发送和接收时在IPC进程中会被自动调用,它有两个方法,encodeMessage

和decodeMessage,在消息接收后调用decodeMessage时开发者可以把base64对应的数据转化为缩略图url,这样在展示缩略图时直接使用url即可。

/**
 * 解码 {@link MessageContent} 到 {@link Message} 中。
 *
 * @param message 用于存放 MessageContent 的消息实体。
 * @param content 将要被解码的 MessageContent。
 */
public abstract void decodeMessage(Message message, T content);

/**
 * 对 {@link Message} 编码。
 *
 * @param message 将要被编码的 Message 实体。
 */
public abstract void encodeMessage(Message message);

此文档包含了两个附件分别为自定义小视频消息和对应的小视频消息MessageHandler,供开发者参考

2.开发中可能还会遇到小视频文件上传时进度更新的问题,如果开发者自定义的小视频消息不继承自MediaMessageContent而是MessageContent,需要自己在UI上维护上传进度


一把双刃剑 -- 融云即时通讯sdk中的自定义消息使用心得&指南 (上)

IM即时通讯王叫兽 发表了文章 • 0 个评论 • 13 次浏览 • 3 天前 • 来自相关话题

背景:最近公司新上的app要加上即时通讯的功能, 自己快速实现一个当然是不可能的了(项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的不足.最后点兵点将,选了融云家的SDK(老板说了算hhhh).他家的官网和文档地址:... ...查看全部

微信截图_20210224192427.png

背景:

最近公司新上的app要加上即时通讯的功能, 自己快速实现一个当然是不可能的了(项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的不足.最后点兵点将,选了融云家的SDK(老板说了算hhhh).

他家的官网和文档地址: 官网:https://www.rongcloud.cn/ 文档:https://docs.rongcloud.cn/v4

这个任务当然还是落在我的头上. 我是使用的他们家的带UI的sdk,(他们家有带UI和不带UI的两种sdk, 不带UI的sdk就是只有即时通讯能力, 所有的UI都需要开发者自定实现, 带UI的sdk封装了一些基本的界面,例如会话列表, 和别人聊天的会话界面).

需求:

融云的体系中默认的消息类型只有9种.


功能     |     描述


文字消息       |     用来发送文字类消息,其中可以包括表情、超链接(会自动识别),客户端收到消息后计入未读消息数、进行存储。

语音消息     |     发送高质量的短语音消息,录制的语音文件存储到融云服务端,语音文件格式为 AAC,时长上限为 60 秒,客户端收到消息后计入未读消息数、进行存储。

图片消息     |     用来发送图片类消息,客户端收到消息后计入未读消息数、进行存储。图片缩略图格式为 JPG,大小建议不超过 100k。

GIF 图片消息     |     用来发送 GIF 动态图片消息,客户端收到消息后计入未读消息数、进行存储。

图文消息     |     用来发送图文消息,包含一个标题,一段文字内容和一张图片,客户端收到消息后计入未读消息数、进行存储。

文件消息     |     用来发送文件类消息,客户端收到消息后计入未读消息数、进行存储。

位置消息     |     用来发送地理位置消息,客户端收到消息后计入未读消息数、进行存储。

小视频消息     |     用来发送小视频消息,支持录制发送及选择本地视频文件发送两种方式,录制时长不超过 10 秒,本地选择视频文件方式时长不超过 2 分钟,小视频消息小视频文件格式为 .mp4,客户端收到消息后计入未读消息数、进行存储。

合并转发消息     |     IMKit SDK 中支持将多条消息合并为一条消息进行发送,合并后的消息以 HTML 文件的方式存储到融云服务端,客户端收到消息后计入未读消息数、进行存储。

这9种消息其实已经满足大部分的即时聊天场景了, 无论是打字聊天最普通的文本消息, 还是长按录制发送的语音消息, 以及图片消息, 分享位置的消息. 基本上微信有的场景, 都覆盖到了.

但是因为各家的产品各不相同, 有人需要一个比微信功能更简洁的聊天工具, 有人则需要一个像QQ那般功能强大的聊天工具. 总是有千奇百怪不同的需求的. 像我们的app就是这样, 总有场景是这里无法满足的. 好比QQ是可以把图片和文本消息放入同一个消息气泡中的(类似于富文本消息), 那么这样的情况下, 默认的几类消息就不够用了.

不过融云还是把这块做的很到位的, 暴露了类和接口让用户去对消息做自定义, 基本上可以做到, 想把消息定义成什么样就定义成什么样子.

心得(上)

这里就举一些我在开发我们公司app时, 用到的自定义消息, 以及使用心得和指南.

只发给当前在线用户的限时奖励通知

只给当前在线用户发送消息, 我们有一种游戏奖励是只发放给特殊时段在线的用户的, 只有当前在线的用户才能接收到这种消息来领取奖励, 其他在该时段未在线的用户, 不能接收到, 且再次登录后也不能接收到保留的离线消息. 这个需求就是做了一个自定义消息来实现的. 把自定义消息类的 MessageTag 中 flag 值设置为 MessageTag.STATUS。此消息类型即为状态消息,状态消息不存储不计数,并且当接收方不在线时,此消息会直接丢弃,用户再上线也不会收到该消息。

有需要的同学可以看他们家关于自定义消息的文档:https://docs.rongcloud.cn/im/imkit/android/conversation/custom_message/

发送自定义消息后撤回消息,撤回消息会失败

这里积累了一个经验, 也算是帮大家踩踩他们家的坑了, 那就是: 使用以下废弃方法发送自定义时会出现此错误:

在发送自定义消息后,撤回消息时没有反应,退出会话界面再次进入后可以正常撤回消息。 在 log 中显示 recallMessage errorCode = 25101。

public Message sendMessage(ConversationType type, String targetId, MessageContent content, String pushContent, String pushData, final SendMessageCallback callback) {

必须要换成这个方法发送才行:

public void sendMessage(Message message, String pushContent, String pushData, final ISendMessageCallback callback)

这个问题也是蛮坑的, 害. 找他们家技术支持费了点劲才排查出来, 希望大家遇到这种问题能快快找到我这篇经验哈.


融云4.x 版本升级到5.0 版本出现的问题

IM即时通讯柠檬^ 发表了文章 • 0 个评论 • 15 次浏览 • 3 天前 • 来自相关话题

1. 4.x 版本与5.x 版本的区别  主要是针对 IMKit(带 UI 界面)进行了重构,并且 5.0 版本以上的 IMKit 进行了开源,可以在 &nbs... ...查看全部

微信截图_20210224192708.png1. 4.x 版本与5.x 版本的区别

  主要是针对 IMKit(带 UI 界面)进行了重构,并且 5.0 版本以上的 IMKit 进行了开源,可以在  https://github.com/rongcloud/imkit-android 进行下来进行集成;

2. 5.x 版本主要的跳转方式

   在之前4.x 版本的SDK 中,界面之间的跳转主要是使用隐式调用的,在5.x 版本则全部改用为显示跳转,并且引入路由的概念,具体可以参考 RouteUtils 这个工具类。

3. 4.x 以及5.x 主要的api 感知变化

  为了方便平滑升级,以及兼容性,所以对外引用 api 并无太大改变,都是通过 RongIM 进行引用。

4. 5.x 自定义消息的变化

主要是针对展示方式变化,取消之前的注解方式,改为复写 MessageItemProviderConfig 的方式,通过代码动态加载来进行展示,设置方式是在自定义的provider 中进行设置config 即可;


融云 IMKit SDK 5.X 升级说明

IM即时通讯fanta2 发表了文章 • 0 个评论 • 23 次浏览 • 5 天前 • 来自相关话题

Tips如果您应用依赖于 suport 包,可参考 AndroidX 迁移文档将依赖转换为 AndroidX 后,再集成 IMKit SDK 5.X版本。1. 类路径调整IMKit SDK 5.X 版本重构了 SDK 的架构,通过 MVVM 框架实现... ...查看全部

Tips

如果您应用依赖于 suport 包,可参考 AndroidX 迁移文档将依赖转换为 AndroidX 后,再集成 IMKit SDK 5.X版本。

微信截图_20210222180400.png

1. 类路径调整

IMKit SDK 5.X 版本重构了 SDK 的架构,通过 MVVM 框架实现,导致很多类路径发生了更改,下表列出了 5.X 之前版本对外公开类的路径变更:

2.x 、4.x 版本路径
io.rong.imkit.fragment.ConversationListFragment
io.rong.imkit.fragment.ConversationFragment
io.rong.imkit.RongExtension
io.rong.imkit.userInfoCache.RongUserInfoManager
io.rong.imkit.mention.RongMentionManager
io.rong.imkit.manager.IUnReadMessageObserver

5.x 版本路径
io.rong.imkit.conversationlist.ConversationListFragment
io.rong.imkit.conversation.ConversationFragment
io.rong.imkit.conversation.extension
io.rong.imkit.userinfo.RongUserInfoManager
io.rong.imkit.feature.mention.RongMentionManager
io.rong.imkit.manager.UnReadMessageManager.IUnReadM

路径调整 Tips

参照上表,在 AndroidStudio 中 command+shift+R 全局搜索旧的类路径,替换为新路径。 如果深度定制化了 IMKit SDK,部分类路径的调整可能不在上述列表中,升级以后 AndroidStudio 会有红色报错。删除报错类里红色未识别的导入路径,鼠标停留到报错的地方,根据 AndroidStudio 的提示导入新路径即可。如果有多个地方使用了该路径,可以参考第一步里的方法,全局搜索并替换。

2. 集成方式变更

页面跳转时由原先的隐式调用方式更改为显示调用, 因此集成步骤有所简化和更改。您需要先移除旧版本 AndroidManifest.xml 文件中关于 IMKit SDK 的配置,参考官网文档重新集成。

3. 消息展示模板变更

列表页由 ListView 更改为效率更高的 RecycleView,因此自定义消息的展示模板需要对应调整。

将自定义消息的展示模板更改为继承 BaseMessageItemProvider<>, 并实现基类方法。 移除展示模板里原先的注解,原注解属性可在新模板构建类里通过调用基类成员 mConfig 的各个方法进行配置

4. 内部实现变更

资源名称变更。IMKit SDK 5.x 版本重新统一了资源名称的命名,如果您自定义了部分资源文件,可参考官网自定义文档,重新替换对应名称的资源。

移除了 EventBus 。IMKit 5.x 版本不再依赖于 EventBus 进行事件分发,更改为通过观察者模式实现。如果您应用里使用了旧版本 SDK 里的 EventBus, 升级后需要您从应用层自己引入依赖。

移除 RongContext 类。如果您应用里有调用 RongContext 作为上下文使用的地方,请更改为调用您自己的应用上下文。

由于更改为 MVVM 框架,原 fragment 里很多业务相关接口被移除,您可参考官网 5.x 版本文档重新进行页面自定义。



融云 FCM 推送与打包方式有关

IM即时通讯fanta2 发表了文章 • 0 个评论 • 34 次浏览 • 5 天前 • 来自相关话题

1.一切都配置完成之后, 开始测试. 第一次启动App, 杀死. 发送测试消息. 收不到推送.2.再次启动App, 杀死, 发送测试消息. 这次能收到推送了.第一次杀死App之后, 发送测试消息, 可以看到log中会即时打出:09-17 11:50:... ...查看全部

1.一切都配置完成之后, 开始测试. 第一次启动App, 杀死. 发送测试消息. 收不到推送.
2.再次启动App, 杀死, 发送测试消息. 这次能收到推送了.

第一次杀死App之后, 发送测试消息, 可以看到log中会即时打出:

09-17 11:50:34.298 W/GCM ( 2025): broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE pkg=com.rongcloud.fcm_demo (has extras) }

GCM打出的log, result=CANCELLED. 广播的intent发送回调是: cancelled. 也就是这个广播还没发送到app层/sdk层, 就已经被系统拦截到了. 失败了.

最开始以为是App关于GCM, 或者FCM的权限问题. 在manifest里遗漏了某个配置, 或者App的通知权限没有打开. 但是做了一番检查以及配置之后, 这个问题还是存在.
之后求助于Google和StackOverflow, 发现有些人是遇到过类似问题的, 但是都没有一个很好的解决方案, 把网上的解决方法一一尝试之后, 这个顽固的问题还是存在.

后来也是一个偶然的发现, 如果我在IDE中直接点击“Run”把App安装运行到手机上, 会出现这个问题, 但是我把项目打包成apk后, 再安装到手机上. 这个问题就消失了, 第一次杀死App之后, 也是可以顺利收到消息的. 这样才把这个问题给解决掉.


美国、日本、俄罗斯版“微信”大PK,即时通讯软件如何流量变现?

IM即时通讯赵炳东 发表了文章 • 0 个评论 • 116 次浏览 • 2021-02-03 17:12 • 来自相关话题

即时通讯软件可以说是互联网时代的基础设施了,从全球范围看,虽然各类即时通讯软件如雨后春笋般出现,但是真正能留在消费者手机中的却凤毛麟角,本文将主要对比美国版微信Whatsapp、日本版微信Line以及俄罗斯版微信Telegram的主要盈利模式。壹美国微信Wha... ...查看全部

即时通讯软件可以说是互联网时代的基础设施了,从全球范围看,虽然各类即时通讯软件如雨后春笋般出现,但是真正能留在消费者手机中的却凤毛麟角,本文将主要对比美国版微信Whatsapp、日本版微信Line以及俄罗斯版微信Telegram的主要盈利模式。

壹美国微信Whatsapp:拒绝广告,赚B端的钱2009年,Jan Koum和Brian Acton开发了一款用于“状态更新的APP”,并将之命名为“Whatsapp”。当这个软件升级到2.0的时候,也就真正开始了其作为即时通讯软件的生涯。
作为一个拥有16亿月活(MAU)用户的超级APP,网络效应早已经形成,但是如何赚钱成了问题——因为其开发者鲜明地表达了拒绝通过广告赚钱的逻辑。

1.jpg

按照Whatsapp开发者的观点,他们希望能为用户创造一个即时通讯平台,而不是为企业创造一个放广告的平台。于是,起先的逻辑是收取每个用户每年1美元的订阅费。
这时候就不得不提及Whatsapp的融资历程了:它的第一轮融资来自5位前雅虎的朋友,总额为25万美元;而它的第二轮和第三轮投资者就值得一说了,那就是大名鼎鼎的红杉资本(Sequoia Capital),总额6000万美元(2011年800万美元,2013年5200万美元)。
这些融资基本就负担了Whatsapp公司的所有开销,考虑到运营这个项目的成本并不是很高——事实上,主要的开销是向用户发送验证码,所以Whatsapp取消了向C端收取1美元/年订阅费的做法。
之后,当Whatsapp再次进入视野的时候,就是Facebook的扎克伯格收购Whatsapp了:在追逐Whatsapp长达2年之后,2014年2月,Facebook以190亿美元收购Whatsapp,而创始人Jan Koum也得以加入Facebook董事会。
收购之后,Whatsapp的价值就显现了:Facebook不仅将之视为一个用户数据的“留量池”,更将之纳入自己的生态体系。
Facebook推出了Whatsapp Business Application,也就是商业版Whatsapp,这样企业就可以在上面建立自己的官方档案,并得到系统认证。在档案中,这些企业可以将自己的网站链接、Facebook主页链接挂上去,甚至可以将他们的座机号连在Whatsapp中。

目前,商业版Whatsapp对于企业来说依然免费,Whatsapp是通过商业API赚钱。 Whatsapp商业API可以把Whatsapp和企业的系统进行整合,通过通知让企业和消费者接触。为了避免垃圾信息,Whatsapp限制了企业发送消息的能力,只有消费者首先联系了公司以后,公司才可以联系消费者(这点和微信的公众平台非常相似),不过API也可以帮助企业向消费者发送送货确认、活动门票等,目前Whatsapp的商业API已经和Booking.com等客户进行了深度合作。

至于Whatsapp如何通过API赚钱,那就很有趣了,Whatsapp向回复缓慢的企业收取费用。
正常情况下,当消费者联系企业后,企业可以在24小时内回复,这是免费的;但是时间一旦超过24小时,此时API就会收费,其费用是固定的,根据国家有所不同。
听起来似乎是一个特别蠢的收费逻辑,但是对于那种百万级用户的企业来说,这就卡住了咽喉:一个订票网站怎么可能同时处理百万级用户的咨询呢?所以这个需求是确实存在的。

此外,在印度,Whatsapp还有支付功能,这可能帮助Whatsapp成为当地用户首选的“寄钱APP”——就像Venm一样,这也可以成为未来的盈利点。
在F8大会上,扎克伯格也提到了这一点,未来他将把Whatsapp的支付功能拓展到更多国家,这对于希望从Whatsapp的网络效应中赚钱的商家,有极大吸引力。
至于盈利数据,Whatsapp目前没有公开过财报,来自福布斯(Forbes)的估算显示,其年收入约50亿美元,ARPU在2020年可以达到4美元。

贰日本微信Line:广告为生,内容为辅在亚洲,Line主要流行于日本、泰国、印尼和中国台湾地区,该公司成立于2000年9月,于2016年7月同时在日本、美国的纽约证交所上市,其主要股东是韩国搜索引擎巨头Naver。
从Line的财报看,2019年4季度(财年截止于2019年12月31日)它的营业收入达到608亿日元,同比增长8.6%,按照地区划分,71%的收入来自日本,29%来自海外。
同期,其在日本的MAU同比增加5.1%,季度MAU达到1.64亿,同时DAU/MAU也达到了79%,也证明了Line的用户活跃度。
从收入角度看,Line共有3个核心收入源,按营收占比,第一是广告(55.4%),第二是交流/内容/其他(29.8%),第三是战略业务(14.8%)。
在广告方面,Line主要是展示广告(Display Ads)和账号广告(Account Ads),二者占总广告收入的93.2%,而展示广告收入同比增长达到65.4%。考虑到Line为各类商家提供大量广告服务,这个成为核心收入源也就十分正常了。

Line的第二大收入源是交流/内容/其他,这部分收入比较稳定,占比超过一半的是内容部分,分别是音乐业务Line Music和漫画业务Line Manga,目前音乐业务同比增长超过40%,漫画业务也有20.1%。
继续往下挖一层,值得一提的是两点,第一点是Line的内容业务,这一部分可以简要称之为“贴纸、壁纸”。用户可以在“主题商店”和“贴图商店”中充值“Line积分”购买壁纸和表情包。

这部分可以和微信进行对比:在微信上,艺术家可以制作表情上架微信,用户对表情的打赏将直接进入艺术家账户。

第二点是“其他”,根据其财报显示,这部分主要是研究业务“Line Research”,财报写道:“有超过500万用户注册成为问卷答卷人,此项业务依然在稳健增长”,为企业提供用户调查,这也属于是对用户的货币化方法之一了。
最后是Line的第三大收入源,Line在财报中将之称为“战略业务(Strategic)”,2019Q4总收入为90亿日元,其中51亿日元收入来自IP业务“LINE FRIEND”,这里主要销售IP赋能的玩具、文具、日用品等;另外的39亿日元来自O2O/电商、Fintech和AI业务。

不过,这里更值得注意的是Line打造的支付业务“Line Pay”,2019Q4,其全球GMV达到3550亿日元,全球MAU达到650万,相比2019Q3分别增长680亿日元和100万。

整体而言,Line的收入源还是比较多的,在广告收入之外,主要是内容(漫画、音乐、表情)、IP变现以及支付业务。对于Line来说,广告和支付业务成为重要收入源并不难以想象,而内容业务的收入更多是和日本等地用户对于漫画、音乐、IP等的认可,以及二次元环境密不可分的。

叁,俄罗斯微信Telegram:绝对免费、绝对安全,发币赚钱对于不少国内用户来说,Telegram的火爆得益于曾经的“发币狂潮”——大量用户为了获得糖果空投(Airdrop)而注册Telegram,加入“电报群”。
相比于其他即时通讯软件,Telegram主打两点,第一是永远免费,第二是绝对加密。
事实上,在成立之初,Telegram就主打“隐私(Privacy)”,其创始人Pavel Durov在2013年创建Telegram,并在短时间内实现爆炸性用户增长,他曾说,在推出Telgram的15个月后,用户在Telegram上就发送了10亿条信息,而VKontakte(这是Durov之前的创业项目)花了6年半才做到的里程碑。
他同时写道,“Telegram的5000万用户均匀地分布在各个大陆,最活跃的用户来自西班牙、巴西、韩国、墨西哥、德国、马来西亚、新加坡、印度、沙特、意大利和美国,而俄罗斯的比例是1%。”
至于所谓的安全性,其实不必看Telegram的官方介绍,只需要看新闻就可以了:
据Trend Micro发布的一份关于恐怖分子通讯方式的研究报告显示,34%的恐怖分子使用Telegram进行沟通,该研究也证实了此前有关极端组织“伊斯兰国(ISIS)”使用Telegram进行秘密信息交换。
和Whatsapp类似,Telegram也不通过广告赚钱,同时还保持了开源的特性,截止到2019年,Telegram没有盈利,或者说没有创造过收入,其创始人Durov在一篇博客上写道,如果资金不足,他可能会引入“非必要的付款选项(non-essential paid options)”来给程序员发工资。
传统的收入来源都没有,Telegram却有“新的收入来源”,那就是“发币”。
2018年1月到3月,Telegram进行了代币首次发行。其白皮书显示,Telegram的加密代币被命名为“Gram”,总发行量为50亿,其中52%用于开发、44%用于代币首次发行,以及余下4%给予团队。
Telegram的区块链网络名为“TON”,该区块链项目将分为四个分支:TON服务、TON DNS、TON支付和TON区块链。
最后,这场宏大的代币首次发行募集了约17亿美元(全世界的投资者购买了约29亿个Gram代币),而来自今年1月初的报道显示,美国证券交易委员会(SEC)提交了一份法院指令,要求Telegram解释代币首次发行所产生的资金是如何使用的。不过迄今为止,Telegram一直拒绝公开账目,并且表示Gram不是有价证券(Security)。
Ton网络原定于2019年10月上线,但美国证券交易委员会将 Telegram 的上线日期推迟到了2020年4月。所以目前没人说的清Telegram到底是用这笔钱干了什么,只能关注今年4月份会不会有新的消息,并希望这一场代币首次发行不是一场闹剧。

总结整体来说,可以发现,即时通讯软件们虽然最终盈利模式并不相同,但是发展模式非常接近,可以抽象为:
1.0时代,免费的时代,主打用户之间的连接、交流,这个时代以两个“结论”作为最终答卷,APP本身看,就是DAU、MAU和用户数,而从外部看就是在市场内的占有率;
2.0时代,赚钱的时代,一般来说,APP在此时已经在一个地区成为至少是Top2的巨头,沉淀了海量用户,此时B端企业就会盯上这个APP,开始做营销、服务,而APP就可以“顺坡下驴”为这些B端企业开发功能模块,进行服务抽成——例如GMV抽成,基本来说在这个领域,中国的微信早已走在了前面。

(来源于公众号-零售威观察)

IM 消息数据存储结构设计

IM即时通讯admin 发表了文章 • 0 个评论 • 128 次浏览 • 2021-01-28 14:25 • 来自相关话题

1背景在移动互联网高速发展的时代,生活中 IM 类产品已经是我们离不开的应用了,像微信、钉钉等都是以 IM 为核心功能的社交产品。另外也有一些应用不是以 IM 为核心,但是也是其重要功能,比如在线游戏、电商直播等应用。在 IM 庞大的体系中,消息系统无疑是最核... ...查看全部

1背景

在移动互联网高速发展的时代,生活中 IM 类产品已经是我们离不开的应用了,像微信、钉钉等都是以 IM 为核心功能的社交产品。另外也有一些应用不是以 IM 为核心,但是也是其重要功能,比如在线游戏、电商直播等应用。

IM 庞大的体系中,消息系统无疑是最核心的,而消息系统中,最关键的部分是消息的分发和存储。

在以往传统消息系统中,对于在线的用户,消息会直接实时发送到在线的接收方,消息发送完成后,服务器端并不会对消息进行落地存储。对于离线的用户,服务器端会将消息存入到离线库,当用户登录后,从离线库中将离线消息拉走,然后服务器端将离线消息删除,这样的缺点是消息不持久化,导致消息无法支持消息漫游,降低了消息的可靠性。而在我们的消息系统中,服务器只要接收到了发送方发上来的消息,在转发给接收方的同时也会在离线数据库以及历史消息库中进行消息的落地存储,消息的落地也就支持了整体的消息漫游等相关功能。

 

2离线消息和历史消息的区别

离线消息,就是用户在离线过程中收到的消息,这些消息大多是用户比较关心的消息,具有一定的时效性。我们的系统设计,离线消息默认只保存最近七天的消息。离线消息在用户登录后会全量的获取,然后客户端根据会话进行整体离线消息的展示。

历史消息,存储了用户所有的消息,包括发的消息以及接收的消息。在客户端获取历史消息时,是按照会话进行分页获取的。历史消息的存储时间我们系统设计默认为半年,当然这个是可配置的。

3消息的发送以及存储的流程

融云整体的消息发送以及存储的流程如下图所示:

1.png

用户发送消息到服务器端后,首先会进入到消息系统中,消息系统会对消息进行分发以及存储。对于在线的接收方,会选择直接推送消息,但是遇到接收方不在线或者是消息推送失败的情况下,也会有另外的消息获取方式,接收方会主动向服务器拉取未收到的消息,但是接收方何时来服务器拉取消息以及从哪里拉取是未知的,所以消息存入到离线库的意义也就在这里。

   消息系统存储离线的过程中,为了不影响整个系统的更为平稳,融云使用了消息队列,消息是异步存入到离线库中的。

   在分发完消息后,消息服务会同步一份消息数据到历史消息服务中,历史消息服务会对消息进行落地存储。对于新的同步设备,会有消息漫游的需求,这也是历史消息的主要作用。在历史消息库中,客户端可以拉取任意会话的全量历史消息。

4 离线消息以及历史消息存储区别

   上述的图中我们能清晰的看到,离线消息我们存储介质选用的是 Redis,历史消息我们选用的是 HBase。为何选用不同的存储介质针对的是不同的业务场景和读写模式。下面我们重点介绍一下离线消息和历史消息存储的区别。

离线消息的存储模式是放大写,如下图所示,每个用户都有自己单独的收件箱和发件箱,收件箱存放需要向这个接收端同步的所有消息,发件箱里存的是发送端发送的所有消息。二人会话中的消息会产生两次写,发送者的发件箱以及接收端的收件箱。而在群的场景下,写入会被更加的放大,如果群里有 N 个人,那一条群消息就会被放大写 N 次。

放大写的优点是,接收端的逻辑会非常清晰简单,只需要从收件箱里读取一次即可,大大降低了同步消息所需的读的压力,但是缺点就是写入会被放大,特别是针对群这种场景。

2.png

历史消息的存储模式是放大读,因为历史消息中,每个会话都保存了整个会话的全量消息。在放大读这种模式下,每个会话的消息只保存一次。相比放大写的那种模式,写入次数大大降低,特别是针对群消息,只需要存一次即可。但是缺点是接收端接收消息非常的复杂和低效,因为这种模式客户端想拉取到所有消息就只能每个会话同步一次,读就会被放大,而且可能会产生很多次无效的读,因为有些会话可能根本没有新消息。

3.png

  IM 这种应用场景下,通常会用到写扩散这种消息同步模型,一条消息产生一条,但是可能会被读多次,是典型的读多写少的场景。一个优化好的系统,必须从设计上平衡读写压力,避免读或者写任意一个维度达到天花板。当然写扩展这种模式也有其弊端,比如万人群,会导致一条消息,写入了一万次。综合来讲,我们需要根据自己的业务场景做相应设计选择,我们的系统是根据了离线和历史消息的不同场景选择了写扩散和读扩散的组合模式。

5 客户端拉取消息

    离线消息的获取针对的是自己的整个离线消息,包括所有的会话。离线消息的获取是自上而下的方式,一次获取 200 条。在客户端拉取离线消息的信令中,需要带上当前客户端缓存的消息的最大时间戳,上面的图我们应该知道,离线消息我们存储的是一个线性结构,Server 会根据这个时间戳向下查找离线消息,重装或者新安装 App 时,客户端可以传 0 上来,Server 也会缓存客户端拉取到的最后一条消息的时间戳,然后根据业务场景,客户端类型等因素来决定从哪里开始拉取,如果没有拉取完 Server 会在拉取消息的应答中带相应的标记位,告诉客户端继续拉取,客户端循环拉取,直到所有离线消息拉完。

历史消息的获取针对的是单一会话,在拉取过程中需要带上来对方的 ID(如果是单聊的话就是对方的 UserID,如果是群,则是群组 ID 以及当前会话的最前面消息的时间戳,Server 会定位到这个人的这个会话然后一次获取 20 条,采用的是自下而上的方式,即从最后面往前翻。只要有消息,客户端可以一直向前翻,手动触发获取会话的历史消息。

 

6总结

   本篇文章主要讲了 IM 中消息系统的消息分发、存储等,重点介绍了离线消息和历史消息的区别以及两者存储中所选用的不同存储方式以及其优缺点。关于文中内容,也欢迎大家随时留言与我讨论。


技术实践丨IM 消息同步机制全面解析

IM即时通讯柠檬^ 发表了文章 • 0 个评论 • 104 次浏览 • 2021-01-21 11:09 • 来自相关话题

综述即时通讯系统最基础、最重要的是消息的及时性与准确性,及时体现在延迟,准确则具体表现为不丢、不重、不乱序。综合考虑业务场景、系统复杂度、网络流量、终端能耗等,融云精心设计了消息收发机制,并不断打磨优化,形成了现在的消息同步机制。整体思路:1.客户端、服务端共... ...查看全部
综述


即时通讯系统最基础、最重要的是消息的及时性与准确性,及时体现在延迟,准确则具体表现为不丢、不重、不乱序。

综合考虑业务场景、系统复杂度、网络流量、终端能耗等,融云精心设计了消息收发机制,并不断打磨优化,形成了现在的消息同步机制。

整体思路:
1.客户端、服务端共同配合,互相补充。
2.采用多重机制,从不同层面保障。
3.拆分上下行,分别处理。

协议层

首先,从协议层保证,协议栈需要提供可靠、有序的双向字节流传输,融云自研通信协议 RMTP(RongCloud Message Transfer Protocol)。

1.jpg

协议交互示意图


协议层通过 qos、 ack 等机制,保证数据传输的可靠性。

业务层

在关键业务,采用 ack 确认机制,配合状态机,服务感知当前业务传输状态,保障业务按照预期执行。

2.jpg

业务层确认机制示意图


消息 ID

采用全局唯一的消息 ID 生成策略。保证消息可通过 ID 进行识别,排重。

3.jpg

如何实现分布式场景下唯一 ID 生成,请点击融云过往技术文章了解。


客户端服务端交互

客户端与服务端之间使用长连接,基于 RMTP 协议传输数据。
经过总结,主要用三种行为:

1.客户端主动拉取消息,主动拉取有两个触发方式:
①与 IM 服务新建立连接成功,用于获取不在线的这段时间未收到的消息。(此处叫做获取离线消息)
②定时器触发。在客户端最后收到消息后启动定时器,比如 3-5 分钟执行一次, 主要有两个目的,一个是用于防止因网络,中间设备等不确定因素引起的通知送达失败,服务端客户端状态不一致,一个是可通过本次请求,对业务层做状态机保活。

2.服务端主动-发送消息(直发消息) 在线消息发送机制之一,简单理解为服务端将消息内容直接发送给客户端,适用于消息频率较低,并且持续交互,比如二人或者群内的正常交流讨论。

3、服务端主动-发送通知(通知拉取) 在线消息发送机制之一,简单理解为服务端给客户端发送一个通知,通知包含时间戳等可作为排序索引的内容,客户端收到通知后,依据自身数据,对比通知内时间戳,发起拉取消息的流程。适用于较多消息传递。比如某人有很多大规模的群,每个群内都有很多成员正在激烈讨论。通过通知拉取机制,可以有效的减少客户端服务端网络交互次数,并且对多条消息进行打包,提升有效数据载荷。既能保证时效,又能保证性能。

4.jpg

客户端服务端交互示意图


业务拆分

在有了多层机制保证后,将业务进行拆分,首先将业务拆分出上下行,在上行过程保证发送消息顺序,为了保证消息有序, 最好的方式是按照 userId 区分,然后使用时间戳排序。那么分布式部署情况下,将用户归属到固定的业务服务器上,会使得上行排序变得更容易。同时归属到同一个服务器,在多端维护时也更容易。

客户端连接过程
1.客户端通过 APP server ,获取到连接使用的 token。
2.客户端使用 token 通过导航服务,获取具体连接的 IM 接入服务器(CMP),导航服务通过 userId 计算接入服务器,然后下发,使得某一客户端可以连接在同一台接入服务器(CMP)。

5.jpg

示意图


上行

客户端发出消息后,通过接入服务,按照 userId 投递到指定消息服务器,生成消息 Id, 依据最后一条消息时间,确认更新当前消息的时间戳(如果存在相同时间戳则后延),然后将时间戳,以及消息 Id,通过 Ack 返回给客户端 ; 然后对上行消息使用 userId + 时间戳进行缓存以及持久化存储,后续业务操作均使用此时间戳。(此业务流程我们成为上行流程,上行过程存储的消息为发件箱消息)

下行

消息节点在处理完上行流程后,消息按照目标用户投递到所在消息节点,进入下行流程。下行过程,按照目标 userId 以及本消息在上行过程中生成的时间戳,计算是否需要更新时间戳(正向)。如果需要更新则对时间戳进行加法操作,直到当前用户时间戳不重复。如此处理后,目标用户的存储以及客户端接收到消息后的排重可以做到一致,并且可以做到同一个会话内的时间戳是有序的。从而保证同一个接收用户的消息不会出现乱序。

至此,我们已经完成了发送过程,接收过程的消息顺序保障,那么消息流程还剩下直发与通知拉取的处理流程,以及服务端如何选择是直发还是通知拉取。

直发消息

1、客户端 SDK 依据本地存储的最新消息时间戳判断,用来做排序等逻辑。
2、对同一个用户直发消息1条,其他转通知。通知拉取时候客户端选择本地最新一条消息时间戳作为开始拉取时间。
3、在消息发送过程中,如果上一条消息发送流程未结束,下一条消息则不用直发(s_msg),而是用(s_ntf)

6.jpg

直发逻辑示意图


通知拉取

1.服务端在通知体中携带当前消息时间戳。投递给客户端。
2.客户端收到通知后,比对本地消息时间戳,选择是否发拉取消息信令。
3.服务端收到拉取消息信令后,以信令携带的时间戳为开始,查询出消息列表(200 条或者 5M),并给客户端应答。
4.客户端收到后,给服务端 ack,服务端维护状态。
5.客户端拉取消息时使用的时间戳,是客户端本地最新一条消息的时间戳。

7.jpg

上图中,3-7 步可能需要循环多次,有以下考虑: 1.客户端一次收到的消息过多,应答体积过于庞大,传输过程对网络质量要求更高, 因此按照数量以及消息体积分批次进行。2. 一次拉取到的消息过多,客户端处理会占用大量资源,可能会有卡顿等,体验较差。


服务端直发消息与通知拉取切换逻辑

主要涉及到的是状态机的更新。下面示意图集成直发消息与通知拉取过程针对状态机的更新:

8.jpg

至此,消息收发核心流程介绍完毕,只剩下多端在线的处理。


多端在线同步

多端按照上下行,同样区分为发送方多端同步以及接收方多端同步。

发送方多端同步

在前面客户端连接 IM 服务过程中,我们已经将同一个用户的客户端汇聚在了同一台服务,那么维护一个 userId 的多端就会变得很简单。

1.用户多个终端链接成功后,发送一条消息,这个消息到达 CMP(IM 接入服务) 后,CMP 做基础检查,然后获此用户的其他终端连接。

2.服务把客户端上行的消息,封装为服务端下行消息,直接投递给用户的其他客户端。这样完成了发送方的多端抄送,然后将这条消息投递到 IM 服务。进入正常发送投递流程。发送方的多端同步没有经过 IM Server,这么做的好处是:1.比较快速;2.经过越少的服务节点,出问题的几率越小。

接收方多端同步

1.IM 服务收到消息后,先判断接收方的投递范围,这个范围指的是接收方用户的哪些的终端要接收消息。

2.IM 服务将范围以及当前消息,发送到 CMP,CMP 依据范围,匹配接收方的终端,然后投递消息。

区分接收方多端范围应用场景: 消息一般是所有终端。

有一些特殊业务,比如我在 A 客户端上,控制另外某个端的状态,可能需要一些命令消息, 这时候需要这个作用范围,针对性的投递消息。

9.jpg到此,我们分析完了有关 IM 消息核心处理流程,通过层层拆解逻辑,提供可靠的消息投递机制。

融云会话页面刷新不及时问题

IM即时通讯徐凤年 发表了文章 • 0 个评论 • 227 次浏览 • 2021-01-11 15:14 • 来自相关话题

项目用的融云 IMKit SDK,调试中发现收到消息的时候,不刷新,上拉一下才会显示。排查方法是直接使用 SDK 的会话页面,排除是子类代码的问题,替换后发现还是有此问题。后来和技术人员沟通发现是使用了 RCIMClient 中的初始化接口,这样会影响 UI ... ...查看全部

项目用的融云 IMKit SDK,调试中发现收到消息的时候,不刷新,上拉一下才会显示。排查方法是直接使用 SDK 的会话页面,排除是子类代码的问题,替换后发现还是有此问题。后来和技术人员沟通发现是使用了 RCIMClient 中的初始化接口,这样会影响 UI 刷新的。替换为 RCIM 的初始化方法,问题解决!希望此文字可以帮助到后续开发者!

/*!
 初始化融云SDK

 @param appKey  从融云开发者平台创建应用后获取到的App Key

 @discussion 您在使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化SDK。
 在App整个生命周期中,您只需要执行一次初始化。

 @warning 如果您使用IMKit,请使用此方法初始化SDK;
 如果您使用IMLib,请使用RCIMClient中的同名方法初始化,而不要使用此方法。
 */
- (void)initWithAppKey:(NSString *)appKey;

友情提示融云官网:(www.rongcloud.cn)

融云 Flutter IM SDK 解析

IM即时通讯木土走召 发表了文章 • 0 个评论 • 226 次浏览 • 2021-01-11 15:14 • 来自相关话题

最近准备使用融云的 Flutter SDK,所以顺便记录一下。融云 Flutter IM SDK 地址:传送门融云的 Flutter SDK 是基于 融云 IMLib 层做的封装,封装了 IMLib 的部分接口提供给 Flutter 开发者使用。此文章只介绍了... ...查看全部

最近准备使用融云的 Flutter SDK,所以顺便记录一下。

融云 Flutter IM SDK 地址:传送门

融云的 Flutter SDK 是基于 融云 IMLib 层做的封装,封装了 IMLib 的部分接口提供给 Flutter 开发者使用。此文章只介绍了 Flutter 层做的一些操作。

目录结构

image.png

整体 SDK 的结构规规矩矩,核心内容参考红色箭头即可。

SDK 层包含 三个目录:
android:此目录包含了和原生 SDK 交互的所有 Java 文件
ios:此目录包含了和原生 SDK 交互的所有 oc 文件
lib: 此目录为使用 dart 编写的 Flutter SDK 文件

其他目录:
doc:主要是融云开发者提供的一些文档相关
example:是融云开发者基于此 SDK 提供的一个简单示例,整体较为简陋,且有细微 bug,仅供参考

FunctionList.md 是融云开发者提供的一个功能清单,
大体如下:

# RongCloud IM Flutter SDK 功能清单

## 连接

初始化

连接

断开连接

连接状态兼容

## 配置

设置服务器地址( im 服务;文件服务)

## 会话

获取会话列表,支持全量获取,分页获取

获取单个会话

删除指定会话



## 消息

当前仅支持 文本消息,语音消息,图片消息,小视频消息

收发消息(可以携带 pushContent)

自定义消息

获取批量本地历史消息

获取单条本地历史消息

获取批量远端历史消息

插入消息

删除批量本地消息

获取未读数

清除指定会话未读数

## 免打扰

设置会话免打扰

获取会话免打扰

## 会话置顶

设置会话置顶

备注:获取会话是可以获取到会话置顶状态

## 黑名单

加入黑名单

移除黑名单

获取黑名单列表

检查特定用户的黑名单状态

## 聊天室

加入聊天室

退出聊天室

获取聊天室信息

都是一些接口层的操作。

剩下的文件基本可以忽略。

解析

我们开始从 lib 目录开始分析

image.png

这两个文件是核心文件,我们所有的调用接口都在这里。

rong_im_client.dart 是最新版本的接口类,我们只关心这个即可。

rong_im_plugin.dart 是旧版本的接口类,已经废弃。

common_define.dart 是定义了 SDK 内使用的所有枚举和状态码。

method_key.dart是定义了 Flutter SDK 和原生层进行交互时标识的唯一的常量字符串。

然后就是剩下的三个文件目录:
image.png

info: 其实就是对象 model 类

image.png

message: 这个是 Flutter SDK提供的所有内置的消息类型,包括聊天室KV消息、合并消息、文件消息、GIF消息、图片消息、位置消息、撤回消息、引用消息、图文消息、视频消息、文本消息、语音消息。

其中有一个比较特殊的 dart 类就是 message_content.dart, 这个类是所有消息的基类。

每个消息都需要继承此类,并复写里面的方法进行编解码。

image.png

util: 这个目录就是一个工具目录。

message_factory.dart 主要是进行消息封装,字典转模型,模型转字典,根本原因我猜就是 Flutter 和 原生仅有的交互类型限制。

type_util.dart:略

以上就是 SDK 在 Flutter 层做的所有的操作,内容整体不多,而且所有代码都是开源的,看看基本上都了解。

与原生层的交互

image.png

整体都是通过 invokeMethod 与原生进行通信的,后面的key 就是之前说的常量字符串,用来保证唯一性。

而在 iOS 和 Android 都提供了对应的定义。

image.png

image.png

并通过触发 iOS 和 Android 层对应的方法来进行处理。

image.png

image.png

原生层

Android:
image.png

整体核心的处理都在 RCIMFlutterWrapper.java 这个类处理了 dart 代码传递过来的数据,并与融云 IMLib 的 SDK 进行了处理。

iOS:
image.png

同样,iOS 的核心代码也都在 RCIMFlutterWrapper.m 这个类处理。具体内容大家可以自己看一下。

到此整个内容我们也就大体明白了。

整体看来其实就是 flutter 中 rong_im_client.dart 和 原生的两个 Wrapper 类做交互,其他的都是助攻。

整体看来不难,搞起~

融云文档:传送门


融云单聊推送标题如何设置

回复

WebRTC梅川酷子 回复了问题 • 3 人关注 • 1 个回复 • 321 次浏览 • 2020-07-20 16:54 • 来自相关话题

一把双刃剑 -- 融云即时通讯sdk中的自定义消息使用心得&指南 (下)

IM即时通讯王叫兽 发表了文章 • 0 个评论 • 15 次浏览 • 3 天前 • 来自相关话题

背景:最近公司新上的app要加上即时通讯的功能, 自己快速实现一个当然是不可能的了(项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的不足.最后点兵点将,选了融云家的SDK(老板说了算hhhh).他家的官网和文档地址:... ...查看全部

微信截图_20210224192919.png

背景:

最近公司新上的app要加上即时通讯的功能, 自己快速实现一个当然是不可能的了(项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的不足.最后点兵点将,选了融云家的SDK(老板说了算hhhh).

他家的官网和文档地址: 官网:https://www.rongcloud.cn/ 文档:https://docs.rongcloud.cn/v4

这个任务当然还是落在我的头上. 我是使用的他们家的带UI的sdk,(他们家有带UI和不带UI的两种sdk, 不带UI的sdk就是只有即时通讯能力, 所有的UI都需要开发者自定实现, 带UI的sdk封装了一些基本的界面,例如会话列表, 和别人聊天的会话界面).

心得 (下)

自定义小视频消息

接上篇对自定义消息的开发心得哈.

因为融云家自带的小视频消息是需要收费的, 需要在服务端开通小视频服务后, 同时在端上做一下配置, 才可以使用小视频消息. 我一看这还得了, 想方设法收我钱呢不是. 不过他家只是对小视频类型的消息在服务端做了限制, 而不是完全不让在消息中携带视频链接. 自定义消息是随便自定义的, 那么我自定义一个小视频消息不就好啦.

大概实现思路如下:

自定义小视频消息继承MediaMessageContent,其中mLocalPath是小视频文件本地的存放路径,mMediaUrl是小视频文件上传到文件服务器后的http/https地址。

小视频的拍摄,播放我们RongCloud SDK没有接口,开发者自己实现。

当拍摄完成,发送小视频消息时使用方法

sendMediaMessage(final Message message, final String pushContent, final String pushData, final IRongCallback.ISendMediaMessageCallback callback)或者

sendMediaMessage(final Message message, final String pushContent, final String pushData, final IRongCallback.ISendMediaMessageCallbackWithUploader callback)

这两个方法的不同是后者开发者负责小视频文件的上传到指定的服务器,前者使用我们RongCloud默认的文件服务器

以上是大致步骤,小视频开发过程中可能遇到的问题,说明如下:

1.关于缩略图的处理,我们SDK没有直接上传一张图片返回一个url地址的接口,开发者可以把缩略图上传到自己的服务器,这样缩略图跟mMediaUrl类似,小视频消息展示显示缩略图时加载一张网络图片即可。

另一种缩略图处理方式类似我们SDK发送图片消息时的缩略图处理,把缩略图做base64编码,放到自定义消息体中直接传输,这种方式涉及到消息发送时把缩略图转化为base64数据和接收到消息时还原为缩略图,在我们SDK内部使用的是MessageHandler。

关于MessageHandler,我们RongCloud的每个消息都有一个MessageHandler,此前我们文档从没有介绍过这个

MessageHandler,对用户透明的,用户的自定义消息没有指定它是因为有个默认的DefaultMessageHandler。

自定义消息时可以指定自己的MessageHandler,例如图片消息的定义如下

ImageMessage.png

MessageHandler在消息发送和接收时在IPC进程中会被自动调用,它有两个方法,encodeMessage

和decodeMessage,在消息接收后调用decodeMessage时开发者可以把base64对应的数据转化为缩略图url,这样在展示缩略图时直接使用url即可。

/**
 * 解码 {@link MessageContent} 到 {@link Message} 中。
 *
 * @param message 用于存放 MessageContent 的消息实体。
 * @param content 将要被解码的 MessageContent。
 */
public abstract void decodeMessage(Message message, T content);

/**
 * 对 {@link Message} 编码。
 *
 * @param message 将要被编码的 Message 实体。
 */
public abstract void encodeMessage(Message message);

此文档包含了两个附件分别为自定义小视频消息和对应的小视频消息MessageHandler,供开发者参考

2.开发中可能还会遇到小视频文件上传时进度更新的问题,如果开发者自定义的小视频消息不继承自MediaMessageContent而是MessageContent,需要自己在UI上维护上传进度


一把双刃剑 -- 融云即时通讯sdk中的自定义消息使用心得&指南 (上)

IM即时通讯王叫兽 发表了文章 • 0 个评论 • 13 次浏览 • 3 天前 • 来自相关话题

背景:最近公司新上的app要加上即时通讯的功能, 自己快速实现一个当然是不可能的了(项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的不足.最后点兵点将,选了融云家的SDK(老板说了算hhhh).他家的官网和文档地址:... ...查看全部

微信截图_20210224192427.png

背景:

最近公司新上的app要加上即时通讯的功能, 自己快速实现一个当然是不可能的了(项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的不足.最后点兵点将,选了融云家的SDK(老板说了算hhhh).

他家的官网和文档地址: 官网:https://www.rongcloud.cn/ 文档:https://docs.rongcloud.cn/v4

这个任务当然还是落在我的头上. 我是使用的他们家的带UI的sdk,(他们家有带UI和不带UI的两种sdk, 不带UI的sdk就是只有即时通讯能力, 所有的UI都需要开发者自定实现, 带UI的sdk封装了一些基本的界面,例如会话列表, 和别人聊天的会话界面).

需求:

融云的体系中默认的消息类型只有9种.


功能     |     描述


文字消息       |     用来发送文字类消息,其中可以包括表情、超链接(会自动识别),客户端收到消息后计入未读消息数、进行存储。

语音消息     |     发送高质量的短语音消息,录制的语音文件存储到融云服务端,语音文件格式为 AAC,时长上限为 60 秒,客户端收到消息后计入未读消息数、进行存储。

图片消息     |     用来发送图片类消息,客户端收到消息后计入未读消息数、进行存储。图片缩略图格式为 JPG,大小建议不超过 100k。

GIF 图片消息     |     用来发送 GIF 动态图片消息,客户端收到消息后计入未读消息数、进行存储。

图文消息     |     用来发送图文消息,包含一个标题,一段文字内容和一张图片,客户端收到消息后计入未读消息数、进行存储。

文件消息     |     用来发送文件类消息,客户端收到消息后计入未读消息数、进行存储。

位置消息     |     用来发送地理位置消息,客户端收到消息后计入未读消息数、进行存储。

小视频消息     |     用来发送小视频消息,支持录制发送及选择本地视频文件发送两种方式,录制时长不超过 10 秒,本地选择视频文件方式时长不超过 2 分钟,小视频消息小视频文件格式为 .mp4,客户端收到消息后计入未读消息数、进行存储。

合并转发消息     |     IMKit SDK 中支持将多条消息合并为一条消息进行发送,合并后的消息以 HTML 文件的方式存储到融云服务端,客户端收到消息后计入未读消息数、进行存储。

这9种消息其实已经满足大部分的即时聊天场景了, 无论是打字聊天最普通的文本消息, 还是长按录制发送的语音消息, 以及图片消息, 分享位置的消息. 基本上微信有的场景, 都覆盖到了.

但是因为各家的产品各不相同, 有人需要一个比微信功能更简洁的聊天工具, 有人则需要一个像QQ那般功能强大的聊天工具. 总是有千奇百怪不同的需求的. 像我们的app就是这样, 总有场景是这里无法满足的. 好比QQ是可以把图片和文本消息放入同一个消息气泡中的(类似于富文本消息), 那么这样的情况下, 默认的几类消息就不够用了.

不过融云还是把这块做的很到位的, 暴露了类和接口让用户去对消息做自定义, 基本上可以做到, 想把消息定义成什么样就定义成什么样子.

心得(上)

这里就举一些我在开发我们公司app时, 用到的自定义消息, 以及使用心得和指南.

只发给当前在线用户的限时奖励通知

只给当前在线用户发送消息, 我们有一种游戏奖励是只发放给特殊时段在线的用户的, 只有当前在线的用户才能接收到这种消息来领取奖励, 其他在该时段未在线的用户, 不能接收到, 且再次登录后也不能接收到保留的离线消息. 这个需求就是做了一个自定义消息来实现的. 把自定义消息类的 MessageTag 中 flag 值设置为 MessageTag.STATUS。此消息类型即为状态消息,状态消息不存储不计数,并且当接收方不在线时,此消息会直接丢弃,用户再上线也不会收到该消息。

有需要的同学可以看他们家关于自定义消息的文档:https://docs.rongcloud.cn/im/imkit/android/conversation/custom_message/

发送自定义消息后撤回消息,撤回消息会失败

这里积累了一个经验, 也算是帮大家踩踩他们家的坑了, 那就是: 使用以下废弃方法发送自定义时会出现此错误:

在发送自定义消息后,撤回消息时没有反应,退出会话界面再次进入后可以正常撤回消息。 在 log 中显示 recallMessage errorCode = 25101。

public Message sendMessage(ConversationType type, String targetId, MessageContent content, String pushContent, String pushData, final SendMessageCallback callback) {

必须要换成这个方法发送才行:

public void sendMessage(Message message, String pushContent, String pushData, final ISendMessageCallback callback)

这个问题也是蛮坑的, 害. 找他们家技术支持费了点劲才排查出来, 希望大家遇到这种问题能快快找到我这篇经验哈.


融云4.x 版本升级到5.0 版本出现的问题

IM即时通讯柠檬^ 发表了文章 • 0 个评论 • 15 次浏览 • 3 天前 • 来自相关话题

1. 4.x 版本与5.x 版本的区别  主要是针对 IMKit(带 UI 界面)进行了重构,并且 5.0 版本以上的 IMKit 进行了开源,可以在 &nbs... ...查看全部

微信截图_20210224192708.png1. 4.x 版本与5.x 版本的区别

  主要是针对 IMKit(带 UI 界面)进行了重构,并且 5.0 版本以上的 IMKit 进行了开源,可以在  https://github.com/rongcloud/imkit-android 进行下来进行集成;

2. 5.x 版本主要的跳转方式

   在之前4.x 版本的SDK 中,界面之间的跳转主要是使用隐式调用的,在5.x 版本则全部改用为显示跳转,并且引入路由的概念,具体可以参考 RouteUtils 这个工具类。

3. 4.x 以及5.x 主要的api 感知变化

  为了方便平滑升级,以及兼容性,所以对外引用 api 并无太大改变,都是通过 RongIM 进行引用。

4. 5.x 自定义消息的变化

主要是针对展示方式变化,取消之前的注解方式,改为复写 MessageItemProviderConfig 的方式,通过代码动态加载来进行展示,设置方式是在自定义的provider 中进行设置config 即可;


融云 IMKit SDK 5.X 升级说明

IM即时通讯fanta2 发表了文章 • 0 个评论 • 23 次浏览 • 5 天前 • 来自相关话题

Tips如果您应用依赖于 suport 包,可参考 AndroidX 迁移文档将依赖转换为 AndroidX 后,再集成 IMKit SDK 5.X版本。1. 类路径调整IMKit SDK 5.X 版本重构了 SDK 的架构,通过 MVVM 框架实现... ...查看全部

Tips

如果您应用依赖于 suport 包,可参考 AndroidX 迁移文档将依赖转换为 AndroidX 后,再集成 IMKit SDK 5.X版本。

微信截图_20210222180400.png

1. 类路径调整

IMKit SDK 5.X 版本重构了 SDK 的架构,通过 MVVM 框架实现,导致很多类路径发生了更改,下表列出了 5.X 之前版本对外公开类的路径变更:

2.x 、4.x 版本路径
io.rong.imkit.fragment.ConversationListFragment
io.rong.imkit.fragment.ConversationFragment
io.rong.imkit.RongExtension
io.rong.imkit.userInfoCache.RongUserInfoManager
io.rong.imkit.mention.RongMentionManager
io.rong.imkit.manager.IUnReadMessageObserver

5.x 版本路径
io.rong.imkit.conversationlist.ConversationListFragment
io.rong.imkit.conversation.ConversationFragment
io.rong.imkit.conversation.extension
io.rong.imkit.userinfo.RongUserInfoManager
io.rong.imkit.feature.mention.RongMentionManager
io.rong.imkit.manager.UnReadMessageManager.IUnReadM

路径调整 Tips

参照上表,在 AndroidStudio 中 command+shift+R 全局搜索旧的类路径,替换为新路径。 如果深度定制化了 IMKit SDK,部分类路径的调整可能不在上述列表中,升级以后 AndroidStudio 会有红色报错。删除报错类里红色未识别的导入路径,鼠标停留到报错的地方,根据 AndroidStudio 的提示导入新路径即可。如果有多个地方使用了该路径,可以参考第一步里的方法,全局搜索并替换。

2. 集成方式变更

页面跳转时由原先的隐式调用方式更改为显示调用, 因此集成步骤有所简化和更改。您需要先移除旧版本 AndroidManifest.xml 文件中关于 IMKit SDK 的配置,参考官网文档重新集成。

3. 消息展示模板变更

列表页由 ListView 更改为效率更高的 RecycleView,因此自定义消息的展示模板需要对应调整。

将自定义消息的展示模板更改为继承 BaseMessageItemProvider<>, 并实现基类方法。 移除展示模板里原先的注解,原注解属性可在新模板构建类里通过调用基类成员 mConfig 的各个方法进行配置

4. 内部实现变更

资源名称变更。IMKit SDK 5.x 版本重新统一了资源名称的命名,如果您自定义了部分资源文件,可参考官网自定义文档,重新替换对应名称的资源。

移除了 EventBus 。IMKit 5.x 版本不再依赖于 EventBus 进行事件分发,更改为通过观察者模式实现。如果您应用里使用了旧版本 SDK 里的 EventBus, 升级后需要您从应用层自己引入依赖。

移除 RongContext 类。如果您应用里有调用 RongContext 作为上下文使用的地方,请更改为调用您自己的应用上下文。

由于更改为 MVVM 框架,原 fragment 里很多业务相关接口被移除,您可参考官网 5.x 版本文档重新进行页面自定义。



融云 FCM 推送与打包方式有关

IM即时通讯fanta2 发表了文章 • 0 个评论 • 34 次浏览 • 5 天前 • 来自相关话题

1.一切都配置完成之后, 开始测试. 第一次启动App, 杀死. 发送测试消息. 收不到推送.2.再次启动App, 杀死, 发送测试消息. 这次能收到推送了.第一次杀死App之后, 发送测试消息, 可以看到log中会即时打出:09-17 11:50:... ...查看全部

1.一切都配置完成之后, 开始测试. 第一次启动App, 杀死. 发送测试消息. 收不到推送.
2.再次启动App, 杀死, 发送测试消息. 这次能收到推送了.

第一次杀死App之后, 发送测试消息, 可以看到log中会即时打出:

09-17 11:50:34.298 W/GCM ( 2025): broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE pkg=com.rongcloud.fcm_demo (has extras) }

GCM打出的log, result=CANCELLED. 广播的intent发送回调是: cancelled. 也就是这个广播还没发送到app层/sdk层, 就已经被系统拦截到了. 失败了.

最开始以为是App关于GCM, 或者FCM的权限问题. 在manifest里遗漏了某个配置, 或者App的通知权限没有打开. 但是做了一番检查以及配置之后, 这个问题还是存在.
之后求助于Google和StackOverflow, 发现有些人是遇到过类似问题的, 但是都没有一个很好的解决方案, 把网上的解决方法一一尝试之后, 这个顽固的问题还是存在.

后来也是一个偶然的发现, 如果我在IDE中直接点击“Run”把App安装运行到手机上, 会出现这个问题, 但是我把项目打包成apk后, 再安装到手机上. 这个问题就消失了, 第一次杀死App之后, 也是可以顺利收到消息的. 这样才把这个问题给解决掉.


美国、日本、俄罗斯版“微信”大PK,即时通讯软件如何流量变现?

IM即时通讯赵炳东 发表了文章 • 0 个评论 • 116 次浏览 • 2021-02-03 17:12 • 来自相关话题

即时通讯软件可以说是互联网时代的基础设施了,从全球范围看,虽然各类即时通讯软件如雨后春笋般出现,但是真正能留在消费者手机中的却凤毛麟角,本文将主要对比美国版微信Whatsapp、日本版微信Line以及俄罗斯版微信Telegram的主要盈利模式。壹美国微信Wha... ...查看全部

即时通讯软件可以说是互联网时代的基础设施了,从全球范围看,虽然各类即时通讯软件如雨后春笋般出现,但是真正能留在消费者手机中的却凤毛麟角,本文将主要对比美国版微信Whatsapp、日本版微信Line以及俄罗斯版微信Telegram的主要盈利模式。

壹美国微信Whatsapp:拒绝广告,赚B端的钱2009年,Jan Koum和Brian Acton开发了一款用于“状态更新的APP”,并将之命名为“Whatsapp”。当这个软件升级到2.0的时候,也就真正开始了其作为即时通讯软件的生涯。
作为一个拥有16亿月活(MAU)用户的超级APP,网络效应早已经形成,但是如何赚钱成了问题——因为其开发者鲜明地表达了拒绝通过广告赚钱的逻辑。

1.jpg

按照Whatsapp开发者的观点,他们希望能为用户创造一个即时通讯平台,而不是为企业创造一个放广告的平台。于是,起先的逻辑是收取每个用户每年1美元的订阅费。
这时候就不得不提及Whatsapp的融资历程了:它的第一轮融资来自5位前雅虎的朋友,总额为25万美元;而它的第二轮和第三轮投资者就值得一说了,那就是大名鼎鼎的红杉资本(Sequoia Capital),总额6000万美元(2011年800万美元,2013年5200万美元)。
这些融资基本就负担了Whatsapp公司的所有开销,考虑到运营这个项目的成本并不是很高——事实上,主要的开销是向用户发送验证码,所以Whatsapp取消了向C端收取1美元/年订阅费的做法。
之后,当Whatsapp再次进入视野的时候,就是Facebook的扎克伯格收购Whatsapp了:在追逐Whatsapp长达2年之后,2014年2月,Facebook以190亿美元收购Whatsapp,而创始人Jan Koum也得以加入Facebook董事会。
收购之后,Whatsapp的价值就显现了:Facebook不仅将之视为一个用户数据的“留量池”,更将之纳入自己的生态体系。
Facebook推出了Whatsapp Business Application,也就是商业版Whatsapp,这样企业就可以在上面建立自己的官方档案,并得到系统认证。在档案中,这些企业可以将自己的网站链接、Facebook主页链接挂上去,甚至可以将他们的座机号连在Whatsapp中。

目前,商业版Whatsapp对于企业来说依然免费,Whatsapp是通过商业API赚钱。 Whatsapp商业API可以把Whatsapp和企业的系统进行整合,通过通知让企业和消费者接触。为了避免垃圾信息,Whatsapp限制了企业发送消息的能力,只有消费者首先联系了公司以后,公司才可以联系消费者(这点和微信的公众平台非常相似),不过API也可以帮助企业向消费者发送送货确认、活动门票等,目前Whatsapp的商业API已经和Booking.com等客户进行了深度合作。

至于Whatsapp如何通过API赚钱,那就很有趣了,Whatsapp向回复缓慢的企业收取费用。
正常情况下,当消费者联系企业后,企业可以在24小时内回复,这是免费的;但是时间一旦超过24小时,此时API就会收费,其费用是固定的,根据国家有所不同。
听起来似乎是一个特别蠢的收费逻辑,但是对于那种百万级用户的企业来说,这就卡住了咽喉:一个订票网站怎么可能同时处理百万级用户的咨询呢?所以这个需求是确实存在的。

此外,在印度,Whatsapp还有支付功能,这可能帮助Whatsapp成为当地用户首选的“寄钱APP”——就像Venm一样,这也可以成为未来的盈利点。
在F8大会上,扎克伯格也提到了这一点,未来他将把Whatsapp的支付功能拓展到更多国家,这对于希望从Whatsapp的网络效应中赚钱的商家,有极大吸引力。
至于盈利数据,Whatsapp目前没有公开过财报,来自福布斯(Forbes)的估算显示,其年收入约50亿美元,ARPU在2020年可以达到4美元。

贰日本微信Line:广告为生,内容为辅在亚洲,Line主要流行于日本、泰国、印尼和中国台湾地区,该公司成立于2000年9月,于2016年7月同时在日本、美国的纽约证交所上市,其主要股东是韩国搜索引擎巨头Naver。
从Line的财报看,2019年4季度(财年截止于2019年12月31日)它的营业收入达到608亿日元,同比增长8.6%,按照地区划分,71%的收入来自日本,29%来自海外。
同期,其在日本的MAU同比增加5.1%,季度MAU达到1.64亿,同时DAU/MAU也达到了79%,也证明了Line的用户活跃度。
从收入角度看,Line共有3个核心收入源,按营收占比,第一是广告(55.4%),第二是交流/内容/其他(29.8%),第三是战略业务(14.8%)。
在广告方面,Line主要是展示广告(Display Ads)和账号广告(Account Ads),二者占总广告收入的93.2%,而展示广告收入同比增长达到65.4%。考虑到Line为各类商家提供大量广告服务,这个成为核心收入源也就十分正常了。

Line的第二大收入源是交流/内容/其他,这部分收入比较稳定,占比超过一半的是内容部分,分别是音乐业务Line Music和漫画业务Line Manga,目前音乐业务同比增长超过40%,漫画业务也有20.1%。
继续往下挖一层,值得一提的是两点,第一点是Line的内容业务,这一部分可以简要称之为“贴纸、壁纸”。用户可以在“主题商店”和“贴图商店”中充值“Line积分”购买壁纸和表情包。

这部分可以和微信进行对比:在微信上,艺术家可以制作表情上架微信,用户对表情的打赏将直接进入艺术家账户。

第二点是“其他”,根据其财报显示,这部分主要是研究业务“Line Research”,财报写道:“有超过500万用户注册成为问卷答卷人,此项业务依然在稳健增长”,为企业提供用户调查,这也属于是对用户的货币化方法之一了。
最后是Line的第三大收入源,Line在财报中将之称为“战略业务(Strategic)”,2019Q4总收入为90亿日元,其中51亿日元收入来自IP业务“LINE FRIEND”,这里主要销售IP赋能的玩具、文具、日用品等;另外的39亿日元来自O2O/电商、Fintech和AI业务。

不过,这里更值得注意的是Line打造的支付业务“Line Pay”,2019Q4,其全球GMV达到3550亿日元,全球MAU达到650万,相比2019Q3分别增长680亿日元和100万。

整体而言,Line的收入源还是比较多的,在广告收入之外,主要是内容(漫画、音乐、表情)、IP变现以及支付业务。对于Line来说,广告和支付业务成为重要收入源并不难以想象,而内容业务的收入更多是和日本等地用户对于漫画、音乐、IP等的认可,以及二次元环境密不可分的。

叁,俄罗斯微信Telegram:绝对免费、绝对安全,发币赚钱对于不少国内用户来说,Telegram的火爆得益于曾经的“发币狂潮”——大量用户为了获得糖果空投(Airdrop)而注册Telegram,加入“电报群”。
相比于其他即时通讯软件,Telegram主打两点,第一是永远免费,第二是绝对加密。
事实上,在成立之初,Telegram就主打“隐私(Privacy)”,其创始人Pavel Durov在2013年创建Telegram,并在短时间内实现爆炸性用户增长,他曾说,在推出Telgram的15个月后,用户在Telegram上就发送了10亿条信息,而VKontakte(这是Durov之前的创业项目)花了6年半才做到的里程碑。
他同时写道,“Telegram的5000万用户均匀地分布在各个大陆,最活跃的用户来自西班牙、巴西、韩国、墨西哥、德国、马来西亚、新加坡、印度、沙特、意大利和美国,而俄罗斯的比例是1%。”
至于所谓的安全性,其实不必看Telegram的官方介绍,只需要看新闻就可以了:
据Trend Micro发布的一份关于恐怖分子通讯方式的研究报告显示,34%的恐怖分子使用Telegram进行沟通,该研究也证实了此前有关极端组织“伊斯兰国(ISIS)”使用Telegram进行秘密信息交换。
和Whatsapp类似,Telegram也不通过广告赚钱,同时还保持了开源的特性,截止到2019年,Telegram没有盈利,或者说没有创造过收入,其创始人Durov在一篇博客上写道,如果资金不足,他可能会引入“非必要的付款选项(non-essential paid options)”来给程序员发工资。
传统的收入来源都没有,Telegram却有“新的收入来源”,那就是“发币”。
2018年1月到3月,Telegram进行了代币首次发行。其白皮书显示,Telegram的加密代币被命名为“Gram”,总发行量为50亿,其中52%用于开发、44%用于代币首次发行,以及余下4%给予团队。
Telegram的区块链网络名为“TON”,该区块链项目将分为四个分支:TON服务、TON DNS、TON支付和TON区块链。
最后,这场宏大的代币首次发行募集了约17亿美元(全世界的投资者购买了约29亿个Gram代币),而来自今年1月初的报道显示,美国证券交易委员会(SEC)提交了一份法院指令,要求Telegram解释代币首次发行所产生的资金是如何使用的。不过迄今为止,Telegram一直拒绝公开账目,并且表示Gram不是有价证券(Security)。
Ton网络原定于2019年10月上线,但美国证券交易委员会将 Telegram 的上线日期推迟到了2020年4月。所以目前没人说的清Telegram到底是用这笔钱干了什么,只能关注今年4月份会不会有新的消息,并希望这一场代币首次发行不是一场闹剧。

总结整体来说,可以发现,即时通讯软件们虽然最终盈利模式并不相同,但是发展模式非常接近,可以抽象为:
1.0时代,免费的时代,主打用户之间的连接、交流,这个时代以两个“结论”作为最终答卷,APP本身看,就是DAU、MAU和用户数,而从外部看就是在市场内的占有率;
2.0时代,赚钱的时代,一般来说,APP在此时已经在一个地区成为至少是Top2的巨头,沉淀了海量用户,此时B端企业就会盯上这个APP,开始做营销、服务,而APP就可以“顺坡下驴”为这些B端企业开发功能模块,进行服务抽成——例如GMV抽成,基本来说在这个领域,中国的微信早已走在了前面。

(来源于公众号-零售威观察)

IM 消息数据存储结构设计

IM即时通讯admin 发表了文章 • 0 个评论 • 128 次浏览 • 2021-01-28 14:25 • 来自相关话题

1背景在移动互联网高速发展的时代,生活中 IM 类产品已经是我们离不开的应用了,像微信、钉钉等都是以 IM 为核心功能的社交产品。另外也有一些应用不是以 IM 为核心,但是也是其重要功能,比如在线游戏、电商直播等应用。在 IM 庞大的体系中,消息系统无疑是最核... ...查看全部

1背景

在移动互联网高速发展的时代,生活中 IM 类产品已经是我们离不开的应用了,像微信、钉钉等都是以 IM 为核心功能的社交产品。另外也有一些应用不是以 IM 为核心,但是也是其重要功能,比如在线游戏、电商直播等应用。

IM 庞大的体系中,消息系统无疑是最核心的,而消息系统中,最关键的部分是消息的分发和存储。

在以往传统消息系统中,对于在线的用户,消息会直接实时发送到在线的接收方,消息发送完成后,服务器端并不会对消息进行落地存储。对于离线的用户,服务器端会将消息存入到离线库,当用户登录后,从离线库中将离线消息拉走,然后服务器端将离线消息删除,这样的缺点是消息不持久化,导致消息无法支持消息漫游,降低了消息的可靠性。而在我们的消息系统中,服务器只要接收到了发送方发上来的消息,在转发给接收方的同时也会在离线数据库以及历史消息库中进行消息的落地存储,消息的落地也就支持了整体的消息漫游等相关功能。

 

2离线消息和历史消息的区别

离线消息,就是用户在离线过程中收到的消息,这些消息大多是用户比较关心的消息,具有一定的时效性。我们的系统设计,离线消息默认只保存最近七天的消息。离线消息在用户登录后会全量的获取,然后客户端根据会话进行整体离线消息的展示。

历史消息,存储了用户所有的消息,包括发的消息以及接收的消息。在客户端获取历史消息时,是按照会话进行分页获取的。历史消息的存储时间我们系统设计默认为半年,当然这个是可配置的。

3消息的发送以及存储的流程

融云整体的消息发送以及存储的流程如下图所示:

1.png

用户发送消息到服务器端后,首先会进入到消息系统中,消息系统会对消息进行分发以及存储。对于在线的接收方,会选择直接推送消息,但是遇到接收方不在线或者是消息推送失败的情况下,也会有另外的消息获取方式,接收方会主动向服务器拉取未收到的消息,但是接收方何时来服务器拉取消息以及从哪里拉取是未知的,所以消息存入到离线库的意义也就在这里。

   消息系统存储离线的过程中,为了不影响整个系统的更为平稳,融云使用了消息队列,消息是异步存入到离线库中的。

   在分发完消息后,消息服务会同步一份消息数据到历史消息服务中,历史消息服务会对消息进行落地存储。对于新的同步设备,会有消息漫游的需求,这也是历史消息的主要作用。在历史消息库中,客户端可以拉取任意会话的全量历史消息。

4 离线消息以及历史消息存储区别

   上述的图中我们能清晰的看到,离线消息我们存储介质选用的是 Redis,历史消息我们选用的是 HBase。为何选用不同的存储介质针对的是不同的业务场景和读写模式。下面我们重点介绍一下离线消息和历史消息存储的区别。

离线消息的存储模式是放大写,如下图所示,每个用户都有自己单独的收件箱和发件箱,收件箱存放需要向这个接收端同步的所有消息,发件箱里存的是发送端发送的所有消息。二人会话中的消息会产生两次写,发送者的发件箱以及接收端的收件箱。而在群的场景下,写入会被更加的放大,如果群里有 N 个人,那一条群消息就会被放大写 N 次。

放大写的优点是,接收端的逻辑会非常清晰简单,只需要从收件箱里读取一次即可,大大降低了同步消息所需的读的压力,但是缺点就是写入会被放大,特别是针对群这种场景。

2.png

历史消息的存储模式是放大读,因为历史消息中,每个会话都保存了整个会话的全量消息。在放大读这种模式下,每个会话的消息只保存一次。相比放大写的那种模式,写入次数大大降低,特别是针对群消息,只需要存一次即可。但是缺点是接收端接收消息非常的复杂和低效,因为这种模式客户端想拉取到所有消息就只能每个会话同步一次,读就会被放大,而且可能会产生很多次无效的读,因为有些会话可能根本没有新消息。

3.png

  IM 这种应用场景下,通常会用到写扩散这种消息同步模型,一条消息产生一条,但是可能会被读多次,是典型的读多写少的场景。一个优化好的系统,必须从设计上平衡读写压力,避免读或者写任意一个维度达到天花板。当然写扩展这种模式也有其弊端,比如万人群,会导致一条消息,写入了一万次。综合来讲,我们需要根据自己的业务场景做相应设计选择,我们的系统是根据了离线和历史消息的不同场景选择了写扩散和读扩散的组合模式。

5 客户端拉取消息

    离线消息的获取针对的是自己的整个离线消息,包括所有的会话。离线消息的获取是自上而下的方式,一次获取 200 条。在客户端拉取离线消息的信令中,需要带上当前客户端缓存的消息的最大时间戳,上面的图我们应该知道,离线消息我们存储的是一个线性结构,Server 会根据这个时间戳向下查找离线消息,重装或者新安装 App 时,客户端可以传 0 上来,Server 也会缓存客户端拉取到的最后一条消息的时间戳,然后根据业务场景,客户端类型等因素来决定从哪里开始拉取,如果没有拉取完 Server 会在拉取消息的应答中带相应的标记位,告诉客户端继续拉取,客户端循环拉取,直到所有离线消息拉完。

历史消息的获取针对的是单一会话,在拉取过程中需要带上来对方的 ID(如果是单聊的话就是对方的 UserID,如果是群,则是群组 ID 以及当前会话的最前面消息的时间戳,Server 会定位到这个人的这个会话然后一次获取 20 条,采用的是自下而上的方式,即从最后面往前翻。只要有消息,客户端可以一直向前翻,手动触发获取会话的历史消息。

 

6总结

   本篇文章主要讲了 IM 中消息系统的消息分发、存储等,重点介绍了离线消息和历史消息的区别以及两者存储中所选用的不同存储方式以及其优缺点。关于文中内容,也欢迎大家随时留言与我讨论。


技术实践丨IM 消息同步机制全面解析

IM即时通讯柠檬^ 发表了文章 • 0 个评论 • 104 次浏览 • 2021-01-21 11:09 • 来自相关话题

综述即时通讯系统最基础、最重要的是消息的及时性与准确性,及时体现在延迟,准确则具体表现为不丢、不重、不乱序。综合考虑业务场景、系统复杂度、网络流量、终端能耗等,融云精心设计了消息收发机制,并不断打磨优化,形成了现在的消息同步机制。整体思路:1.客户端、服务端共... ...查看全部
综述


即时通讯系统最基础、最重要的是消息的及时性与准确性,及时体现在延迟,准确则具体表现为不丢、不重、不乱序。

综合考虑业务场景、系统复杂度、网络流量、终端能耗等,融云精心设计了消息收发机制,并不断打磨优化,形成了现在的消息同步机制。

整体思路:
1.客户端、服务端共同配合,互相补充。
2.采用多重机制,从不同层面保障。
3.拆分上下行,分别处理。

协议层

首先,从协议层保证,协议栈需要提供可靠、有序的双向字节流传输,融云自研通信协议 RMTP(RongCloud Message Transfer Protocol)。

1.jpg

协议交互示意图


协议层通过 qos、 ack 等机制,保证数据传输的可靠性。

业务层

在关键业务,采用 ack 确认机制,配合状态机,服务感知当前业务传输状态,保障业务按照预期执行。

2.jpg

业务层确认机制示意图


消息 ID

采用全局唯一的消息 ID 生成策略。保证消息可通过 ID 进行识别,排重。

3.jpg

如何实现分布式场景下唯一 ID 生成,请点击融云过往技术文章了解。


客户端服务端交互

客户端与服务端之间使用长连接,基于 RMTP 协议传输数据。
经过总结,主要用三种行为:

1.客户端主动拉取消息,主动拉取有两个触发方式:
①与 IM 服务新建立连接成功,用于获取不在线的这段时间未收到的消息。(此处叫做获取离线消息)
②定时器触发。在客户端最后收到消息后启动定时器,比如 3-5 分钟执行一次, 主要有两个目的,一个是用于防止因网络,中间设备等不确定因素引起的通知送达失败,服务端客户端状态不一致,一个是可通过本次请求,对业务层做状态机保活。

2.服务端主动-发送消息(直发消息) 在线消息发送机制之一,简单理解为服务端将消息内容直接发送给客户端,适用于消息频率较低,并且持续交互,比如二人或者群内的正常交流讨论。

3、服务端主动-发送通知(通知拉取) 在线消息发送机制之一,简单理解为服务端给客户端发送一个通知,通知包含时间戳等可作为排序索引的内容,客户端收到通知后,依据自身数据,对比通知内时间戳,发起拉取消息的流程。适用于较多消息传递。比如某人有很多大规模的群,每个群内都有很多成员正在激烈讨论。通过通知拉取机制,可以有效的减少客户端服务端网络交互次数,并且对多条消息进行打包,提升有效数据载荷。既能保证时效,又能保证性能。

4.jpg

客户端服务端交互示意图


业务拆分

在有了多层机制保证后,将业务进行拆分,首先将业务拆分出上下行,在上行过程保证发送消息顺序,为了保证消息有序, 最好的方式是按照 userId 区分,然后使用时间戳排序。那么分布式部署情况下,将用户归属到固定的业务服务器上,会使得上行排序变得更容易。同时归属到同一个服务器,在多端维护时也更容易。

客户端连接过程
1.客户端通过 APP server ,获取到连接使用的 token。
2.客户端使用 token 通过导航服务,获取具体连接的 IM 接入服务器(CMP),导航服务通过 userId 计算接入服务器,然后下发,使得某一客户端可以连接在同一台接入服务器(CMP)。

5.jpg

示意图


上行

客户端发出消息后,通过接入服务,按照 userId 投递到指定消息服务器,生成消息 Id, 依据最后一条消息时间,确认更新当前消息的时间戳(如果存在相同时间戳则后延),然后将时间戳,以及消息 Id,通过 Ack 返回给客户端 ; 然后对上行消息使用 userId + 时间戳进行缓存以及持久化存储,后续业务操作均使用此时间戳。(此业务流程我们成为上行流程,上行过程存储的消息为发件箱消息)

下行

消息节点在处理完上行流程后,消息按照目标用户投递到所在消息节点,进入下行流程。下行过程,按照目标 userId 以及本消息在上行过程中生成的时间戳,计算是否需要更新时间戳(正向)。如果需要更新则对时间戳进行加法操作,直到当前用户时间戳不重复。如此处理后,目标用户的存储以及客户端接收到消息后的排重可以做到一致,并且可以做到同一个会话内的时间戳是有序的。从而保证同一个接收用户的消息不会出现乱序。

至此,我们已经完成了发送过程,接收过程的消息顺序保障,那么消息流程还剩下直发与通知拉取的处理流程,以及服务端如何选择是直发还是通知拉取。

直发消息

1、客户端 SDK 依据本地存储的最新消息时间戳判断,用来做排序等逻辑。
2、对同一个用户直发消息1条,其他转通知。通知拉取时候客户端选择本地最新一条消息时间戳作为开始拉取时间。
3、在消息发送过程中,如果上一条消息发送流程未结束,下一条消息则不用直发(s_msg),而是用(s_ntf)

6.jpg

直发逻辑示意图


通知拉取

1.服务端在通知体中携带当前消息时间戳。投递给客户端。
2.客户端收到通知后,比对本地消息时间戳,选择是否发拉取消息信令。
3.服务端收到拉取消息信令后,以信令携带的时间戳为开始,查询出消息列表(200 条或者 5M),并给客户端应答。
4.客户端收到后,给服务端 ack,服务端维护状态。
5.客户端拉取消息时使用的时间戳,是客户端本地最新一条消息的时间戳。

7.jpg

上图中,3-7 步可能需要循环多次,有以下考虑: 1.客户端一次收到的消息过多,应答体积过于庞大,传输过程对网络质量要求更高, 因此按照数量以及消息体积分批次进行。2. 一次拉取到的消息过多,客户端处理会占用大量资源,可能会有卡顿等,体验较差。


服务端直发消息与通知拉取切换逻辑

主要涉及到的是状态机的更新。下面示意图集成直发消息与通知拉取过程针对状态机的更新:

8.jpg

至此,消息收发核心流程介绍完毕,只剩下多端在线的处理。


多端在线同步

多端按照上下行,同样区分为发送方多端同步以及接收方多端同步。

发送方多端同步

在前面客户端连接 IM 服务过程中,我们已经将同一个用户的客户端汇聚在了同一台服务,那么维护一个 userId 的多端就会变得很简单。

1.用户多个终端链接成功后,发送一条消息,这个消息到达 CMP(IM 接入服务) 后,CMP 做基础检查,然后获此用户的其他终端连接。

2.服务把客户端上行的消息,封装为服务端下行消息,直接投递给用户的其他客户端。这样完成了发送方的多端抄送,然后将这条消息投递到 IM 服务。进入正常发送投递流程。发送方的多端同步没有经过 IM Server,这么做的好处是:1.比较快速;2.经过越少的服务节点,出问题的几率越小。

接收方多端同步

1.IM 服务收到消息后,先判断接收方的投递范围,这个范围指的是接收方用户的哪些的终端要接收消息。

2.IM 服务将范围以及当前消息,发送到 CMP,CMP 依据范围,匹配接收方的终端,然后投递消息。

区分接收方多端范围应用场景: 消息一般是所有终端。

有一些特殊业务,比如我在 A 客户端上,控制另外某个端的状态,可能需要一些命令消息, 这时候需要这个作用范围,针对性的投递消息。

9.jpg到此,我们分析完了有关 IM 消息核心处理流程,通过层层拆解逻辑,提供可靠的消息投递机制。

融云会话页面刷新不及时问题

IM即时通讯徐凤年 发表了文章 • 0 个评论 • 227 次浏览 • 2021-01-11 15:14 • 来自相关话题

项目用的融云 IMKit SDK,调试中发现收到消息的时候,不刷新,上拉一下才会显示。排查方法是直接使用 SDK 的会话页面,排除是子类代码的问题,替换后发现还是有此问题。后来和技术人员沟通发现是使用了 RCIMClient 中的初始化接口,这样会影响 UI ... ...查看全部

项目用的融云 IMKit SDK,调试中发现收到消息的时候,不刷新,上拉一下才会显示。排查方法是直接使用 SDK 的会话页面,排除是子类代码的问题,替换后发现还是有此问题。后来和技术人员沟通发现是使用了 RCIMClient 中的初始化接口,这样会影响 UI 刷新的。替换为 RCIM 的初始化方法,问题解决!希望此文字可以帮助到后续开发者!

/*!
 初始化融云SDK

 @param appKey  从融云开发者平台创建应用后获取到的App Key

 @discussion 您在使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化SDK。
 在App整个生命周期中,您只需要执行一次初始化。

 @warning 如果您使用IMKit,请使用此方法初始化SDK;
 如果您使用IMLib,请使用RCIMClient中的同名方法初始化,而不要使用此方法。
 */
- (void)initWithAppKey:(NSString *)appKey;

友情提示融云官网:(www.rongcloud.cn)

融云 Flutter IM SDK 解析

IM即时通讯木土走召 发表了文章 • 0 个评论 • 226 次浏览 • 2021-01-11 15:14 • 来自相关话题

最近准备使用融云的 Flutter SDK,所以顺便记录一下。融云 Flutter IM SDK 地址:传送门融云的 Flutter SDK 是基于 融云 IMLib 层做的封装,封装了 IMLib 的部分接口提供给 Flutter 开发者使用。此文章只介绍了... ...查看全部

最近准备使用融云的 Flutter SDK,所以顺便记录一下。

融云 Flutter IM SDK 地址:传送门

融云的 Flutter SDK 是基于 融云 IMLib 层做的封装,封装了 IMLib 的部分接口提供给 Flutter 开发者使用。此文章只介绍了 Flutter 层做的一些操作。

目录结构

image.png

整体 SDK 的结构规规矩矩,核心内容参考红色箭头即可。

SDK 层包含 三个目录:
android:此目录包含了和原生 SDK 交互的所有 Java 文件
ios:此目录包含了和原生 SDK 交互的所有 oc 文件
lib: 此目录为使用 dart 编写的 Flutter SDK 文件

其他目录:
doc:主要是融云开发者提供的一些文档相关
example:是融云开发者基于此 SDK 提供的一个简单示例,整体较为简陋,且有细微 bug,仅供参考

FunctionList.md 是融云开发者提供的一个功能清单,
大体如下:

# RongCloud IM Flutter SDK 功能清单

## 连接

初始化

连接

断开连接

连接状态兼容

## 配置

设置服务器地址( im 服务;文件服务)

## 会话

获取会话列表,支持全量获取,分页获取

获取单个会话

删除指定会话



## 消息

当前仅支持 文本消息,语音消息,图片消息,小视频消息

收发消息(可以携带 pushContent)

自定义消息

获取批量本地历史消息

获取单条本地历史消息

获取批量远端历史消息

插入消息

删除批量本地消息

获取未读数

清除指定会话未读数

## 免打扰

设置会话免打扰

获取会话免打扰

## 会话置顶

设置会话置顶

备注:获取会话是可以获取到会话置顶状态

## 黑名单

加入黑名单

移除黑名单

获取黑名单列表

检查特定用户的黑名单状态

## 聊天室

加入聊天室

退出聊天室

获取聊天室信息

都是一些接口层的操作。

剩下的文件基本可以忽略。

解析

我们开始从 lib 目录开始分析

image.png

这两个文件是核心文件,我们所有的调用接口都在这里。

rong_im_client.dart 是最新版本的接口类,我们只关心这个即可。

rong_im_plugin.dart 是旧版本的接口类,已经废弃。

common_define.dart 是定义了 SDK 内使用的所有枚举和状态码。

method_key.dart是定义了 Flutter SDK 和原生层进行交互时标识的唯一的常量字符串。

然后就是剩下的三个文件目录:
image.png

info: 其实就是对象 model 类

image.png

message: 这个是 Flutter SDK提供的所有内置的消息类型,包括聊天室KV消息、合并消息、文件消息、GIF消息、图片消息、位置消息、撤回消息、引用消息、图文消息、视频消息、文本消息、语音消息。

其中有一个比较特殊的 dart 类就是 message_content.dart, 这个类是所有消息的基类。

每个消息都需要继承此类,并复写里面的方法进行编解码。

image.png

util: 这个目录就是一个工具目录。

message_factory.dart 主要是进行消息封装,字典转模型,模型转字典,根本原因我猜就是 Flutter 和 原生仅有的交互类型限制。

type_util.dart:略

以上就是 SDK 在 Flutter 层做的所有的操作,内容整体不多,而且所有代码都是开源的,看看基本上都了解。

与原生层的交互

image.png

整体都是通过 invokeMethod 与原生进行通信的,后面的key 就是之前说的常量字符串,用来保证唯一性。

而在 iOS 和 Android 都提供了对应的定义。

image.png

image.png

并通过触发 iOS 和 Android 层对应的方法来进行处理。

image.png

image.png

原生层

Android:
image.png

整体核心的处理都在 RCIMFlutterWrapper.java 这个类处理了 dart 代码传递过来的数据,并与融云 IMLib 的 SDK 进行了处理。

iOS:
image.png

同样,iOS 的核心代码也都在 RCIMFlutterWrapper.m 这个类处理。具体内容大家可以自己看一下。

到此整个内容我们也就大体明白了。

整体看来其实就是 flutter 中 rong_im_client.dart 和 原生的两个 Wrapper 类做交互,其他的都是助攻。

整体看来不难,搞起~

融云文档:传送门