IM 即时通讯
Android
开发指南

登录 IM

更新时间: 2024/01/03 10:36:23

完成 NIM SDK 的初始化之后,用户需要先调用 SDK 的登录接口登录 IM。登录成功后,用户才能正常调用消息和会话等其他 SDK 接口。

本文介绍账号集成与登录的技术原理、实现 IM 登录的流程、IM 登录状态转换流程,以及相关常见问题

技术原理

IM 的登录与账号集成密切相关。上图展示了应用集成 NIM SDK 后,从账号集成到登录 IM 成功的主要流程:

  1. 用户在应用客户端注册用户账号时,由应用服务端向云信服务端发起创建 IM 账号的请求。
  2. IM 账号创建成功后,云信服务端会返回该 IM 账号(即 accid)和 token 等信息。此时,应用服务端需要负责保存 accidtoken 的映射关系。
  3. 应用客户端发起登录请求时,先走应用自有的登录验证逻辑,如账号和密码的验证。
  4. 验证成功后,应用服务端将与该用户对应的 accidtoken 等信息返回给应用客户端。此时,应用客户端需要负责保存 accidtoken 的映射关系。
  5. 当应用客户端需要调用云信的 IM 服务时,需要先进行 token 验证,以登录 IM 服务。
  6. token 验证成功后,应用客户端登录 IM 服务成功。之后用户便可调用 NIM SDK 的相关接口使用 IM 服务,如进行 IM 消息收发。
  • 终端用户使用云信 IM 服务时,应用本身的用户账号和云信的 IM 账号(accid彼此独立。云信的 IM 账号只用于云信 IM 服务的鉴权,IM 账号并不等同于应用的用户账号
  • 应用的用户账号和密码,与云信登录 IM 使用的 accidtoken 完全不一致。accidtoken 不由终端用户创建,而是由应用服务端分配,以保证安全性。

前提条件

  • 已完成初始化
  • 已在云信控制台配置应用的 IM 登录策略。如未配置相应的登录策略,可能导致后续调用登录接口时因无登录权限而报错(状态码:403)。
  • (可选)已在控制台配置客户端应用标识

实现登录 IM

步骤1:准备 Token

登录 IM 需要通过 Token 进行鉴权。云信支持静态和动态两种 Token 类型,您可根据业务需求进行选择。

  • 静态 Token:默认为永久有效。如有需要,可通过云信服务端 API 主动刷新 Token

  • 动态 Token:具备时效性,可在生成时设置有效期。

获取静态Token

  • 方式一:在控制台获取静态 Token

    如果您只需要进行简单的体验或者快速测试,那么可以在云信控制台创建测试用的 IM 账号,并获取与该 IM 账号相应的静态token,具体参见注册调试用的 IM 账号。获取的静态token可用于下文提及的静态 Token 登录

  • 方式二:调用服务端 API 获取静态 Token

    如果您有正式的生产环境,且您的业务仅需保障基础的用户信息安全,那么可通过云信 IM 服务端 API 注册 IM 账号,并获取与之相对应的静态token,具体参见注册云信 IM 账号。获取的静态token可用于静态 Token 登录的鉴权。

获取动态Token

如果您有正式的生产环境,且您的业务对用户信息安全有较高的要求,可使用动态 token。动态 token 可用于动态 Token 登录的鉴权。

  1. 注册云信 IM 账号,获取 IM 账号(accid)。

  2. 基于 App Key、App Secret 和 accid,通过约定算法在应用服务端生成动态 Token。

  3. 客户端可通过在初始化时实现 SDKOptions#AuthProvider 方法,从回调中获取动态 token

    SDKOptions options = new SDKOptions();
    options.authProvider = new AuthProvider() {
        @Override
        public String getToken(String account) {
            return "your_token";
        }
    };
    

获取动态LoginExt

NIM SDK 也支持获取动态的登录自定义扩展字段 loginExt。动态 loginExt 适用于所有登录模式,其中,在第三方回调登录模式中使用动态 loginExt时,第三方服务器可以使用该字段来进行鉴权。

客户端可通过在初始化时实现 SDKOptions#loginExtProvider 方法,从回调中获取动态 loginExt

options.loginExtProvider = new LoginExtProvider() {

    @Override
    public String getLoginExt(String account) {
        return "your_login_ext";
    }
};

步骤2:监听登录相关回调

监听登录状态

调用observeOnlineStatus方法注册在线状态变化观察者,监听登录状态变化。注册后,观察者(Observer)的onEvent回调函数会立即被调用一次,告知观察者当前的登录状态(StatusCode)。

  • StatusCode枚举各属性的详细说明和具体转换流程,参见文末的登录状态转换流程

  • StatusCode枚举的每个属性包含一个 int 类型的 value 和一个 String 类型的 desc。通过云信 IM 服务端接口封禁 IM 账号时,如果配置了kickNotifyExt,则会表现在onEvent回调函数的 desc 变量中。

示例代码如下:

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

监听数据同步状态

调用observeLoginSyncDataStatus方法注册观察者,监听登录后的数据同步状态(LoginSyncStatus)。

登录 IM 成功后,SDK 会自动同步群信息,离线消息,漫游消息,系统通知等数据。数据同步完成时,整个登录过程才算真正完成

LoginSyncStatus属性
说明
NO_BEGIN 未开始同步
BEGIN_SYNC 开始同步(正在同步)
  • 同步开始时,SDK 数据库中的数据可能还是旧数据
    • 如果是首次登录,那么 SDK 数据库中还没有数据
    • 重新登录时 SDK 数据库中还是上一次退出时保存的数据
  • 在同步过程中,SDK 数据的更新会通过相应的监听接口发出数据变更通知
SYNC_COMPLETED 同步完成。SDK 数据库已完成更新

示例代码如下:

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");
        }
    }
}, register);

