云信im在Android中的使用2

昨天写的是云信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

相关推荐
LSL666_1 小时前
5 Repository 层接口
android·运维·elasticsearch·jenkins·repository
alexhilton4 小时前
在Jetpack Compose中创建CRT屏幕效果
android·kotlin·android jetpack
2501_940094026 小时前
emu系列模拟器最新汉化版 安卓版 怀旧游戏模拟器全集附可运行游戏ROM
android·游戏·安卓·模拟器
下位子7 小时前
『OpenGL学习滤镜相机』- Day9: CameraX 基础集成
android·opengl
参宿四南河三8 小时前
Android Compose SideEffect(副作用)实例加倍详解
android·app
火柴就是我9 小时前
mmkv的 mmap 的理解
android
没有了遇见9 小时前
Android之直播宽高比和相机宽高比不支持后动态获取所支持的宽高比
android
shenshizhong10 小时前
揭开 kotlin 中协程的神秘面纱
android·kotlin
vivo高启强10 小时前
如何简单 hack agp 执行过程中的某个类
android
沐怡旸10 小时前
【底层机制】 Android ION内存分配器深度解析
android·面试