Android 常见问题
SDK 如何初始化
- 在你的 application 类中 onCreate() 方法中调用初始化方法
/**
* 初始化 SDK,在整个应用程序全局,只需要调用一次。
*
* @param appKey 应用的app key.
* @param context 应用上下文。
*/
public static void init(Context context, String appKey)
- 注意:SDK 在初始化成功后,会有至少两个进程:主进程,ipc;在不支持系统推送的机型上,还会有 push 进程。
SDK 初始化失败、应用启动不成功
- 在特定机型上出现此问题,一般是因为 64k 问题,应用程序引用库太多,放法数超过 65536,解决方法 https://support.rongcloud.cn/ks/NTM5
缓存和刷新 token
-
从 App Server 获取到 token 后,客户端应该做 token 的缓存(存储在 sharepreference 中)
-
token 的有效期是开发者后台设置的,可以永久有效,也可以定期失效
-
当链接时,connect() 方法回调 onTokenIncorrect() 时,应从 App Server 上重新获取 token 并缓存,使用新获取的 token 再次链接
SDK 如何连接
- 调用 SDK 的设置网络状态监听方法,之后所有的链接状态变化都会通过此方法回调通知
/**
* 设置连接状态变化的监听器。
*
* @param listener 连接状态变化的监听器。
*/
public static void setConnectionStatusListener(final RongIMClient.ConnectionStatusListener listener)
- 在你的登录界面类中调用连接方法
/**
* <p>连接服务器,在整个应用程序全局,只需要调用一次,需在 {@link #init(Context)} 之后调用。</p>
* <p>如果调用此接口遇到连接失败,SDK 会自动启动重连机制进行最多10次重连,分别是1, 2, 4, 8, 16, 32, 64, 128, 256, 512秒后。
* 在这之后如果仍没有连接成功,还会在当检测到设备网络状态变化时再次进行重连。</p>
*
* @param token 从服务端获取的用户身份令牌(Token)。
* @param callback 连接回调。
* @return RongIMClient IM 客户端核心类的实例。
*/
public static RongIMClient connect(final String token, final ConnectCallback callback)
连接成功后收不到消息如何解决
-
可以使用此链接检查:https://rongcloud.github.io/websdk-demo/connect-check.html
-
使用上述连接成功后,此账户收到的消息都会打印到页面中
如何动态获取 token
-
动态获取 token 需要在 APP server 端获取
-
参考文档:http://www.rongcloud.cn/docs/server.html#user_get_token
token 失效问题
-
token错误,请您检查客户端初始化使用的AppKey和您服务器获取token使用的AppKey是否一致
-
token过期,是因为您在开发者后台设置了token过期时间,您需要请求您的服务器重新获取token并再次用新的token建立连接。
-
请确认一下 AppKey 和 token 是否匹配。
-
请在开发者后台确认 token 是否在有效期。
-
请使用工具:https://rongcloud.github.io/websdk-demo/api-test.html 来测试一下能否链接成功。
自定义的消息接收不到如何解决
-
首先按照文档:http://www.rongcloud.cn/docs/android.html#message_customize实现自定义消息
-
需要注意的是:消息在 ipc 和主进程间需要跨进程,涉及到序列化问题,需要严格控制和检查 json 中是否有 null 字段问题
获取不到消息中携带的用户信息
-
首先检查数据库中 rct_message 表中,相应的消息中是否有用户信息:如果没有,可以就是发送端没有设置成功用户信息
-
数据库位置:需要 root 手机或者模拟器
老版本:/data/data/app包名/files/appkey/userId/storage
新版本:包含三个文件,/data/data/app包名/files/appkey/userId/ 目录下的 “storage”、“storage-shm”、“storage-wal”。将这三个文件拷贝到统一路径下,打开 storage 文件。
-
如果数据库消息表中包含用户信息,需要检查用户信息是否完整:比如 userId 是否正确
如何在会话列表、会话界面展示群组头像,个人头像
-
在你的 application 类中设置用户、群组信息提供者,当 SDK 需要展示头像时,会回调提供者的回调方法
-
如果是异步获取信息,你可以先在回调方法中先返回 null,再取到信息后,调用如下方法再次刷新:
/**
* 刷新用户缓存数据。
*
* @param userInfo 需要更新的用户缓存数据。
*/
public void refreshUserInfoCache(UserInfo userInfo)
/**
* 刷新群组缓存数据。
*
* @param group 需要更新的群组缓存数据。
*/
public void refreshGroupInfoCache(Group group)
-
头像、名字信息第一次加载成功后,SDK 会做数据库存储。SDK 在展示头像、名字信息时如果能从数据库中取出,就不会再回调信息提供者
-
所以,如果信息变更,需要你重新调用刷新接口,做强制刷新
IMKit 和 IMLib 发送消息接口有什么区别
- kit 中的发消息接口在发送消息时,会同时将消息展示在界面上
如何解决 libsqlite.so 文件找不到的异常
问题表现:SDK 的 ipc 进程启动不起来,连接不成功
-
方法一:在 build.gradle 中把 targetSdkVersion 改小于24
-
方法二: 如果配置了
build.gradle
中的sourceSets
,请检查配置是否正确:sourceSets
正确的配置如下:sourceSets { main { jniLibs.srcDirs = ['libs'] } }
-
通过Android Studio的Analyze APK功能[Build → Analyze APK…], 或直接解开apk包,查看是apk的lib目录下是否已包含libsqlite.so文件 https://support.rongcloud.cn/ks/NzIw
点击通知栏后,如何跳转到会话、会话列表界面
-
跳转原理是通过 manifest 中的 intent-filter 配置实现的:http://www.rongcloud.cn/docs/android.html#other_intent-filter
-
在被跳转的界面中判断是否是来自 push 的消息,如果是,需要做 connect()连接,(注意:此方法和 SDK 自动重连不冲突)
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
...
Intent intent = getIntent();
Uri data = intent != null ? intent.getData() : null;
String pushParam = data != null ? data.getQueryParameter("isFromPush") : null;
isPush = pushParam != null && pushParam.equals("true");
boolean isBackgroundNotify = pushParam != null && pushParam.equals("false");
//push 通知
if (isPush
//应用被杀死,后台通知依然存在
|| (isBackgroundNotify && RongIMClient.getCurrentConnectionStatus().equals(RongIMClient.ConnectionStatusListener.ConnectionStatus.DISCONNECTED))
//界面被回收恢复
|| (savedInstanceState != null && !RongIMClient.getCurrentConnectionStatus().equals(RongIMClient.ConnectionStatusListener.ConnectionStatus.CONNECTED))) {
RongIM.connect(token, callback);
}
...
}
历史消息、历史消息云存储、消息补偿的解释
- 历史消息:SDK 会对消息做本地存储,在会话中显示的都是本地存储的消息
/**
* <p>
* 获取指定类型,targetId 的N条历史消息记录。通过此接口可以根据情况分段加载历史消息,节省网络资源,提高用户体验。
* 该接口不支持拉取聊天室 {io.rong.imlib.model.Conversation.ConversationType#CHATROOM} 历史消息。
* </p>
*
* @param conversationType 会话类型。
* @param targetId 目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
* @param oldestMessageId 最后一条消息的 Id,获取此消息之前的 count 条消息,没有消息第一次调用应设置为:-1。
* @param count 要获取的消息数量。
* @param callback 获取历史消息记录的回调,按照时间顺序从新到旧排列。
*/
public void getHistoryMessages(final Conversation.ConversationType conversationType, final String targetId, final int oldestMessageId, final int count, final ResultCallback<List<Message>> callback)
- 历史消息云存储:
-
当本地数据库的消息展示完成以后,如果你开通了历史消息云存储的服务,在会话中下拉,会继续加载消息,这部分消息就是从服务器端拉取的历史消息;
-
清空会话中的历史消息,仅仅清除的是本地存储的历史消息,如果你开通了历史消息云存储服务,在会话中下拉,依然能拉取历史消息,这部分消息就是从服务器端拉取的历史消息;
/**
* <p>获取融云服务器中暂存,特定类型,targetId 的N条(一次不超过40条)历史消息记录。通过此接口可以根据情况分段加载历史消息,节省网络资源,提高用户体验。</p>
* <p>区别于 {@link #getHistoryMessages},该接口是从融云服务器中拉取。通常用于更换新设备后,拉取历史消息。
* 公众服务会话 {@link io.rong.imlib.model.Conversation.ConversationType#APP_PUBLIC_SERVICE}
* {@link io.rong.imlib.model.Conversation.ConversationType#PUBLIC_SERVICE} </p>
*
* @param conversationType 会话类型。
* @param targetId 目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
* @param dateTime 从该时间点开始获取消息。即:消息中的 sentTime;第一次可传 0,获取最新 count 条。
* @param count 要获取的消息数量,最多 40 条。
* @param callback 获取历史消息记录的回调,按照时间顺序从新到旧排列。
*/
public void getRemoteHistoryMessages(final Conversation.ConversationType conversationType, final String targetId, final long dateTime, final int count, final ResultCallback<List<Message>> callback)
- 消息补偿:是一项收费服务器,体现在多端登录的时候消息同步。消息补偿可以设置时间:3天或7天;当客户端第一次(仅仅是第一次)安装登录,就会把这段时间内的所有消息下发下来
+号扩展区域
如何自定义+号扩展区域
- 设置 App 级别的扩展区域,通过这个方法设置后,每个会话界面展示的都是一样的:http://support.rongcloud.cn/kb/NTU1
如何动态自定义会话中的+号扩展区域
- 继承 ConversationFragment 然后根据布局中的 id 获取到 Extension 对象
public class ChatFragment extends ConversationFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
containerView = (RelativeLayout) super.onCreateView(inflater, container, savedInstanceState);
extension = (RongExtension) containerView.findViewById(io.rong.imkit.R.id.rc_extension);
return containerView;
}
}
- 根据当前页面的 ConversationType 和 TargetId,调用 Extension 中的对应方法:
/**
* 动态在 plugin 区域的末尾增加一个 plugin 。
*
* @param pluginModule 增加的 plugin
*/
public void addPlugin(IPluginModule pluginModule)
/**
* 移除指定的 plugin
*
* @param pluginModule 指定 plugin
*/
public void removePlugin(IPluginModule pluginModule)
/**
* 获取当前所有 Plugin 列表
*
* @return 已加载的 plugin 列表
*/
public List<IPluginModule> getPluginModules()