监听数据准备完成回调

发送消息等后续操作要求数据库处于开启状态,否则可能导致发送消息失败,或者阻塞等待数据库开启。

当手动登录或自动登录成功后,云信 IM 开始打开数据库,调用 observeDataReady 方法注册观察者,监听数据库成功开启的回调。

首次登录成功后开启数据库会回调,不登出再调用登录不会多次回调。

步骤3:登录 IM

登录方式概览

NIM SDK 登录方式分为两大类,即手动登录和自动登录。其中手动登录可进一步分为静态token登录、动态token登录和通过第三方回调登录。

您可按需实现一种或多种手动登录方式,并在手动登录成功后,实现自动登录。

登录方式
子方式 鉴权方式 使用场景
手动登录 静态 Token 登录 静态 Token 鉴权 如下登录场景,用户需要手动登录 IM:
动态 Token 登录 动态 Token 鉴权
通过第三方回调登录 通过第三方回调鉴权
自动登录 继承手动登录的方式 继承手动登录的鉴权方式 应用被清理后,用户再次点击应用图标启动应用时,无需输入用户名和密码即可完成登录的场景。自动登录需在手动登录成功后使用

推荐在手动登录成功后,将accidtoken保存到本地,方便下次应用启动进行初始化时在SDKOptionsLoginInfo中传入,实现自动登录。更多相关说明,参见IM 登录最佳实践。您也可以参考该文档中提供的 Sample Code 实现 IM 登录。

方式1:手动登录

静态 Token 登录

调用AuthService#login方法手动登录 IM。调用时需将authType参数设置为 0。

调用后,NIM SDK 会自动连接云信服务端,传递用户信息,返回登录结果。登录过程中可主动取消登录。如果因为网络或其他原因导致云信服务端长时间未响应,用户也没有主动取消登录,NIM SDK 将在 45 秒后自动重新连接云信服务端,并返回错误码,错误码详情参见下文的手动登录错误码

