IM 即时通讯
Android
开发指南

实现聊天室消息收发

更新时间: 2024/01/04 17:08:47

聊天室是网易云信 IM 即时通讯服务中一种比群组更加开放、更加自由的组织形态,可帮助您实现真正意义上的大型聊天室,参与人数无上限,又可满足消息到达的实时性要求,主要应用于娱乐直播、教育直播等场景。

本文介绍如何通过较少的代码集成 NetEase IM SDK (以下简称 NIM SDK)并调用相关 API,在您的应用中实现聊天室消息收发。

使用前准备

实现流程

流程概览

实现聊天室消息收发的流程,可分为下图所示的 5 步:

聊天室登录方式分为独立模式非独立模式

  • 非独立模式:先登录 IM,再登录聊天室,适用于同时需要 IM 和聊天室功能的业务场景。

  • 独立模式:无需先登录 IM,可直接登录聊天室,适用于只需要聊天室功能的业务场景。

uml diagram

步骤1: 集成 NIM SDK

本节仅介绍更为快速的 Gradle 自动集成方式。如需查看手动集成的具体说明,请参见手动集成

Gradle 自动集成

  1. 创建 Android 项目。若已有 Android 项目,则跳过该步骤。

    打开 Android Studio,在顶部菜单依次选择 File > New > New Project 新建工程,再依次选择 Phone and Tablet > Empty Activity,单击 Next
    创建 Android 项目成功后,Android Studio 会自动开始同步 gradle, 您需要等同步成功后再进行下一步操作。

  2. 在项目根目录下的build.gradle文件中,在 repositories 后配置 mavenCentral,示例代码如下:

    allprojects {
        repositories {
            mavenCentral()
        }
    }
    
  3. 在主工程的 build.gradle 文件中,设置支持的 SO 库架构。

    android {
        defaultConfig {
            ndk {
                //设置支持的 SO 库架构
                abiFilters "armeabi-v7a", "x86","arm64-v8a","x86_64"
            }
        }
    }
    
  4. 在主工程的 build.gradle 文件中,根据需要添加对应的依赖库:

    dependencies {
        implementation fileTree(dir: 'libs', include: '*.jar')        
        // 添加 IM 基础功能依赖 (必需),LATEST_VERSION 为 SDK 最新版本号
        implementation "com.netease.nimlib:basesdk:${LATEST_VERSION}"
        // 添加第三方离线推送相关依赖(可选),LATEST_VERSION 为 SDK 最新版本号
        implementation "com.netease.nimlib:push:${LATEST_VERSION}"
        // 添加聊天室相关依赖(聊天室功能必需),LATEST_VERSION 为 SDK 最新版本号
        implementation "com.netease.nimlib:chatroom:${LATEST_VERSION}"
    }
    

    添加的各依赖库版本号必须一致。可在SDK 下载页面查看当前最新版本号。

添加权限

