本文详细介绍如何建立一个简单的项目并使用声网 RTM SDK 实现消息发送与接收。
登录 RTM 系统包括以下流程:
你的业务服务器登录 RTM。
发送和接收点对点消息包括以下流程:
发送和接收频道消息包括以下流程:
按照以下步骤,在控制台创建一个声网项目。
在项目管理页面,点击创建按钮。
在弹出的对话框内输入项目名称,选择鉴权机制为 APP ID + Token。
点击提交,新建的项目就会显示在项目管理页中。
声网会给每个项目自动分配一个 App ID 作为项目唯一标识。
在声网控制台的项目管理页面,找到你的项目,点击 App ID 右侧的眼睛图标就可以直接复制项目的 App ID。
点击编辑进入编辑项目页面,你可以点击眼睛图标查看并复制 App 证书。
为提高项目的安全性,声网推荐使用 Token 对即将登录 RTM 系统的用户进行鉴权。
为了方便测试,声网服务器提供部署签发 RTM Token 的功能。参考以下步骤获取 RTM Token:
login
时,请确保填入的用户 ID 与生成 RTM Token 时填入的用户 ID 一致。新建一个目录 RTM_quickstart
,目录中包含以下文件夹:
RTM_quickstart/
├── src
└── lib
下载最新版实时消息 Linux Java SDK 并解压。将 SDK 包中的 *.so
文件和 *.jar
文件复制到 lib
目录下。
在 RTM_quickstart
目录下新建 pom.xml
文件。文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.agora</groupId>
<artifactId>RTM-Client-Demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>io.agora.rtm</groupId>
<artifactId>agora-rtm-sdk</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<!-- Attach the shade into the package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>io.agora.mainClass.RtmJavaDemo</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
在 RTM_quickstart\src\main\java\io\agora
目录下新建 RtmJavaDemo.java
文件,并按照以下步骤实现基本逻辑:
导入以下库:
package io.agora.mainClass;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import io.agora.rtm.RtmClient;
import io.agora.rtm.RtmClientListener;
import io.agora.rtm.RtmMessage;
import io.agora.rtm.RtmFileMessage;
import io.agora.rtm.RtmImageMessage;
import io.agora.rtm.RtmMediaOperationProgress;
import io.agora.rtm.ErrorInfo;
import io.agora.rtm.ResultCallback;
import io.agora.rtm.RtmChannel;
import io.agora.rtm.RtmChannelListener;
import io.agora.rtm.RtmChannelMember;
import io.agora.rtm.RtmStatusCode;
import io.agora.rtm.RtmChannelAttribute;
设置 App ID 和 Token。
class Auth {
public static final String APP_ID = "<Your App ID>";
public static final String Token = "<Your token>";
}
实现 RtmChannelListener
接口,重写以下回调:
onMessageReceived
:收到频道消息时触发,并返回成员 uid 和消息实例onMemberJoined
:频道成员加入时触发,并返回成员 uidonMemberLeft
:频道成员离开频道时触发,并返回成员 uidclass ChannelListener implements RtmChannelListener {
private String channel_;
public ChannelListener(String channel) {
channel_ = channel;
}
@Override
public void onMemberCountUpdated(int memberCount) {
}
@Override
public void onAttributesUpdated(List<RtmChannelAttribute> attribute) {
}
// 收到频道消息时触发,并返回成员 uid 和消息实例
@Override
public void onMessageReceived(
final RtmMessage message, final RtmChannelMember fromMember) {
String account = fromMember.getUserId();
String msg = message.getText();
System.out.println("Receive message from channel: " + channel_ +
" member: " + account + " message: " + msg);
}
// 频道成员加入时触发,并返回成员 uid
@Override
public void onMemberJoined(RtmChannelMember member) {
String account = member.getUserId();
System.out.println("member " + account + " joined the channel "
+ channel_);
}
// 频道成员离开频道时触发,并返回成员 uid
@Override
public void onMemberLeft(RtmChannelMember member) {
String account = member.getUserId();
System.out.println("member " + account + " left the channel "
+ channel_);
}
@Override
public void onImageMessageReceived(RtmImageMessage message, RtmChannelMember fromMember){
}
@Override
public void onFileMessageReceived(RtmFileMessage message, RtmChannelMember fromMember){
}
}
实现主应用类 RtmJavaDemo
。包含以下逻辑:
onConnectionStateChanged
:连接状态变化时触发,并返回变更后的状态及变更原因onMessageReceived
:收到点对点消息时触发,并返回消息实例和消息发送方的 uidpublic class RtmJavaDemo {
private RtmClient mRtmClient;
private RtmChannel mRtmChannel;
private boolean loginStatus = false;
private Scanner scn;
public void init() {
try {
// 初始化客户端实例
mRtmClient = RtmClient.createInstance(Auth.APP_ID,
new RtmClientListener() {
// 连接状态变化回调
@Override
public void onConnectionStateChanged(int state, int reason) {
System.out.println("on connection state changed to "
+ state + " reason: " + reason);
}
// 收到点对点消息回调
@Override
public void onMessageReceived(RtmMessage rtmMessage, String peerId) {
String msg = rtmMessage.getText();
System.out.println("Receive message: " + msg
+ " from " + peerId);
}
@Override
public void onTokenExpired() {
}
@Override
public void onPeersOnlineStatusChanged(Map<String, Integer> peersStatus) {
}
@Override
public void onImageMessageReceivedFromPeer(RtmImageMessage message, String peerId){
}
@Override
public void onFileMessageReceivedFromPeer(RtmFileMessage message, String peerId){
}
@Override
public void onMediaUploadingProgress(RtmMediaOperationProgress progress, long requestId){
}
@Override
public void onMediaDownloadingProgress(RtmMediaOperationProgress progress, long requestId){
}
});
} catch (Exception e) {
System.out.println("Rtm sdk init fatal error!");
throw new RuntimeException("Need to check rtm sdk init process");
}
scn = new Scanner(System.in);
}
public boolean login() {
System.out.println("Please enter userID (literal \"null\" or starting " +
"with space is not allowed, no more than 64 characters!):");
String userId = scn.nextLine();
if (userId.equals("") ||
userId.startsWith(" ") ||
userId.equals("null")) {
System.out.println("Invalid userID detected!");
return false;
}
// 登录 RTM 系统
mRtmClient.login(Auth.Token, userId, new ResultCallback<Void>() {
//@Override
public void onSuccess(Void responseInfo) {
loginStatus = true;
System.out.println("login success!");
}
//@Override
public void onFailure(ErrorInfo errorInfo) {
loginStatus = false;
System.out.println("login failure!");
}
});
return true;
}
// 登出 RTM 系统
public void logout() {
loginStatus = false;
mRtmClient.logout(null);
}
// 发送点对点消息界面
public void p2pChat(String dst) {
String msg;
while(true) {
System.out.println("please input message you want to send,"+
" or input \'quit\' " + " to leave p2pChat");
msg = scn.nextLine();
if (msg.equals("quit")) {
return;
} else {
sendPeerMessage(dst, msg);
}
}
}
// 发送频道消息界面
public void groupChat(String channel) {
String msg;
mRtmChannel = mRtmClient.createChannel(channel,
new ChannelListener(channel));
if (mRtmChannel == null) {
System.out.println("channel created failed!");
return;
}
mRtmChannel.join(new ResultCallback<Void>() {
@Override
public void onSuccess(Void responseInfo) {
System.out.println("join channel success!");
}
@Override
public void onFailure(ErrorInfo errorInfo) {
System.out.println("join channel failure! errorCode = "
+ errorInfo.getErrorCode());
}
});
while(true) {
System.out.println("please input message you want to send,"+
" or input \'quit\' " + " to leave groupChat, " +
"or input \'members\' to list members");
msg = scn.nextLine();
if (msg.equals("quit")) {
mRtmChannel.leave(null);
mRtmChannel.release();
mRtmChannel = null;
return;
} else if (msg.equals("members")) {
getChannelMemberList();
} else {
sendChannelMessage(msg);
}
}
}
// 发送点对点消息
public void sendPeerMessage(String dst, String message) {
RtmMessage msg = mRtmClient.createMessage();
msg.setText(message);
mRtmClient.sendMessageToPeer(dst, msg, new ResultCallback<Void>() {
@Override
public void onSuccess(Void aVoid) {
}
@Override
public void onFailure(ErrorInfo errorInfo) {
final int errorCode = errorInfo.getErrorCode();
System.out.println("Send Message to peer failed, errorCode = "
+ errorCode);
}
});
}
// 获取频道成员列表
public void getChannelMemberList() {
mRtmChannel.getMembers(new ResultCallback<List<RtmChannelMember>>() {
@Override
public void onSuccess(final List<RtmChannelMember> responseInfo) {
for (int i = 0; i < responseInfo.size(); i++) {
System.out.println("memberlist[" + i + "]" + ": "
+ responseInfo.get(i).getUserId());
}
}
@Override
public void onFailure(ErrorInfo errorInfo) {
System.out.println("failed to get channel members, errCode = "
+ errorInfo.getErrorCode());
}
});
}
// 发送频道消息
public void sendChannelMessage(String msg) {
RtmMessage message = mRtmClient.createMessage();
message.setText(msg);
mRtmChannel.sendMessage(message, new ResultCallback<Void>() {
@Override
public void onSuccess(Void aVoid) {
}
@Override
public void onFailure(ErrorInfo errorInfo) {
final int errorCode = errorInfo.getErrorCode();
System.out.println("Send Message to channel failed, erroCode = "
+ errorCode);
}
});
}
// main 函数实现 CLI 界面逻辑
public static void main(String[] args) {
RtmJavaDemo client_ = new RtmJavaDemo();
client_.init();
while(true) {
if (!client_.loginStatus) {
if (!client_.login())
continue;
}
System.out.println("1: peer to peer chat\n"
+ "2: group chat\n"
+ "3: logout");
System.out.println("please input your choice:");
Scanner scn = new Scanner(System.in);
int choice;
if (scn.hasNextInt()) {
choice = scn.nextInt();
} else {
System.out.println("your input is not an int type");
continue;
}
if (choice == 1) {
System.out.println("please input your destination user ID:");
scn.nextLine();
String dst = scn.nextLine();
System.out.println("input destination ID:" + dst);
client_.p2pChat(dst);
} else if (choice == 2) {
System.out.println("please input your channel ID:");
scn.nextLine();
String channel = scn.nextLine();
client_.groupChat(channel);
} else if (choice == 3) {
client_.logout();
System.out.println("quit the demo? yes/no");
scn.nextLine();
if (scn.hasNextLine()) {
String quit = scn.nextLine();
if (quit.equals("yes")) {
break;
}
}
} else {
continue;
}
}
System.out.println("leaving demo...");
System.exit(0);
}
}
将 .jar
文件安装到本地 maven。
$ mvn install:install-file -Dfile=lib/agora_rtm.jar -DgroupId=io.agora.rtm -DartifactId=agora-rtm-sdk -Dversion=1.0 -Dpackaging=jar
在 pom.xml
文件所在目录运行以下命令,使用 maven 进行打包。
$ mvn package
使用以下命令运行示例项目。
$ java -cp target/RTM-Client-Demo-1.0-SNAPSHOT.jar -Dsun.boot.library.path=lib/ io.agora.mainClass.RtmJavaDemo
RTM 支持多个相互独立的 RtmClient 实例。
在收发点对点消息或进行其他频道操作前,请确保你已成功登录声网 RTM 系统(即确保已经收到 onSuccess)。
使用频道核心功能前必须通过调用 createChannel 方法创建频道实例。
你可以创建多个 RtmClient 客户端实例,但是每个客户端实例最多只能同时加入 20 个频道。每个频道的 channelId
参数应该不同。
当离开了频道且不再加入该频道时,可以调用 release 方法及时释放频道实例所占用的资源。
接收到的 RtmMessage 消息对象不能重复利用再用于消息发送。