LoginInfo 参数
是否必传 说明
account 用户的 IM 账号,即 accid
token 获取到的静态 token
authType 登录 IM 的鉴权方式。采用静态token登录时,使用默认的 0 即可,即静态 token 鉴权
appKey 当前应用的 App Key,一个 App Key 对应一个账号体系如果不填,则优先使用初始化时SDKOptions中配置的 App Key;如果SDKOptions中未配置,则使用 AndroidManifest 中配置的 App Key。
customClientType 自定义客户端类型,小于或等于 0 则视为没有自定义类型
loginExt 登录自定义扩展字段,长度上限为 1k 字符。若在初始化时实现了 loginExtProvider 方法,并且回调该方法时返回了非空的 loginExt 值,则优先取返回值,忽略此处输入的 loginExt 值。

示例代码如下:

//静态token的模式登录IM
public class LoginActivity extends Activity {
    public void doLogin() {
        LoginInfo info = new LoginInfo(); 
        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);
    }
}
动态 Token 登录

NIM SDK 支持动态 token 登录这一登录方式。该登录方式的 token 具备时效性,可有效提升 token 破解难度,降低密码泄露风险。

要实现动态token登录 IM,需完成如下两步操作:

  1. 初始化时,实现SDKOptions#AuthProvider 方法获取上文中提及的基于App Secret生成的动态Token

    SDKOptions options = new SDKOptions();
    options.authProvider = new AuthProvider() {
        @Override
        public String getToken(String account) {
            return "your_token";
        }
    };    
    
  2. 调用AuthService#login方法手动登录 IM,调用时需将 authType设置为 1。

    调用后,NIM SDK 会自动连接云信服务端,传递用户信息,返回登录结果。登录过程中可主动取消登录。如果因为网络或其他原因导致云信服务端长时间未响应,用户也没有主动取消登录,NIM SDK 将在 45 秒后自动重新连接云信服务端,并返回错误码,错误码详情参见下文的手动登录错误码

    具体参数说明如下:

    LoginInfo 参数
    是否必传 说明
    account 用户的 IM 账号,即accid
    authType 该登录方式必传 采用动态token登录时必须传入 1,表示通过动态token鉴权,动态token基于 App Secret 计算生成
    token 静态 token。当 IM 采用动态 token 鉴权方式且在初始化时实现了 SDKOptions#AuthProvider 方法,回调该方法时返回了非空的 token 值,那么优先使用返回的动态 token 进行鉴权;如果回调返回空值,会返回错误码,此时若已传入静态 token,则取此处的静态 token 进行鉴权;如果回调返回空值且未传入静态 token,则直接返回 414 错误码如果您的应用启用了云信的聊天室功能,并且采用非独立模式&静态 token 登录方式鉴权时,那么此处必须传入静态 token。传入后,后续非独立模式的聊天室静态登录时会使用该静态 token
    appKey 当前应用的 App Key,一个 App Key 对应一个账号体系如果不填,则优先使用初始化时SDKOptions中配置的 App Key;如果SDKOptions中未配置,则使用 AndroidManifest 中配置的 App Key。
    customClientType 自定义客户端类型,小于或等于 0 则视为没有自定义类型
    loginExt 登录自定义扩展字段,长度上限为 1k 字符。若在初始化时实现了 loginExtProvider 方法,并且回调该方法时返回了非空的 loginExt 值,则优先取回调返回值,忽略此处输入的 loginExt 值。
    • 使用动态 token 登录(即登录方式 authType 为 1)时,如果注册了动态 token 回调,但返回空值且未传入静态 token(可能第三方服务器设置了动态时间),则直接返回 414 错误码,云信内部不做登录请求。
    • 若注册了回调,回调返回空值,但是登录信息中已传入静态 token,也会返回相关错误码,但是此时,不中断重连,即继续走重连机制(若在初始化设置了自动重连的次数限制,注意该场景下的自动重连次数不计入),等待动态 Token 的传入。