根据实际应用需求,在 AndroidManifest.xml 中添加所需权限。请将 com.netease.nim.demo 替换为自己的包名。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	      package="com.netease.nim.demo">
	<!-- 权限声明 -->
	<!-- 访问网络状态-->
	<uses-permission android:name="android.permission.INTERNET" />
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
	<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
	
    <!-- 外置存储存取权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <!-- 多媒体相关 -->
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <!-- Android11:V8.6.1及之后的版本不需要;其他:V4.4.0及之后的版本不需要 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

    <!-- 控制呼吸灯,振动器等,用于新消息提醒 -->
    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <uses-permission android:name="android.permission.VIBRATE" />
    
    <!-- 8.0+系统需要-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />


    <!-- 下面的 uses-permission 一起加入到你的 AndroidManifest 文件中。 -->
    <permission
        android:name="com.netease.nim.demo.permission.RECEIVE_MSG"
        android:protectionLevel="signature"/>

     <uses-permission android:name="com.netease.nim.demo.permission.RECEIVE_MSG"/>

    <application
        ...>
        <!-- APP key, 可以在这里设置,也可以在 SDKOptions 中提供。
            如果 SDKOptions 中提供了,则取 SDKOptions 中的值。 -->
        <meta-data
            android:name="com.netease.nim.appKey"
            android:value="key_of_your_app" />

        <!-- 云信后台服务,请使用独立进程。 -->
        <service
            android:name="com.netease.nimlib.service.NimService"
            android:process=":core"/>

       <!-- 云信后台辅助服务 -->
        <service
            android:name="com.netease.nimlib.service.NimService$Aux"
            android:process=":core"/>

        <!-- 云信后台辅助服务 -->
        <service
            android:name="com.netease.nimlib.job.NIMJobService"
            android:exported="false"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:process=":core"/>

        <!-- 云信监视系统启动和网络变化的广播接收器,保持和 NimService 同一进程 -->
        <receiver android:name="com.netease.nimlib.service.NimReceiver"
            android:process=":core"
            android:exported="false">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
            </intent-filter>
        </receiver>

        <!-- 云信进程间通信 Receiver -->
        <receiver android:name="com.netease.nimlib.service.ResponseReceiver"/>

        <!-- 云信进程间通信service -->
        <service android:name="com.netease.nimlib.service.ResponseService"/>

        <!-- 云信进程间通信provider -->
        <provider
            android:name="com.netease.nimlib.ipc.NIMContentProvider"
            android:authorities="com.netease.nim.demo.ipc.provider"
            android:exported="false"
            android:process=":core" />
      	
      	<!-- 云信内部使用的进程间通信provider -->
      	<!-- SDK启动时会强制检测该组件的声明是否配置正确,如果检测到该声明不正确,SDK会主动抛出异常引发崩溃 -->
        <provider
            android:name="com.netease.nimlib.ipc.cp.provider.PreferenceContentProvider"
            android:authorities="com.netease.nim.demo.ipc.provider.preference"
            android:exported="false" />
    </application>
</manifest>

防止代码混淆

为了避免代码混淆而导致调用接口异常,请在 proguard-rules.pro 文件中添加以下代码,将 NIM SDK 相关类加入不混淆名单。

-dontwarn com.netease.nim.**
-keep class com.netease.nim.** {*;}

-dontwarn com.netease.nimlib.**
-keep class com.netease.nimlib.** {*;}

-dontwarn com.netease.share.**
-keep class com.netease.share.** {*;}

-dontwarn com.netease.mobsec.**
-keep class com.netease.mobsec.** {*;}

#如果你使用全文检索插件,需要加入
-dontwarn org.apache.lucene.**
-keep class org.apache.lucene.** {*;}

#如果你开启数据库功能,需要加入
-keep class net.sqlcipher.** {*;}

步骤2: 初始化 SDK

集成 SDK 后,需要先完成 SDK 的初始化后才能使用其他功能。

ApplicationonCreate 中,调用 init 方法进行初始化。

示例代码如下:

public class NimApplication extends Application {
    public void onCreate() {
        NIMClient.init(this, loginInfo(), options());
    // 如果提供用户信息,将同时进行自动登录。如果当前还没有登录用户,请传入null。
    private LoginInfo loginInfo() {
        return null;
    }
    // 设置初始化配置参数,如果返回值为 null,则全部使用默认参数。
    private SDKOptions options() {
        SDKOptions options = new SDKOptions();
        return options;
      }// 可在 SDKOptions 中配置 App Key
    }
}

以上提供了一个简化的初始化示例,更多初始化信息请参见初始化 SDK

(可选)步骤3: 登录云信 IM

