昨天写的是云信IM版本的V10以上的,但是我目前项目使用的是V9也就是V10以下的版本,两者在使用方式上还是有所区别的,所以今天想了想,还是写一篇V10以下的,也贴上自己的一些代码,比较有参考性
一、首先我们先贴出云信IM官网的首页(https://doc.yunxin.163.com/messaging/guide?platform=android)

官网是有给出demo,第一次使用的可以先下载demo,先跑看看,体验一下
我使用的是IM Demo
主要是项目只需要用到消息模块,单聊,群聊,通讯录等,语聊方面我们项目使用的是ZEGO即构,不是云信
二、根据以上需要的功能,我们就在项目来集成并使用
1.我们的集成方式是通过 Gradle 自动集成,也是推荐的集成方式
allprojects {
repositories {
mavenCentral()
}
}
android {
defaultConfig {
ndk {
//设置支持的 SO 库架构
abiFilters "armeabi-v7a", "x86","arm64-v8a","x86_64"
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
// 添加依赖。注意,版本号必须一致。
// 基础功能 (必需)
implementation "com.netease.nimlib:basesdk:${LATEST_VERSION}"
// 聊天室需要
implementation "com.netease.nimlib:chatroom:${LATEST_VERSION}"
// 通过网易云信来集成小米等厂商推送需要
implementation "com.netease.nimlib:push:${LATEST_VERSION}"
// 超大群需要
implementation "com.netease.nimlib:superteam:${LATEST_VERSION}"
// 全文检索插件
implementation "com.netease.nimlib:lucene:${LATEST_VERSION}"
// 海外融合存储需要
// 该功能仅支持 Gradle 集成,不提供手动集成方式
implementation "com.netease.nimlib:fusionstorage:${LATEST_VERSION}"
implementation "com.google.code.gson:gson:${GSON_VERSION}" // Gson 推荐版本 2.8.9
}
2.添加权限
使用云信IM的相关功能是需要一定的权限
<?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" />
<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.push.net.HeartbeatService"
android:process=":core"
/>
<!-- 声明云信后台辅助服务 -->
<service
android:name="com.netease.nimlib.job.NIMJobService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":core"
/>
<!-- 云信SDK的监视系统启动和网络变化的广播接收器,用户开机自启动以及网络变化时候重新登录 -->
<receiver
android:name="com.netease.nimlib.service.NimReceiver"
android:exported="false"
android:process=":core"
>
<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.cp.provider.PreferenceContentProvider"
android:authorities="${applicationId}.ipc.provider.preference"
android:exported="false"
/>
<provider
android:name="com.netease.nimlib.ipc.NIMContentProvider"
android:authorities="${applicationId}.ipc.provider"
android:exported="false"
android:process=":core"
/>
</application>
</manifest>
3.添加混淆
不然在项目打包时会被混淆,所以需要防止被混淆
-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.** {*;}
三、云信IM初始化
以上通过集成完后,我们就需要在项目进行相关的初始化
public class NimApplication extends Application {
public void onCreate() {
// ... your codes
// SDK 初始化(启动后台服务,若已经存在用户登录信息,SDK 将进行自动登录)。不能对初始化语句添加进程判断逻辑。
NIMClient.init(this, loginInfo(), options());
// ... your codes
// 使用 `NIMUtil` 类可以进行主进程判断。
// boolean mainProcess = NIMUtil.isMainProcess(context)
if (NIMUtil.isMainProcess(this)) {
// 注意:以下操作必须在主进程中进行
// 1、UI 相关初始化操作
// 2、相关 Service 调用
}
}
// 如果提供,将同时进行自动登录。如果当前还没有登录用户,请传入 null。请参考自动登录章节。
private LoginInfo loginInfo() {
return null;
}
// 设置初始化配置参数,如果返回值为 null,则全部使用默认参数。
private SDKOptions options() {
SDKOptions options = new SDKOptions();
...
// 配置是否需要预下载附件缩略图,默认为 true
options.preloadAttach = true;
...
return options;
}
}

以上是官网给出的初始化方式和建议
以下是我们项目的初始化方式:
object HaTioNimConfig {
private var isInitNimConfig = false
/**
* 云信im SDK/NimClient 配置 初始化
*/
fun initNimSDKConfig(context: Context) {
if (!isInitNimConfig) {
isInitNimConfig = true
//云信im 初始化
NIMClient.init(context, getLoginSuccessInfo(), initNimSDKOptionsSettings(context))
//通知栏消息提醒开关
NIMClient.toggleNotification(true)
//注册云信im 的 相关事件注册
registerNimIM(context)
}
}
/**
* 获取登录成功的信息
*/
private fun getLoginSuccessInfo(): LoginInfo? {
val account: String = HaTioModuleManager.getUserProvider()?.getLoginInfo()?.id ?: ""
val token: String = HaTioModuleManager.getUserProvider()?.getLoginInfo()?.imToken ?: ""
HaTioLog.d("getTopImLogin 云信登录 --> account=$account")
HaTioLog.d("getTopImLogin 云信登录 --> token=$token")
return if (!TextUtils.isEmpty(account) && !TextUtils.isEmpty(token)) {
LoginInfo(account, token)
} else {
null
}
}
/**
* 云信sdk 相关数据 配置
*/
private fun initNimSDKOptionsSettings(context: Context): SDKOptions {
val options = SDKOptions()
options.appKey = AppConfigManager.appKey
options.notifyStickTopSession = false //客户端会话置顶
options.disableAwake = true
options.sessionReadAck = true
options.serverConfig = initServerConfig()
options.sdkStorageRootPath = initSdkStorageRootPath(context)
options.messageNotifierCustomization = initMessageNotifierCustomization()
val notificationConfig = initStatusBarNotificationConfig()
notificationConfig.titleOnlyShowAppName = true
options.statusBarNotificationConfig = notificationConfig
return options
}
}
class HaTioMessageInit : IHaTioInit {
//todo 初始化消息相关sdk
override fun onInitModuleSdk(application: Application?) {
application?.let {
HaTioNimConfig.initNimSDKConfig(it)
}
}
}
class HaTioInitConfig {
companion object {
val instance: HaTioInitConfig by lazy { HaTioInitConfig() }
val LoginInit = "com.nim.imchat.HaTioLoginInit"
val MsgInit = "com.nim.imchat.HaTioMessageInit"
val UserInit = "com.nim.imchat.HaTioUserInit"
val initModuleNames = arrayOf(LoginInit, MsgInit,UserInit)
}
fun initModuleSdk(application: Application?){
for (moduleInitName in initModuleNames) {
try {
val clazz = Class.forName(moduleInitName)
val init = clazz.getDeclaredConstructor().newInstance() as IHaTioInit
// 调用初始化方法
init.onInitModuleSdk(application)
} catch (e: ClassNotFoundException) {
e.printStackTrace()
} catch (e: InstantiationException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
}
}
}
}
然后在Application中调用
HaTioInitConfig.instance.initModuleSdk(this)
四、登录IM
初始化以后,就可以登录IM,只有登录成功后才可以获取IM的相关信息
我们项目的逻辑是,先登录自己的接口,成功后再通过登录成功返回的信息去登录云信IM
fun loginApp(
username: String = "",
captcha: String
) {
val map = hashMapOf<String, Any>()
map["username"] = username
map["captcha"] = captcha
launchReqCall(
block = { HaTioLoginRepository.loginApp(map) },
onSuccess = { userInfo ->
HaTioModuleManager.getMessageProvider()
?.tioImLogin(account = userInfo?.id ?: "", token = userInfo?.imToken ?: "") {
if (it) {
//云信登录成功
}else{
//云信登录失败
}
}
},
onFail = { code, msg, status ->
_userLoginInfo.tryEmit(null)
},
loadVisible = true,
errorToast = true,
successToast = false
)
}
class HaTioMsgImpl : IHaTioMessageProvider {
override fun init(context: Context?) {
}
override fun tioImLogin(
account: String,
token: String,
callback: ((Boolean) -> Unit)?
) {
HaTioLog.d("云信登录 account $account token $token")
val loginInfo = LoginInfo(account, token)
NIMClient.getService(AuthService::class.java).login(loginInfo)
.setCallback(object : RequestCallback<LoginInfo> {
override fun onSuccess(result: LoginInfo) {
HaTioLog.d("云信登录 onSuccess ${result.toJson()}")
callback?.invoke(true)
}
override fun onFailed(code: Int) {
HaTioLog.d("云信登录 onFailed $code")
callback?.invoke(false)
}
override fun onException(exception: Throwable) {
HaTioLog.d("云信登录 onException ${exception.message}")
callback?.invoke(false)
}
})
}
override fun timImLogout(callback: ((Boolean) -> Unit)?) {
NIMClient.getService(AuthService::class.java).logout(3 * 1000L)
.setCallback(object : RequestCallback<Void> {
override fun onSuccess(param: Void?) {
HaTioLog.d("云信登出 onSuccess")
callback?.invoke(true)
}
override fun onFailed(code: Int) {
HaTioLog.d("云信登出 onFailed $code")
callback?.invoke(false)
}
override fun onException(exception: Throwable) {
HaTioLog.d("云信登出 onException ${exception.message}")
callback?.invoke(false)
}
})
}
}
五、登录成功后,就可以获取消息列表、聊天列表等
比如:
我们来获取消息列表
NIMSDK.getMsgService().queryRecentContacts(
queryAnchor,
QueryDirectionEnum.QUERY_OLD,
pageSize
).setCallback(object : RequestCallbackWrapper<List<RecentContact>>() {
override fun onResult(code: Int, result: List<RecentContact>?, exception: Throwable?) {
HaTioLog.d("queryRecentContacts code=$code; size=${result?.size} data=${result?.toJson()}}")
}
}
}
})
我们来获取会话列表(聊天列表)
NIMClient.getService(MsgService::class.java)
.queryMessageListEx(
iMMessage ?: haTioCreateDefaultNimMsg(chatImId, chatType),
QueryDirectionEnum.QUERY_OLD,
limit,
true
).setCallback(object : RequestCallback<List<IMMessage>> {
override fun onSuccess(result: List<IMMessage>) {
}
override fun onFailed(code: Int) {}
override fun onException(exception: Throwable?) {}
})
其他的功能,根据官网给出的API来操作就好了
客户端的API:https://doc.yunxin.163.com/messaging/client-apis?platform=android

服务端的API:https://doc.yunxin.163.com/messaging/server-apis?platform=server