通过第三方回调登录

如采用该登录方式,云信服务端不做 IM 登录鉴权,鉴权工作需由指定的第三方服务器(可以是应用服务器)进行。

  1. 实现该登录方式,需开通和配置第三方服务

  2. 若您的应用需要采用第三方服务器的动态 Token 或者动态 LoginExt 鉴权,那么需要在初始化时实现 SDKOptions#authProviderSDKOptions#loginExtProvider 方法,SDK 会在登录过程时动态通过 Delegate 方法获取第三方回调的动态 Token 和动态扩展字段(loginExt)。

    示例代码如下:

    SDKOptions options = new SDKOptions();
    options.authProvider = new AuthProvider() {
        @Override
        public String getToken(String account) {
            return "your_token";
        }
    };
    
    options.loginExtProvider = new LoginExtProvider() {
    
        @Override
        public String getLoginExt(String account) {
            return "your_login_ext";
        }
    };
    
  3. 调用AuthService#login方法手动登录 IM,调用时authType必须传入 2。调用后,NIM SDK 会自动连接云信服务端,传递用户信息,返回登录结果。登录过程中可主动取消登录。如果因为网络或其他原因导致云信服务端长时间未响应,用户也没有主动取消登录,NIM SDK 将在 45 秒后自动重新连接云信服务端,并返回错误码,错误码详情参见下文的手动登录错误码

    具体参数说明如下:

    LoginInfo 参数
    是否必传 说明
    account 用户的 IM 账号,即accid
    authType 该登录方式必传 登录 IM 的鉴权方式,采用该登录方式时必须传入 2,表示通过第三方回调进行鉴权
    token 静态 token。当 IM 采用第三方回调鉴权方式且在初始化时实现了 SDKOptions#AuthProvider 方法,回调该方法时返回了非空的 token 值,那么优先使用返回的第三方动态 token 进行鉴权;如果回调返回空值,会返回错误码,如果此时已传入静态 token,则取此处的静态 token 进行鉴权如果您的应用启用了云信的聊天室功能,并且采用非独立模式&静态 token 登录方式鉴权时,那么此处必须传入静态 token。传入后,后续非独立模式的聊天室静态登录时会使用该静态 token
    appKey 当前应用的 App Key,一个 App Key 对应一个账号体系如果不填,则优先使用初始化时SDKOptions中配置的 App Key;如果SDKOptions中未配置,则使用 AndroidManifest 中配置的 App Key。
    customClientType 自定义客户端类型,小于或等于 0 则视为没有自定义类型
    loginExt 登录自定义扩展字段,长度上限为 1k 字符。第三方服务器可以使用该字段来鉴权。若在初始化时实现了 SDKOptions#loginExtProvider 方法,并且回调该方法时返回了非空的 loginExt 值,则优先使用返回的第三方动态 loginExt 值进行鉴权,如果回调返回空值,会返回错误码,如果此时已传入静态 loginExt,则取此处手动传入的 loginExt 进行鉴权。
    • 使用第三方回调登录(即登录方式 authType 为 2)时,如果注册了第三方动态 token 和 loginExt 回调,但都返回空值且未传入静态 token 和 loginExt(可能第三方服务器设置了动态时间),则直接返回 414 错误码,云信内部不做登录请求。
    • 若注册了回调,回调返回空值,但是登录信息中已传入静态鉴权字段,也会返回相关错误码,但是此时,不中断重连,即继续走重连机制(若在初始化设置了自动重连的次数限制,注意该场景下的自动重连次数不计入),等待第三方动态 Token 或 loginExt 的传入。
  4. 发起登录相关回调的请求,由第三方服务器进行鉴权并判定 IM 登录事件是否放行通过。

    若不通过,云信服务端将返回 302 错误码。

方式2:自动登录