若您采用非独立模式登录聊天室,那么在登录聊天室之前需要先登录 IM。若您采用独立模式登录聊天室,则跳过该步骤。

  1. 调用 AuthServiceObserver.observeOnlineStatus 方法监听 IM 登录状态。

    NIMClient.getService(AuthServiceObserver.class).observeOnlineStatus(
        new Observer<StatusCode> () {
            public void onEvent(StatusCode status) {
        //获取状态的描述
        String desc = status.getDesc();
                if (status.wontAutoLogin()) {
                    // 被踢出、账号被禁用、密码错误等情况,自动登录失败,需要返回到登录界面进行重新登录操作
                }
            }
    }, true);
    
  2. (可选)调用observeLoginSyncDataStatus方法监听登录后数据同步过程。

    示例代码如下:

    NIMClient.getService(AuthServiceObserver.class).observeLoginSyncDataStatus(new Observer<LoginSyncStatus>() {
        @Override
        public void onEvent(LoginSyncStatus status) {
            if (status == LoginSyncStatus.BEGIN_SYNC) {
                LogUtil.i(TAG, "login sync data begin");
            } else if (status == LoginSyncStatus.SYNC_COMPLETED) {
                LogUtil.i(TAG, "login sync data completed");
            }
        }
    }, true);
    
  3. 调用 AuthService#login方法开始手动登录。

    示例代码如下:

    public class LoginActivity extends Activity {
        public void doLogin() {
            LoginInfo info = new LoginInfo(); //传入accid和token
            RequestCallback<LoginInfo> callback =
                new RequestCallback<LoginInfo>() {
                        @Override
                        public void onSuccess(LoginInfo param) {
                            LogUtil.i(TAG, "login success");
                            // your code
                        }
    
                        @Override
                        public void onFailed(int code) {
                            if (code == 302) {
                                LogUtil.i(TAG, "账号密码错误");
                                // your code
                            } else {
                                // your code
                            }
                        }
    
                        @Override
                        public void onException(Throwable exception) {
                            // your code
                        }
            };
    
            //执行手动登录
            NIMClient.getService(AuthService.class).login(info).setCallback(callback);
        }
    }
    
  4. 登录开始后,AuthServiceObserver.observeOnlineStatus 方法的 Observer 接口根据实际登录情况触发回调函数,返回具体的登录状态。如最终返回 LOGINED,则代表登录成功。

步骤4: 登录聊天室

  1. 发送方和接收方调用 ChatRoomServiceObserver.observeOnlineStatus 方法监听聊天室连接状态。

    示例代码如下:

    Observer<ChatRoomStatusChangeData> onlineStatus = new Observer<ChatRoomStatusChangeData>() {
        @Override
        public void onEvent(ChatRoomStatusChangeData chatRoomStatusChangeData) {
            if (!chatRoomStatusChangeData.roomId.equals(roomId)) {
                return;
            }
            if (chatRoomStatusChangeData.status == StatusCode.CONNECTING) {
                // 连接中...
            } else if (chatRoomStatusChangeData.status == StatusCode.LOGINING) {
                // "登录中..."
            } else if (chatRoomStatusChangeData.status == StatusCode.LOGINED) {
                // "已登陆"
            } else if (chatRoomStatusChangeData.status == StatusCode.UNLOGIN) {
                // 登出的状态
            } else if (chatRoomStatusChangeData.status == StatusCode.NET_BROKEN) {
                // "当前网络不可用"
            }
        }
    };
    
    // 注册监听
    NIMClient.getService(ChatRoomServiceObserver.class).observeOnlineStatus(onlineStatus, true);
    // 注销监听
    NIMClient.getService(ChatRoomServiceObserver.class).observeOnlineStatus(onlineStatus, false);
    
  2. 接收方调用 ChatRoomServiceObserver.observeReceiveMessage 方法监听聊天室消息接收。

    示例代码如下:

    Observer<List<ChatRoomMessage>> receiveMsgObserver = new Observer<List<ChatRoomMessage>>() {
        @Override
        public void onEvent(List<ChatRoomMessage> chatRoomMessages) {
            if (chatRoomMessages == null || chatRoomMessages.isEmpty()) {
                return;
            }
        // 收到消息
            for (ChatRoomMessage message : chatRoomMessages) {
                LogUtil.i(TAG, String.format("ChatRoomMessage notifyTargetTags: %s", message.getNotifyTargetTags()));
            }
        }
    };
    // 注册监听聊天室消息接收
    NIMClient.getService(ChatRoomServiceObserver.class).observeReceiveMessage(receiveMsgObserver, true);
    // 注销
    NIMClient.getService(ChatRoomServiceObserver.class).observeReceiveMessage(receiveMsgObserver, false);
    
  3. (可选)若您选择独立模式登录聊天室。独立模式由于不依赖 IM 连接,SDK 无法自动获取聊天室服务器的地址,需要客户端向开发者应用服务器请求该地址,而应用服务器需要向网易云信服务器请求,然后将请求结果原路返回给客户端。因此 SDK 需要提前注册获取聊天室地址的回调方法ChatRoomIndependentCallback

    NIMChatroomIndependentMode *mode = [[NIMChatroomIndependentMode alloc] init];
    mode.username = @"username";
    mode.anonName = @"anonName";
    mode.token = [password toMD5String];    // set password.
    mode.chatroomAppKey = @"your chatroom app key";
    
    [NIMChatroomIndependentMode registerRequestChatroomAddressesHandler:^(NSString * _Nonnull roomId, NIMRequestChatroomAddressesCallback  _Nonnull callback) {
            [YourHTTPService request:roomId completion:^(NSError *error,NSArray *addresses)
            {
                //无论请求是否成功,都需要进行回调
                if(callback)
                {
                    callback(error,addresses);
                }
            }];
        }];
    
  4. 发送方和接收方调用 enterChatRoomenterChatRoomEx方法登录聊天室。

    EnterChatRoomData data = new EnterChatRoomData(roomId);
    data.setLoginAuthType(0);	// 静态 Token,传入0; 可使用 loginInfo.getAuthType();
    data.setLoginExt("设置登录自定义字段"); // 可使用 loginInfo.getLoginExt();
    
    // enterChatRoom
    AbortableFuture<EnterChatRoomResultData> enterRequest = NIMClient.getService(ChatRoomService.class).enterChatRoom(data);
    // enterChatRoomEx
    AbortableFuture<EnterChatRoomResultData> enterRequestEx = NIMClient.getService(ChatRoomService.class).enterChatRoomEx(data, 1);
    
  5. 成功登录聊天室后,ChatRoomServiceObserver.observeOnlineStatus 方法的Observer接口触发回调函数,根据实际连接情况返回连接状态。

