迁移指南
自 2023 年 6 月起,声网针对市场及行业需求,先后推出了 RTM v2(以下简称 v2)系列版本。此系列版本在功能、性能、体验上都有创新性提升:
-
功能覆盖:该版本通过引入
Channel
、Message
、Topic
、Presence
、Storage
和Lock
等功能模块,能覆盖更多业务场景,你可以把更多的精力集中在自己的业务创新上。 -
性能提升:我们在新版本中重构了后台架构,通过优化网络连接进一步提升性能,提供长时间低延迟、高可靠、大并发、易扩展的实时网络接入能力,让你无需为业务质量担忧。
-
体验优化:我们重新设计并简化了 API 接口;优化了包括用户指南、API 参考在内的所有文档,提供了更全面的示例程序,支持开发者低成本学习使用 SDK,快速完成集成,提高开发效率。
本文提供 RTM v1 和 v2 的主要区别及相关示例代码,从而帮助用户顺利地从 v1 迁移到 v2。
开通服务
开通 v2 和 v1 的步骤相同:
- 注册并登录声网控制台
- 创建声网项目
- 进入功能配置,开通 RTM 服务
- 获取开发所需参数,例如 App ID
如果你没有声网账号,点击此处注册账号。关于如何开通服务和如何创建项目,详见开通服务。
集成 SDK
v2 和 v1 的 SDK 包名不同,你需要注意区分。不变的是,二者都支持 CDN 和 Cocoapods 两种集成方式。其中,通过 Cocoapods 集成 SDK 的区别如下:
-
v1 的引用方式:
Rubyplatform :ios, '11.0'
target 'Your App' do
# 将 x.y.z 替换为具体的 SDK 版本号,如 1.5.1
pod 'AgoraRtm_iOS', 'x.y.z'
end -
v2 的引用方式:
Rubyplatform :ios, '11.0'
target 'Your App' do
# 将 x.y.z 替换为具体的 SDK 版本号,如 2.2.0
# 如需获取 2.2.0 之前的版本,请将包名修改为 AgoraRtm_iOS
pod 'AgoraRtm', 'x.y.z'
end
初始化实例
相比于 v1,v2 对初始化参数做了很大的调整,增加了很多新特性,例如端侧加密、云代理等,详见 API 参考。此外,v2 还丰富了接口调用的错误信息,你可以通过 AgoraRtmErrorInfo
数据结构获取错误码、错误原因及 API 操作名称,以便于你能更快地排查故障。结合错误排查文档,你也可以快速找到解决方法。
RTM v2 版本在命名字符集的支持上与 v1 版本存在差异。例如,v2 版本不支持以 "_"
开头或包含 "."
字符的频道名、用户名和 Topic 名等。在从 v1 升级到 v2 或混合使用这两个版本时,需注意字符集差异可能导致的不兼容问题。建议在迁移时统一使用 v2 版本支持的字符集。
-
v1 的示例代码如下:
Objective-Cself.appID = @"your_appid";
_kit = [[AgoraRtmKit alloc] initWithAppId:self.appID delegate:self]; -
v2 的示例代码如下:
Objective-CAgoraRtmClientConfig* rtm_cfg = [[AgoraRtmClientConfig alloc] initWithAppId:@"your_appid" userId:@"your_userid"];
NSError* initError = nil;
AgoraRtmClientKit* rtm = [[AgoraRtmClientKit alloc] initWithConfig:rtm_cfg delegate:handler error:&initError];
登录服务
v2 登录服务的方法和 v1 有区别,如下所示:
-
v1 的示例代码如下:
Objective-Cself.uid = self.UserIDTextField.text;
self.token = @"your_token";
[_kit loginByToken:(self.token) user:(self.uid) completion:^(AgoraRtmLoginErrorCode errorCode) {
if (errorCode != AgoraRtmLoginErrorOk){
self.text = [NSString stringWithFormat:@"Login failed for user %@. Code: %ld",self.uid, (long)errorCode];
NSLog(@"%@", self.text);
}
else {
NSLog(@"%@", self.text);
self.text = [NSString stringWithFormat:@"Login successful for user %@. Code: %ld",self.uid, (long)errorCode];
}
}]; -
v2 的示例代码如下:
Objective-C[rtm loginByToken:@"token" completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"login success!!");
} else {
NSLog(@"login failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
事件通知
相比于 v1,v2 重新设计了系统事件通知方式和 API 接口,对事件通知类型进行了更详细的分类和聚合,对事件通知的负载数据结构进行了优化。
v2 的事件通知类型有 8 种,如下所示:
事件类型 | 描述 |
---|---|
didReceiveMessageEvent | 消息事件通知:接收用户所订阅的 Message Channel 及 Topic 中的所有消息事件通知。 |
didReceivePresenceEvent | 用户出席与自定义状态变更事件通知(简称 Presence 事件通知):接收用户所订阅的 Message Channel 及加入的 Stream Channel 中所有的 Presence 事件通知。 |
didReceiveTopicEvent | Topic 变更事件通知:接收用户所加入的 Stream Channel 中所有 Topic 变更事件通知。 |
didReceiveStorageEvent | 频道属性和用户属性事件通知:接收用户所订阅的 Message Channel 及加入的 Stream Channel 中所有的 Channel Metadata 事件通知,及订阅用户的 User Metadata 事件通知。 |
didReceiveLockEvent | 锁变更事件通知:接收用户所订阅的 Message Channel 及加入的 Stream Channel 中所有的 Lock 事件通知。 |
connectionChangedToState | (已废弃)网络连接状态变更事件通知:接收客户端网络连接状态变更的事件通知。 |
didReceiveLinkStateEvent | 接收客户端网络连接状态变更的事件通知,包含变更前后的连接状态、服务类型、导致变更的操作类型、变更原因、频道列表等信息。 |
tokenPrivilegeWillExpire | 接收客户端 Token 将要过期的事件通知。 |
关于事件通知的更多信息及负载数据结构见事件监听。
以监听频道消息 didReceiveMessageEvent
事件通知为例,示例代码如下:
-
v1:
Objective-C@interface ChannelListener ()<AgoraRtmChannelDelegate>
@end
@implementation ChannelListener
- (void)channel:(AgoraRtmChannel *)channel messageReceived:(AgoraRtmMessage *)message fromMember:(AgoraRtmMember *)member
{
self.text = [NSString stringWithFormat:@"Message received in channel: %@ from user: %@ content: %@",member.channelId, member.userId, message.text];
[self AddMsgToRecord:(self.text)];
}
@end
ChannelListener* handler = [[ChannelListener alloc] init];
channel = [rtm createChannelWithId:self.channelID delegate:handler]; -
v2:
Objective-C@interface RtmListener : NSObject <AgoraRtmClientDelegate>
@end
@implementation RtmListener
-(void) rtmKit:(AgoraRtmClientKit *)rtmKit didReceiveMessageEvent:(AgoraRtmMessageEvent *)event {}
@end
// 方式一:调用 initWithAppId 方法初始化 RTM Client 实例时添加事件监听
AgoraRtmClientConfig* rtm_cfg = [[AgoraRtmClientConfig alloc] initWithAppId:@"your_appid" userId:@"your_userid"];
RtmListener* handler = [[RtmListener alloc] init];
NSError* initError = nil;
AgoraRtmClientKit* rtm = [[AgoraRtmClientKit alloc] initWithConfig:rtm_cfg delegate:handler error:&initError];
// 方式二:在 App 生命周期的任意时间中添加事件监听
[rtm addDelegate:handler];
从上面的示例代码可以看出以下显著区别:
-
v1 的频道消息事件通知绑定在具体的
channel
实例上,用户需要先调用createChannelWithId:delegate
方法创建channel
实例,然后注册messageReceived
回调处理事件,SDK 会在收到消息后通过该回调通知处理程序,并且多个频道要实现绑定多次。而 v2 的消息事件通知绑定在客户端实例上,是全局设置:在创建并初始化AgoraRtmClientKit
实例时注册事件监听实例,只需要绑定一次,就可以监听所有订阅的频道或 Topic。 -
v1 的消息事件通知负载数据结构包含的信息相对较少,而 v2 的消息事件通知负载数据结构包含了更多的信息,可以帮助你更好地实现自己的业务。
频道消息
在 1.x 中,发送频道消息的步骤如下:
-
创建一个频道实例
-
加入频道
-
发送频道消息
这种设计会有个弊端,你无法实现发送消息而不收到消息。因为发送消息和接收消息没有解耦。v2 采用了基于 Pub/Sub 的新设计,将频道消息的发送和接收解耦:你无需加入频道即可向指定频道发送消息,你只需订阅指定频道即可接收该频道中的消息,两种操作互不影响。
-
v1 的示例代码如下:
Objective-C// 创建 RTM 频道
_channel = [_kit createChannelWithId:self.channelID delegate:self];
// 加入 RTM 频道
[_channel joinWithCompletion:^(AgoraRtmJoinChannelErrorCode errorCode) {
if(errorCode == AgoraRtmJoinChannelErrorOk){
self.text = [NSString stringWithFormat:@"Successfully joined channel %@ Code: %ld",self.channelID,(long)errorCode];
NSLog(@"%@", self.text);
} else {
self.text = [NSString stringWithFormat:@"Failed to join channel %@ Code: %ld",self.channelID, (long)errorCode];
NSLog(@"%@", self.text); }
}];
// 发送频道消息
[_channel sendMessage:[[AgoraRtmMessage alloc] initWithText:self.channelMsg] sendMessageOptions:self.options completion:^(AgoraRtmSendChannelMessageErrorCode errorCode) {
if (errorCode == AgoraRtmSendChannelMessageErrorOk)
{
self.text = [NSString stringWithFormat:@"Message sent to channel %@ : %@", self.channelID, self.channelMsg]; }
else
{
self.text = [NSString stringWithFormat:@"Message failed to send to channel %@ : %@ ErrorCode: %ld", self.channelID, self.channelMsg, (long)errorCode]; }
}]; -
v2 的示例代码如下:
Objective-C// 发送频道消息
NSString* message = @"Hello Agora!";
NSString* channel = @"your_channel";
[rtm publish:channel message:message option:nil completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"publish success!!");
} else {
NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
// 订阅频道
AgoraRtmSubscribeOptions* opt = [[AgoraRtmSubscribeOptions alloc] init];
opt.features = AgoraRtmSubscribeChannelFeatureMessage|AgoraRtmSubscribeChannelFeaturePresence;
[rtm subscribeWithChannel:@"you_channel" option:opt completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"subscribe success!!");
} else {
NSLog(@"subscribe failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
点对点消息
v1 版本中的点对点消息 API 用于向指定的用户发送消息,例如,你如果需要向用户 ID 为 Tony
的用户发送消息,你可以按照如下方式实现:
// v1
self.peerMsg = self.PeerMsgTextField.text;
self.peerID = self.PeerIDTextField.text;
[_kit sendMessage:[[AgoraRtmMessage alloc] initWithText:self.peerMsg] toPeer:self.peerID completion:^(AgoraRtmSendPeerMessageErrorCode errorCode) {
if (errorCode == AgoraRtmSendPeerMessageErrorOk)
{
self.text = [NSString stringWithFormat:@"Message sent from user: %@ to user: %@ content: %@", self.uid, self.peerID, self.peerMsg];
}
else
{
self.text = [NSString stringWithFormat:@"Message failed to send from user: %@ to user: %@ content: %@ Error: %ld", self.uid, self.peerID, self.peerMsg, (long)errorCode];
}
}];
自 2.2.0 版本起,我们对点对点消息进行了调整,将其定义为用户频道(User Channel):通过 publish
方法发送消息,通过 didReceiveMessageEvent
事件通知接收消息。这一新方法的实现效果与 v1 版本中点对点消息的功能完全一致你,你可以按照以下方式去实现:
// v2
// 适用于 2.2.0 及之后版本
NSString* message = @"Hello Agora!";
NSString* user = @"Tony";
AgoraRtmPublishOptions* publish_option = [[AgoraRtmPublishOptions alloc] init];
publish_option.channelType = AgoraRtmChannelTypeUser;
[rtm publish:user message:message option:publish_option completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"publish success!!");
} else {
NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
当然,你也可以通过 Message Channel 来实现收件箱功能。只不过这种方式,发送方无法收到送达回执。
// v2
// 1. 订阅自己收件箱
[_kit subscribeWithChannel:"inbox_Tony" option:nil completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if(errorInfo == nil) {
self.text = [NSString stringWithFormat:@"Successfully subscribe channel %@",self.channelID];
NSLog(@"%@", self.text);
} else {
self.text = [NSString stringWithFormat:@"Failed to subscribe channel %@ Code: %ld",self.channelID, (long)errorInfo.errorCode];
NSLog(@"%@", self.text);
}
}];
// 消息内容
NSString* payload = @"{
type: "PrivateMessage",
message: "This is a message",
sender: "Tony"
}";
// 2. 向 Lily 发送消息
[rtm publish:"inbox_Lily" message:message option:nil completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"publish success!!");
} else {
NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
图片与文件消息
出于对用户数据和隐私保护合规性、成本优化的考虑,RTM 自 1.5.0 版本起不再直接支持传输图片和文件消息,相关的 API 也已经下架。你可以结合 RTM 和第三方对象存储服务(例如 Amazon S3 或者阿里云 OSS)来构建图片与文件消息功能,在获得极佳的实时消息传输体验的同时,还能实现更灵活的技术构建方案,例如,实现 CDN 静态资源加速、图片文本审核等业务需求。以下示例代码向你展示如何使用 v2 和 Amazon S3 对象性存储服务实现图片和文件消息的构建和发送:
// 文件上传成功后,自定义 RTM 文件消息负载结构
NSString* imageMessagePayload = @"{
// 文件类型,接收方可以根据此字段解析消息包结构
type:'File',
// 你在 Amazon S3 上的 bucket 名称,接收方需要此字段来下载文件
bucket:uploadParams.Bucket,
// 文件在 Amazon S3 存储的 Key,接收方需要此字段来下载文件
key:uploadParams.Key,
// 文件类型
contentType:uploadParams.ContentType,
// 文件 URL 地址
url:data.Location,
// 发送方的用户 ID
sender:userId
}";
// 使用 RTM v2 发送文件消息负载
AgoraRtmPublishOptions* option = [[AgoraRtmPublishOptions alloc] init];
option.customType = @"File";
[rtm publish:channelName message:imageMessagePayload option:option completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"publish success!!");
} else {
NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
使用 Amazon S3 实现静态文件存储时,你需要进入 Amazon S3 控制台,然后设置正确的用户权限和访问策略。详见访问控制最佳实践。
用户出席与自定义状态
在 v1 中,你可以订阅或查询多个用户的在线状态、查询频道人数或频道在线成员列表等。v2 不仅保留了这些能力,还在 v1 的基础上进行了升级和扩展,新设计了 Presence 模块。Presence 模块提供监控用户上线、下线及用户临时状态变更的能力,你可以实时获取以下信息:
- 用户加入或离开指定频道
- 自定义临时用户状态及其变更
- 查询指定用户加入或订阅了哪些频道
- 查询指定频道有哪些用户加入及其用户临时状态数据
你可以调用 whoNow
方法,实时查询指定频道的在线用户数量、在线用户列表及在线用户的临时状态等信息。
// v2
AgoraRtmPresenceOptions* presence_opt = [[AgoraRtmPresence alloc] init];
presence_opt.includeState = false;
presence_opt.includeUserId = false;
[[rtm getPresence] whoNow:@"your_channel" channelType:AgoraRtmChannelTypeMessage options:presence_opt completion:^(AgoraRtmWhoNowResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"whoNow success!!");
int user_count = response.totalOccupancy;
} else {
NSLog(@"whoNow failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
你可以调用 whereNow
方法,实时获取指定用户所在频道的列表。
// v2
[[rtm getPresence] whereNow:@"userId" completion:^(AgoraRtmWhereNowResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"whereNow success!!");
int channel_count = response.totalChannel;
NSArray<AgoraRtmChannelInfo *> * channels = response.channels;
} else {
NSLog(@"whereNow failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
为满足业务场景对用户状态的设置需求,v2 提供了设置临时用户状态的能力,你可以通过 setState
方法自定义临时用户状态。用户可以为自己添加分数、游戏状态、位置、心情、连麦状态等自定义状态。
// v2
NSDictionary *states = @{@"key1": @"value1", @"key2": @"value2"};
[[rtm getPresence] setState:@"your_channel" channelType:AgoraRtmChannelTypeMessage items:states completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"setState success!!");
} else {
NSLog(@"setState failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
你也可以随时通过 getState
方法获取用户的在线状态,或者通过 removeState
方法删除用户的状态。用户临时状态变更后,RTM 服务器会触发 AgoraRtmPresenceEventTypeRemoteStateChanged
类型的 didReceivePresenceEvent
事件通知。具体用法见临时用户状态。
在 v2 中,实时监听频道中用户加入、离开、超时掉线或临时状态变更通知会更加方便,你只需实现如下步骤:
-
实现 Presence 事件监听程序
-
加入频道时,开启
withPresence
开关
// v2
// 1. 实现 Presence 事件监听程序
@interface RtmListener : NSObject <AgoraRtmClientDelegate>
@end
@implementation RtmListener
// Presence 事件通知
-(void) rtmKit:(AgoraRtmClientKit *)rtmKit didReceivePresenceEvent:(AgoraRtmPresenceEvent *)event {
// 实现代码
}
@end
// 2. 加入频道时,开启 withPresence 开关
AgoraRtmSubscribeOptions* option = [[AgoraRtmSubscribeOptions alloc] init];
option.features = AgoraRtmSubscribeChannelFeaturePresence;
[rtm subscribeWithChannel:@"you_channel" option:opt completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"subscribe success!!");
} else {
NSLog(@"subscribe failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
v2 对实时通知进行了全新的设计,在频道中采取两种模式将 Presence 事件通知到订阅用户:实时通知模式 (Announce) 和定时通知模式 (Interval)。你可以在控制台的项目设置中通过实时通知最大人数大小来决定两种模式相互切换的条件。其中,定时通知模式可防止频道内在线用户过多而导致的事件嘈杂,详见事件通知模式。
用户属性与频道属性
基于 v1 的用户属性和频道属性功能,v2 新增了版本控制和锁控制等能力,并优化了 API 接口形式,让功能的使用更加简单。v2中把用户属性和频道属性挂载在 Storage 模块下,以设置频道属性为例,示例代码如下:
// v2
// 创建 Metadata
AgoraRtmMetadata* metadata = [[AgoraRtmMetadata alloc] init];
// 设置 Metadata Item
AgoraRtmMetadataItem* apple = [[AgoraRtmMetadataItem alloc] init];
apple.key = @"Apple";
apple.value = @"100";
apple.revision = 174298200;
AgoraRtmMetadataItem* banana = [[AgoraRtmMetadataItem alloc] init];
banana.key = @"Banana";
banana.value = @"200";
banana.revision = 174298100;
NSArray *item_array = [NSArray arrayWithObjects:apple,banana];
metadata.items = item_array;
metadata.majorRevision = 174298100;
// 记录设置 Metadata Item 的时间戳和用户 ID
AgoraRtmMetadataOptions* metadata_opt = [[AgoraRtmMetadataOptions alloc] init];
metadata_opt.recordUserId = true;
metadata_opt.recordTs = true;
[[rtm getStorage] setChannelMetadata:@"channel_name" channelType:AgoraRtmChannelTypeMessage data:metadata options:metadata_opt lock:@"lockName" completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"setChannelMetadata success!!");
} else {
NSLog(@"setChannelMetadata failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
如何获取、更新、删除频道属性,如何使用 CAS 控制、锁控制等可以参考频道属性。用户属性的使用与频道属性是类似的,详见用户属性。
v2 通过 didReceiveStorageEvent
类型的事件通知将频道属性和用户属性分发给用户,监听 didReceiveStorageEvent
事件通知的步骤如下:
-
实现 Storage 事件监听程序
-
加入频道时,开启
withMetadata
开关
// v2
// 1. 实现 Storage 事件监听程序
@interface RtmListener : NSObject <AgoraRtmClientDelegate>
@end
@implementation RtmListener
// Storage 事件通知
-(void) rtmKit:(AgoraRtmClientKit *)rtmKit didReceiveStorageEvent:(AgoraRtmStorageEvent *)event {
// 实现代码
}
@end
// 2. 加入频道时,添加 Metadata 的 feature
AgoraRtmSubscribeOptions* option = [[AgoraRtmSubscribeOptions alloc] init];
option.features = AgoraRtmSubscribeChannelFeatureMetadata;
[rtm subscribeWithChannel:@"you_channel" option:opt completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) {
if (errorInfo == nil) {
NSLog(@"subscribe success!!");
} else {
NSLog(@"subscribe failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason);
}
}];
访问区域限定
RTM 支持限定访问区域功能,以适应不同国家或地区的法律法规。开启限定访问区域功能后,不论用户在哪个区域使用你的 App,SDK 都只会访问指定区域的声网服务器。v2 实现访问区域限定的代码和 v1 有区别。
- v1 的示例代码如下:
AgoraRtmServiceContext* context = [[AgoraRtmServiceContext alloc] init];
context.areaCode = AgoraAreaCodeGLOB;
[AgoraRtmKit setRtmServiceContext:context];
- v2 的示例代码如下:
AgoraRtmClientConfig* rtm_config = [[AgoraRtmClientConfig alloc] initWithAppId:_appID userId:_uid];
rtm_config.areaCode = AgoraRtmAreaCodeGLOB;
NSError* initError = nil;
AgoraRtmClientKit* rtm = [[AgoraRtmClientKit alloc] initWithConfig:rtm_config delegate:self error:&initError];
其他新特性
除上述版本之间的功能差异之外,v2 还额外增加了很多被广泛验证和使用的新功能,你可以根据项目的需要选择和使用,相信革新版本的 v2 一定可以帮助你快速接入实时互动领域。v2 所具备的功能特性见特性列表。