自动登录一般用于应用被清理后,用户再次点击应用图标启动应用时,无需输入用户名和密码即可完成登录的场景。此时应用可以在无网络、未登录成功的状态下直接访问用户本地 SDK 数据。自动登录与手动登录在客户端侧和服务端逻辑上的区别,参见文末的常见问题

实现自动登录的方式为,在调用初始化的几个方法时,传入LoginInfo

推荐参考自动登录最佳实践登录状态处理最佳实践实现自动登录以及相应的登录状态处理逻辑。


示例代码如下(仅以调用NIMClient#init方法为例):

public class NimApplication extends Application {

	public void onCreate() {
		// ... your codes

		NIMClient.init(this, loginInfo(), options());

		// ... your codes
	}

	private LoginInfo loginInfo() {
	    // 从本地读取上次登录成功时保存的用户登录信息
        String account = Preferences.getUserAccount();
        String token = Preferences.getUserToken();

        if (!TextUtils.isEmpty(account) && !TextUtils.isEmpty(token)) {
            DemoCache.setAccount(account.toLowerCase());
            return new LoginInfo(account, token);
        } else {
            return null;
        }
    }
}

步骤4(可选):主动查询登录状态

SDK支持通过NIMClient#getStatus 方法主动查询当前账号是否处于在线状态。

返回当前用户的登录的状态枚举值说明,请参见下文的登录状态转换流程

示例代码:

if (NIMClient.getStatus() == StatusCode.LOGINED) {
    ……;
}

相关信息

手动登录错误码

手动登录的错误码通过onFailed回调返回,具体如下:

错误码 说明
302 App Key、accidtoken三者不对应
408 连接超时
415 网络断开或者连接云信服务端失败
416 调用频次过高
1000 本地数据库未打开。请在手动登录成功后打开本地数据库

断网重连机制

SDK 提供了自动重连机制(自动重新建立与云信服务端的连接并重新登录),所有重连的登录状态变更都会在observeOnlineStatus方法中回调。

SDK 在两种场景下会自动进行重连:

  • 手动/自动登录成功后,网络不佳导致连接断开的情况。
  • 网络不佳时,账号密码本身正常(未被封禁,且账号密码均正确),启动应用时调用自动登录接口的情况。

满足上述中一个条件,当用户遇到普通网络问题如连接超时等,会自动进行重连登录,不需要上层开发者去做额外的重登逻辑

多端登录与互踢

当前 NIM SDK 支持配置四种不同的 IM 多端登录与互踢策略,具体参见多端登录与互踢

离线查看数据

对于一些弱 IM 场景,需要在登录成功前或者未登录状态下访问指定账号的数据(聊天记录、好友资料等)。

SDK 提供两种方案:

  • 使用自动登录。在登录成功前,可以访问 SDK 服务来读取本地数据(但不能发送数据)。

  • 在手动登录成功前(可能由于网络问题,登录时间较长),调用AuthService#openLocalCache方法在离线时打开本地数据。这是一个同步方法,打开后即可读取 SDK 数据库中的记录。可以通过注销来切换账号查看本地数据。

登录状态转换流程

登录状态(StatusCode)
说明
INVALID 未定义
UNLOGIN 未登录/登录失败。登录成功之后,如果触发了 UNLOGIN 回调,不需要尝试重新手动登录,SDK 内部有自动重连逻辑
NET_BROKEN 网络连接已断开
CONNECTING 正在连接云信服务端
LOGINING 正在登录中
SYNCING 正在同步数据,登录成功后开始同步
LOGINED 已成功登录
KICKOUT 被其他端的登录踢下线,此时应该跳转至手动登录界面。具体机制参见多端登录与互踢策略。被踢后,无法自动登录
KICK_BY_OTHER_CLIENT 被同时在线的其他端主动踢下线(通过kickOtherClient方法),此时应该跳转至手动登录界面。被踢后,无法自动登录
FORBIDDEN 被服务器禁止登录(云信 IM 账号被禁用)。被禁止登录后,无法自动登录
VER_ERROR SDK 版本错误。出现该登录异常后,无法自动登录
PWD_ERROR 云信 IM 账号(accid)或 Token 错误。出现该登录异常后,无法自动登录
DATA_UPGRADE 数据库需要迁移到加密状态(类似被踢出、云信 IM 账号被禁用、Token 错误等情况。如自动登录失败,需要返回到登录界面进行重新登录操作)

常见问题

手动登录和自动登录的主要区别是什么?

手动登录和自动登录主要在于:

差异点
说明
NIM SDK 是否接管登录失败后的处理
  • 手动登录:NIM SDK 认为手动登录即是终端用户发起登录的流程,因此在登录失败后(如网络情况不佳、密码错误),NIM SDK 会触发相应回调,并停止重连操作,等待用户再次发起登录操作
  • 自动登录:自动登录失败后仍旧尝试重连,直到登录成功为止(密码错误等情况除外)
云信服务端是否验证当前登录设备的安全性
  • 手动登录:不验证
  • 自动登录:自动登录时,如果当前登录设备不是上一次登录设备,云信服务端会自动禁止其登录,以保证安全性。

如您选择自动登录,当您的应用在后台被唤起时,会计算为1次登录行为,计入日活统计作为计费依据。

断线后是否会自动重连?

一旦登录成功后(或者调用过自动登录),NIM SDK 将接管所有的重连情况:在网络正常的情况下不停重试重连直到正常登录为止,并不需要做额外的登录操作(聊天室同理)。

如何根据产品形态选择 IM 登录方式?

接入网易云信 IM 服务的产品大致分为两种形态:

  • IM 产品:通讯作为其核心模块。典型例子如微信、易信、网络直播相关应用。
  • 非 IM 产品:通讯只是其附带模块,典型例子如各种有私信模块的应用。

对于 IM 产品,由于通讯能力是核心能力,如果云信无法登录成功则整个应用将无法正常表现,所以推荐在执行业务逻辑前,首先完成应用服务端和云信服务端的登录。只有应用服务端和云信服务端都登录成功才认为整个登录完成。而对于非 IM 产品而言,通讯能力是可以在登录应用服务端成功后延迟加载,登录成功拿到服务端下发的云信 IM 账号和 token 后进行自动登录即可。

如何获取云信服务端当前时间?

可调用MiscService#getServerTime方法获取云信服务端当前的时间戳。该方法的调用有频控限制。如果处于频控限制内,返回的时间为上一次获取时间 + 两次时间的偏移量。

如何处理登录请求被拒绝问题?

若您开启了应用标识安全验证,需要在将列表中写入允许的客户端应用标识。当请求登录的客户端应用标识不在列表中时,登录请求将被拒绝。

在控制台首页应用管理选择应用进入应用配置页面,顶部选择标识管理页签,添加对应的客户端应用标识。

应用标识管理.png

此文档是否对你有帮助?
有帮助
去反馈
  • 技术原理
  • 前提条件
  • 实现登录 IM
  • 步骤1:准备 Token
  • 获取静态Token
  • 获取动态Token
  • 获取动态LoginExt
  • 步骤2:监听登录相关回调
  • 监听登录状态
  • 监听数据同步状态
  • 监听数据准备完成回调
  • 步骤3:登录 IM
  • 登录方式概览
  • 方式1:手动登录
  • 静态 Token 登录
  • 动态 Token 登录
  • 通过第三方回调登录
  • 方式2:自动登录
  • 步骤4(可选):主动查询登录状态
  • 相关信息
  • 手动登录错误码
  • 断网重连机制
  • 多端登录与互踢
  • 离线查看数据
  • 登录状态转换流程
  • 常见问题
  • 手动登录和自动登录的主要区别是什么?
  • 断线后是否会自动重连?
  • 如何根据产品形态选择 IM 登录方式?
  • 如何获取云信服务端当前时间?
  • 如何处理登录请求被拒绝问题?