步骤5: 聊天室消息收发

NIM SDK 支持多种消息类型,包括文本消息、图片消息、语音消息、视频消息、文件消息、地理位置消息、提示消息、通知消息以及自定义消息。

本节以发送方与接收方的消息交互为例,介绍通过 NIM SDK 快速实现聊天室文本消息收发的流程。

其他类型消息收发相关详情,请参见聊天室消息收发

  1. 发送方调用 ChatRoomServiceObserver.observeMsgStatus 方法监听聊天室消息发送状态。

    示例代码如下:

    Observer<ChatRoomMessage> msgStatusObserver = new Observer<ChatRoomMessage>() {
        @Override
        public void onEvent(ChatRoomMessage chatRoomMessage) {
    	    // 处理 chatRoomMessage
        }
    };
    
    // 注册监听聊天室消息发送状态
    NIMClient.getService(ChatRoomServiceObserver.class).observeMsgStatus(msgStatusObserver, true);
    // 注销
    NIMClient.getService(ChatRoomServiceObserver.class).observeMsgStatus(msgStatusObserver, false);
    
  2. 发送方调用 createChatRoomTextMessage 方法构建聊天室文本消息,然后调用 ChatRoomService.sendMessage 方法在聊天室中发送一条文本消息。

    示例代码如下:

    // 构建聊天室文本消息
    ChatRoomMessage text = ChatRoomMessageBuilder.createChatRoomTextMessage(roomId, "android test");
    // 在聊天室中发送一条文本消息
    NIMClient.getService(ChatRoomService.class).sendMessage(text, false);
    
  3. ChatRoomServiceObserver.observeReceiveMessage 方法的 Observer 接口触发回调函数,接收方通过该回调收到聊天室消息。

后续步骤

为保障通信安全,如果您在调试环境中的使用的是云信控制台生成的测试用 IM 账号 和 Token,请确保在后续的正式生产环境中,将其替换为通过 IM 服务端 API 生成的正式 IM 账号(accid)和 token

相关文档

此文档是否对你有帮助?
有帮助
去反馈
  • 使用前准备
  • 实现流程
  • 流程概览
  • 步骤1: 集成 NIM SDK
  • Gradle 自动集成
  • 添加权限
  • 防止代码混淆
  • 步骤2: 初始化 SDK
  • (可选)步骤3: 登录云信 IM
  • 步骤4: 登录聊天室
  • 步骤5: 聊天室消息收发
  • 后续步骤
  • 相关文档