1、BmobOldIM SDK 回顾

Android BmobIM SDK v2.0.0之前的版本统称为BmobOldIM SDK ,BmobOldIM SDK已经开源但不再进行维护,请开发者集成Android BmobNewIM SDK进行开发。

BmobOldIM SDK 问题
无法自定义消息类型
消息发送受限于BmobPushSDK
API设计不够合理规范且不易扩展
聊天消息出现接收延迟或丢失

2、BmobNewIM SDK 介绍

Android BmobIM SDK v2.0.0开始的版本统称为BmobNewIM SDK,BmobNewIM SDK采用全新架构,设计更加合理规范,API更加简单易用,扩展性强,但不兼容 Android BmobOldIM SDK。

2.1、Android BmobNewIM SDK 特点及其描述

Android BmobNewIM SDK 特点 描述
与用户系统解耦 终端用户聊天的唯一标识是objectId,不再受限于Bmob的用户系统
支持多账号登录、跨平台 支持单个设备多个账号登录,支持与iOS互通聊天
支持多种格式的富媒体消息 支持文本、图片、音频和地理位置等多种格式的富媒体消息
允许开发者自定义消息 支持开发者自定义消息类型,方便开发者扩展本业务逻辑
API设计更加合理规范 全新的架构设计,API更加简单易用,较BmobOldIM SDK 进一步降低开发者使用成本

2.2、自IM SDK v2.0.5版本开始提供aar格式远程发布包,可以自动集成并结合Data SDK进行开发

IM SDK aar格式所包含文件 Data SDK 版本
BmobNewIM(版本号)(发布日期).jar BmobNewIM的核心SDK
androidasync_2.1.6.jar 用于协议通讯

2.3、IM SDK和Data SDK的版本对应关系

IM SDK 使用Data SDK的BmobFile用于图片、语音等文件消息的发送,因此必须导入特定版本的BmobSDK。

IM SDK 版本 Data SDK 版本
bmob-im:1.1.8 bmob-sdk:3.3.5
bmob-im:1.1.9 bmob-sdk:3.4.3
bmob-im:2.0.1 bmob-sdk:3.4.6-0304
bmob-im:2.0.2 bmob-sdk:3.4.6-0304
bmob-im:2.0.3 bmob-sdk:3.4.6
bmob-im:2.0.4 bmob-sdk:3.4.6
bmob-im:2.0.5 bmob-sdk:3.4.7-aar
bmob-im:2.0.6 bmob-sdk:3.5.5

3、BmobNewIM SDK 集成

3.1、手动集成

3.1.1、下载Android BmobNewIM SDK开发包及其Demo

下载平台 下载地址
Bmob基于BmobNewIM SDK v2.0.6 的Demo bmob-newim-demo
Github基于BmobNewIM SDK v2.0.5 的Demo bmob-newim-demo
Github基于BmobNewIM SDK v2.0.6 的Demo bmob-newim-demo

3.1.2、解压Android BmobNewIM SDK开发包

文件 使用
libs 外部依赖库,拷贝于工程的libs文件夹;自Data SDK v3.4.7开始,加入libbmob.so文件;自Data SDK v3.5.2开始,加入libBmobStat.so文件。
NewIM_V2.x.x_Demo 开发示例,开发环境是Android Studio,功能是陌生人以及好友聊天

3.1.3、在app下的build.gradle文件中设置jni依赖库的目录,设置后点击Sync Now同步配置

  1. android {
  2. sourceSets {
  3. main.jniLibs.srcDirs = ['libs']
  4. }
  5. }

3.2、自动集成

3.2.1、在Project下的build.gradle文件中添加Bmob的maven仓库地址

  1. buildscript {
  2. repositories {
  3. jcenter()
  4. }
  5. dependencies {
  6. classpath 'com.android.tools.build:gradle:1.3.0'
  7. }
  8. }
  9. allprojects {
  10. repositories {
  11. jcenter()
  12. //Bmob的maven仓库地址,必须填写
  13. maven { url "https://raw.github.com/bmob/bmob-android-sdk/master" }
  14. }
  15. }
  16. task clean(type: Delete) {
  17. delete rootProject.buildDir
  18. }

3.2.2、在app下的build.gradle文件中添加dependencies外部依赖库,添加后点击Sync Now同步配置

  1. dependencies {
  2. compile fileTree(dir: 'libs', include: ['*.jar'])
  3. //bmob-im:特定版本的bmob-im依赖特定版本的bmob-sdk
  4. compile 'cn.bmob.android:bmob-im:2.0.6@aar'
  5. compile 'cn.bmob.android:bmob-sdk:3.5.5'
  6. }

3.3、配置AndroidManifest.xml

3.3.1、 添加Bmob_APP_KEY

  1. <meta-data
  2. android:name="Bmob_APP_KEY"
  3. android:value="Bmob平台的Application ID" />

3.3.2、 添加权限

请注意在Android 6.0版本开始某些权限需要动态获取,详情请看Android Developwers官方文档,android-6.0-changesandroid-7.0-changes

  1. <!--网络权限 -->
  2. <uses-permission android:name="android.permission.INTERNET" />
  3. <!-- 监听网络的变化 -->
  4. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  5. <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
  6. <!-- 设备休眠 -->
  7. <uses-permission android:name="android.permission.WAKE_LOCK" />
  8. <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  9. <!-- sd卡存储-->
  10. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  11. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  12. <!--摄像头-->
  13. <uses-permission android:name="android.permission.CAMERA" />
  14. <!--录音-->
  15. <uses-permission android:name="android.permission.RECORD_AUDIO" />
  16. <!--通知震动-->
  17. <uses-permission android:name="android.permission.VIBRATE" />

3.3.3、 添加service、receiver标签:

  1. <receiver android:name="cn.bmob.newim.core.ConnectChangeReceiver" >
  2. <intent-filter>
  3. <action android:name="cn.bmob.action.RECONNECT" />
  4. <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
  5. <action android:name="android.intent.action.BOOT_COMPLETED" />
  6. <action android:name="android.intent.action.USER_PRESENT" />
  7. </intent-filter>
  8. </receiver>
  9. <service
  10. android:name="cn.bmob.newim.core.service.BmobIMService"
  11. android:process=":bmobcore" />
  12. <service
  13. android:name="cn.bmob.newim.core.service.NotifyService"
  14. android:process=":bmobcore" />
  15. <service android:name="cn.bmob.newim.core.service.ReConnectService" />
  16. <service android:name="cn.bmob.newim.core.service.HeartBeatService" />

注:自v2.0.5版本开始,将原来的BmobImService名称更换为BmobIMService,请务必修改,否则将无法正常使用IM服务。

3.4、代码配置

3.4.1、注册消息接收器

3.4.1.1、如果你使用的是NewIM_V2.0.2及以后的版本

1、请自定义消息接收器继承自BmobIMMessageHandler来处理服务器发来的消息和离线消息。

  1. public class DemoMessageHandler extends BmobIMMessageHandler{
  2. @Override
  3. public void onMessageReceive(final MessageEvent event) {
  4. //当接收到服务器发来的消息时,此方法被调用
  5. }
  6. @Override
  7. public void onOfflineReceive(final OfflineMessageEvent event) {
  8. //每次调用connect方法时会查询一次离线消息,如果有,此方法会被调用
  9. }
  10. }

2、在Application的onCreate方法中注册这个DemoMessageHandler

  1. public class BmobIMApplication extends Application{
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. //NewIM初始化
  6. BmobIM.init(this);
  7. //注册消息接收器
  8. BmobIM.registerDefaultMessageHandler(new DemoMessageHandler(this));
  9. }
  10. }
3.4.1.2、如果你使用的SDK版本是NewIM_V2.0.1

1、请创建一个广播消息接收器,用于接收服务器发来的消息。

  1. public class MessageReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(final Context context, Intent intent) {
  4. if(intent!=null){
  5. final MessageEvent event =(MessageEvent)intent.getSerializableExtra("event");
  6. //开发者可以在这里发应用通知
  7. }
  8. }

2、在AndroidManifest.xml中注册此receiver。

  1. <receiver
  2. android:name="程序包名.MessageReceiver"
  3. android:enabled="true">
  4. <intent-filter>
  5. <action android:name="cn.bmob.im.action.MESSAGE"/>
  6. </intent-filter>
  7. </receiver>

3.4.2、初始化BmobNewIM SDK

在Application的onCreate方法中调用BmobIM.init(context)

  1. public class BmobIMApplication extends Application{
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. //只有主进程运行的时候才需要初始化
  6. if (getApplicationInfo().packageName.equals(getMyProcessName())){
  7. //im初始化
  8. BmobIM.init(this);
  9. //注册消息接收器
  10. BmobIM.registerDefaultMessageHandler(new DemoMessageHandler(this));
  11. }
  12. }
  13. /**
  14. * 获取当前运行的进程名
  15. * @return
  16. */
  17. public static String getMyProcessName() {
  18. try {
  19. File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
  20. BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
  21. String processName = mBufferedReader.readLine().trim();
  22. mBufferedReader.close();
  23. return processName;
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. return null;
  27. }
  28. }
  29. }

注:

  1. 初始化方法包含了BmobSDK的初始化步骤,故无需再初始化BmobSDK。
  2. 在初始化的时候,最好做下判断:只有主进程运行的时候才开始初始化,避免资源浪费。

4、BmobNewIM SDK 使用

4.1、服务器连接

4.1.1、连接

调用connect方法,需要传入唯一用户标示clientId,Demo使用的是Bmob的用户登录系统objectId

  1. User user = BmobUser.getCurrentUser(context,User.class);
  2. BmobIM.connect(user.getObjectId(), new ConnectListener() {
  3. @Override
  4. public void done(String uid, BmobException e) {
  5. if (e == null) {
  6. Logger.i("connect success");
  7. } else {
  8. Logger.e(e.getErrorCode() + "/" + e.getMessage());
  9. }
  10. }
  11. });

4.1.2、断开连接:

调用disConnect方法,客户端会断开与服务器之间的连接,再次聊天需要重新调用connect方法完成与服务器之间的连接。

  1. BmobIM.getInstance().disConnect();

4.1.3、监听服务器连接状态

调用setOnConnectStatusChangeListener方法即可监听到当前长链接的连接状态。

  1. BmobIM.getInstance().setOnConnectStatusChangeListener(new ConnectStatusChangeListener() {
  2. @Override
  3. public void onChange(ConnectionStatus status) {
  4. Logger.i("" + status.getMsg());
  5. }
  6. });

4.2、会话

4.2.1、创建会话

BmobNewIM SDK 采用会话(BmobIMConversation)管理消息(BmobIMMessage)的方式,即消息的查询、发送和删除等操作均在指定会话下进行,因此需要获取指定会话信息并创建会话实例。目前创建会话有两种创建方式,分别是暂态会话常态会话

4.2.1.1、暂态消息

BmobNewIM SDK在BmobIMMessage类中新增isTransient属性来标识该条消息是否自动保存到聊天对象的本地DB中。

  • 设置为true,表明为暂态消息,那么这条消息并不会保存到聊天对象的本地db中,SDK只负责发送和接收。
  • 设置为false,表明不为暂态消息,SDK会自动保存该类型的消息到指定会话的数据库中。
4.2.1.2、创建暂态会话

该会话只提供消息发送功能,不可使用其他查询,删除等API,不会自动创建会话到本地DB中。一般用于自定义消息的发送,比如,添加好友的请求,在对方还没有同意的情况下,你并不希望在自己的会话列表中显示该会话。v2.0.4版本的NewIM开始提供此种方式创建暂态会话

  1. //开启私聊会话,isTransient可设置是否保存该会话到自己的本地会话表中
  2. startPrivateConversation(BmobIMUserInfo info, boolean isTransient,ConversationListener listener)
4.2.1.3、创建常态会话

该会话提供消息查询、发送、删除等功能,SDK内部自动创建该会话。

  1. //开启私聊会话,默认会保存该会话到自己的本地会话表中
  2. startPrivateConversation(BmobIMUserInfo info, ConversationListener listener)
4.2.1.3、创建会话示例

BmobIMUserInfo类,是用户信息类,有三个属性需要开发者关注下:userId(用户唯一id),name(用户名),avatar(用户头像)。

  1. //如果需要更新用户资料,开发者只需要传新的info进去就可以
  2. BmobIM.getInstance().startPrivateConversation(BmobIMUserInfo info, new ConversationListener() {
  3. @Override
  4. public void done(BmobIMConversation c, BmobException e) {
  5. if(e==null){
  6. //在此跳转到聊天页面
  7. Bundle bundle = new Bundle();
  8. bundle.putSerializable("c", c);
  9. startActivity(ChatActivity.class, bundle, false);
  10. }else{
  11. toast(e.getMessage()+"("+e.getErrorCode()+")");
  12. }
  13. }
  14. });

4.2.2、查询全部会话

  1. BmobIM.getInstance().loadAllConversation()

4.2.3、查询会话的未读消息数量

4.2.3.1、查询指定会话下的未读消息数量
  1. BmobIM.getInstance().getUnReadCount(String conversationId)
4.2.3.2、查询全部会话的全部未读消息数
  1. BmobIM.getInstance().getUnReadCount.getAllUnReadCount()

4.2.4、删除指定会话

  1. //提供两种方式删除会话
  2. BmobIM.getInstance().deleteConversation(BmobIMConversation c);
  3. BmobIM.getInstance().deleteConversation(String conversationId);

4.2.5、清空全部会话

  1. BmobIM.getInstance().clearAllConversation();

4.2.6、更新会话标题、会话图标及用户信息

由于BmobNewIM SDK并不包含与用户有关的逻辑,只负责存储用户信息并对外提供更新等方法,用来操作本地的用户信息。

在与人单聊时,需要更新会话标题和会话图标及用户信息,可调用如下方法在DemoMessageHandler的全局消息接收器中进行统一更新。

  1. /**更新用户资料和会话资料
  2. * @param event
  3. * @param listener
  4. */
  5. public void updateUserInfo(MessageEvent event,final UpdateCacheListener listener){
  6. final BmobIMConversation conversation=event.getConversation();
  7. final BmobIMUserInfo info =event.getFromUserInfo();
  8. final BmobIMMessage msg =event.getMessage();
  9. String username =info.getName();
  10. String title =conversation.getConversationTitle();
  11. //sdk内部,将新会话的会话标题用objectId表示,因此需要比对用户名和会话标题--单聊,后续会根据会话类型进行判断
  12. if(!username.equals(title)) {
  13. UserModel.getInstance().queryUserInfo(info.getUserId(), new QueryUserListener() {
  14. @Override
  15. public void done(User s, BmobException e) {
  16. if(e==null){
  17. String name =s.getUsername();
  18. String avatar = s.getAvatar();
  19. conversation.setConversationIcon(avatar);
  20. conversation.setConversationTitle(name);
  21. info.setName(name);
  22. info.setAvatar(avatar);
  23. //更新用户资料
  24. BmobIM.getInstance().updateUserInfo(info);
  25. //更新会话资料-如果消息是暂态消息,则不更新会话资料
  26. if(!msg.isTransient()){
  27. BmobIM.getInstance().updateConversation(conversation);
  28. }
  29. }else{
  30. Logger.e(e);
  31. }
  32. listener.done(null);
  33. }
  34. });
  35. }else{
  36. listener.internalDone(null);
  37. }
  38. }

4.3、消息

消息(BmobIMMessage)是所有消息的基类,以下BmobNewIM SDK目前支持的消息类型。

消息类型 消息类名
文本 BmobIMTextMessage
文件 BmobIMFileMessage
图像 BmobIMImageMessage
音频 BmobIMAudioMessage
视频 BmobIMVideoMessage
地理位置 BmobIMLocationMessage

4.3.1、获取指定会话信息并创建会话实例

BmobNewIM SDK采用会话(BmobIMConversation)管理消息(BmobIMMessage)的方式,即消息的查询、发送和删除等操作均在指定会话下进行,因此需要通过以下两个步骤来获取指定会话信息并创建会话实例。

1、 开启私聊

  1. //如果需要更新用户资料,开发者只需要传新的info进去就可以
  2. BmobIM.getInstance().startPrivateConversation(BmobImUserInfo info, new ConversationListener() {
  3. @Override
  4. public void done(BmobIMConversation c, BmobException e) {
  5. if(e==null){
  6. //在此跳转到聊天页面
  7. Bundle bundle = new Bundle();
  8. bundle.putSerializable("c", c);
  9. startActivity(ChatActivity.class, bundle, false);
  10. }else{
  11. toast(e.getMessage()+"("+e.getErrorCode()+")");
  12. }
  13. }
  14. });

2、 创建会话实例

使用BmobIMConversation.obtain(BmobIMClient client,BmobIMConversation conversation)方法传入BmobIMClient和BmobIMConversation的各自实例就可以创建一个用于控制消息查询、发送和删除的会话实例。

  1. BmobIMConversation c;
  2. //在聊天页面的onCreate方法中,通过如下方法创建新的会话实例,这个obtain方法才是真正创建一个管理消息发送的会话
  3. c=BmobIMConversation.obtain(BmobIMClient.getInstance(),(BmobIMConversation)getBundle().getSerializable("c"));

创建完成后,就可以使用这个会话实例c对消息进行各种操作啦,以下操作中的c都指的是该会话实例。

注:
如果不调用BmobIMConversation的obtain方法是无法控制消息发送等操作的,会报client disconnect的错误。

4.3.2、查询指定会话的聊天记录

  1. //首次加载,可设置msg为null,
  2. //下拉刷新的时候,可用消息表的第一个msg作为刷新的起始时间点,默认按照消息时间的降序排列,limit由开发者控制
  3. c.queryMessages(msg, limit, new MessagesQueryListener() {
  4. @Override
  5. public void done(List<BmobIMMessage> list, BmobException e) {
  6. sw_refresh.setRefreshing(false);
  7. if (e == null) {
  8. if (null != list && list.size() > 0) {
  9. adapter.addMessages(list);
  10. adapter.notifyDataSetChanged();
  11. layoutManager.scrollToPositionWithOffset(list.size() - 1, 0);
  12. }
  13. } else {
  14. toast(e.getMessage() + "(" + e.getErrorCode() + ")");
  15. }
  16. }
  17. });

4.3.3、删除指定会话的聊天记录

删除消息不同于删除会话,会直接清空本地的消息记录数据。

  1. //删除指定聊天消息
  2. c.deleteMessage(BmobIMMessage msg)
  3. //删除一条或多条聊天消息
  4. c.deleteBatchMessage(List<BmobIMMessage> msgs)
  5. //清空该会话下的聊天消息,允许保留会话(可选)
  6. c.clearMessage(boolean isKeepConversion,MessageListener listener)
  7. 注:isKeepConversion 表示是否保留该会话消息。

4.3.4、更新指定会话的所有消息为已读状态

可以在ChatActivity的聊天页面的onDestory方法中调用如下方法更新该会话的的所有消息为已读状态

  1. //更新此会话的所有消息为已读状态
  2. c.updateLocalCache();

4.4、消息发送

4.4.1、文本消息

文本消息可以是纯文本,也可以是包含表情的文本消息,通过BmobIMTextMessagesetContent方法设置内容来构建BmobIMTextMessage实例,再调用BmobIMConversationsendMessage方法发送。

  1. BmobIMTextMessage msg =new BmobIMTextMessage();
  2. msg.setContent(text);
  3. //可随意设置额外信息
  4. Map<String,Object> map =new HashMap<>();
  5. map.put("level", "1");
  6. msg.setExtraMap(map);
  7. c.sendMessage(msg, new MessageSendListener() {
  8. @Override
  9. public void onStart(BmobIMMessage msg) {
  10. super.onStart(msg);
  11. scrollToBottom();
  12. adapter.addMessage(msg);
  13. adapter.notifyDataSetChanged();
  14. }
  15. @Override
  16. public void done(BmobIMMessage msg, BmobException e) {
  17. scrollToBottom();
  18. adapter.notifyDataSetChanged();
  19. edit_msg.setText("");
  20. if (e != null) {
  21. toast(e.getMessage());
  22. }
  23. }
  24. });

4.4.2、图片消息

图片可以是通过系统拍照或本地相册中获取的本地图片地址,也可以使用网络上某个有效的图片地址。然后构造一个BmobIMImageMessage对象,再调用BmobIMConversationsendMessage方法发送。

4.4.2.1、发送本地图片

使用系统拍照功能或从本地相册中获取到本地图片地址(localPath),然后调用构造方法BmobIMImageMessage(String localPath)来创建BmobIMImageMessage实例。

  1. BmobIMImageMessage image =new BmobIMImageMessage(localPath);
  2. c.sendMessage(image, new MessageSendListener() {
  3. @Override
  4. public void onProgress(int value) {
  5. super.onProgress(value);
  6. //文件类型的消息才有进度值:do something
  7. Logger.i("onProgress:"+value);
  8. }
  9. @Override
  10. public void onStart(BmobIMMessage msg) {
  11. scrollToBottom();
  12. adapter.addMessage(msg);
  13. adapter.notifyDataSetChanged();
  14. }
  15. @Override
  16. public void done(BmobIMMessage msg, BmobException e) {
  17. scrollToBottom();
  18. adapter.notifyDataSetChanged();
  19. edit_msg.setText("");
  20. if (e != null) {
  21. toast(e.getMessage());
  22. }
  23. }
  24. });
4.4.2.2、发送远程图片URL

例如,从微博或QQ中获取到某个图片地址,然后调用BmobIMImageMessage的setRemoteUrl方法设置远程图片URL来创建BmobIMImageMessage实例。

  1. BmobIMImageMessage image =new BmobIMImageMessage();
  2. image.setRemoteUrl("http://img.lakalaec.com/ad/57ab6dc2-43f2-4087-81e2-b5ab5681642d.jpg");
  3. c.sendMessage(image, new MessageSendListener() {
  4. @Override
  5. public void onProgress(int value) {
  6. super.onProgress(value);
  7. //文件类型的消息才有进度值
  8. Logger.i("onProgress:"+value);
  9. }
  10. @Override
  11. public void onStart(BmobIMMessage msg) {
  12. scrollToBottom();
  13. adapter.addMessage(msg);
  14. adapter.notifyDataSetChanged();
  15. }
  16. @Override
  17. public void done(BmobIMMessage msg, BmobException e) {
  18. scrollToBottom();
  19. adapter.notifyDataSetChanged();
  20. edit_msg.setText("");
  21. if (e != null) {
  22. toast(e.getMessage());
  23. }
  24. }
  25. });

4.4.3、语音消息

语音可以是通过录制音频得到的本地音频地址,也可以使用网络上某个有效的音频地址。然后构造一个BmobIMAudioMessage对象,再调用BmobIMConversationsendMessage方法发送。

4.4.3.1、发送本地音频文件:
  1. BmobIMAudioMessage image =new BmobIMAudioMessage(localPath);
  2. c.sendMessage(image, new MessageSendListener() {
  3. @Override
  4. public void onProgress(int value) {
  5. super.onProgress(value);
  6. //文件类型的消息才有进度值:do something
  7. Logger.i("onProgress:"+value);
  8. }
  9. @Override
  10. public void onStart(BmobIMMessage msg) {
  11. scrollToBottom();
  12. adapter.addMessage(msg);
  13. adapter.notifyDataSetChanged();
  14. }
  15. @Override
  16. public void done(BmobIMMessage msg, BmobException e) {
  17. scrollToBottom();
  18. adapter.notifyDataSetChanged();
  19. edit_msg.setText("");
  20. if (e != null) {
  21. toast(e.getMessage());
  22. }
  23. }
  24. });
4.4.3.2、发送远程语音URL地址

同样的,语音消息也支持发送远程语音URL地址:

  1. BmobIMAudioMessage image =new BmobIMAudioMessage();
  2. image.setRemoteUrl("远程语音地址");
  3. c.sendMessage(image, new MessageSendListener() {
  4. @Override
  5. public void onProgress(int value) {
  6. super.onProgress(value);
  7. //文件类型的消息才有进度值
  8. Logger.i("onProgress:"+value);
  9. }
  10. @Override
  11. public void onStart(BmobIMMessage msg) {
  12. scrollToBottom();
  13. adapter.addMessage(msg);
  14. adapter.notifyDataSetChanged();
  15. }
  16. @Override
  17. public void done(BmobIMMessage msg, BmobException e) {
  18. scrollToBottom();
  19. adapter.notifyDataSetChanged();
  20. edit_msg.setText("");
  21. if (e != null) {
  22. toast(e.getMessage());
  23. }
  24. }
  25. });

4.4.4、地理位置消息

地理位置可以通过任意地图SDK获取到经纬度,详细地址等信息,然后调用BmobIMLocationMessage(String address,double latitude,double longitude)构造方法构建BmobIMLocationMessage实例,再调用BmobIMConversationsendMessage方法发送。:

  1. BmobIMLocationMessage location =new BmobIMLocationMessage("广州番禺区",23.5,112.0);
  2. c.sendMessage(location, new MessageSendListener() {
  3. @Override
  4. public void onStart(BmobIMMessage msg) {
  5. scrollToBottom();
  6. adapter.addMessage(msg);
  7. adapter.notifyDataSetChanged();
  8. }
  9. @Override
  10. public void done(BmobIMMessage msg, BmobException e) {
  11. scrollToBottom();
  12. adapter.notifyDataSetChanged();
  13. edit_msg.setText("");
  14. if (e != null) {
  15. toast(e.getMessage());
  16. }
  17. }
  18. });

4.5、消息接收

4.5.1、自定义消息接收器

4.5.1.1、NewIM_V2.0.4及以后的NewBmobIM SDK版本

如果你使用的是NewIM_V2.0.4以后(包含v2.0.4)的SDK版本,那么不仅可以使用BmobIMMessageHandler方式来注册全局的消息接收器,还可以使用MessageListHandler为单个页面注册消息接收器,具体步骤如下:

  1. Activity/Fragment中实现MessageListHandler接口;
  2. onResume方法中添加页面消息监听器:BmobIM.getInstance().addMessageListHandler(this)
  3. onPause方法中移除页面消息监听器:BmobIM.getInstance().removeMessageListHandler(this)
  4. MessageListHandler接口的onMessageReceive方法中做相关的操作。

具体示例可查看NewIMDemo中的ChatActivity类:

  1. @Override
  2. public void onMessageReceive(List<MessageEvent> list) {
  3. //当注册页面消息监听时候,有消息(包含离线消息)到来时会回调该方法
  4. for (int i=0;i<list.size();i++){
  5. //do something...
  6. }
  7. }
4.5.1.2、NewIM_V2.0.2及以后的NewBmobIM SDK版本

如果你使用的是NewIM_V2.0.2以后(包含v2.0.2)的SDK版本,那么只需要自定义消息接收器继承自BmobIMMessageHandler来处理服务器发来的消息和离线消息。

  1. public class DemoMessageHandler extends BmobIMMessageHandler{
  2. private Context context;
  3. public DemoMessageHandler(Context context) {
  4. this.context = context;
  5. }
  6. @Override
  7. public void onMessageReceive(final MessageEvent event) {
  8. //当接收到服务器发来的消息时,此方法被调用
  9. //可以统一在此检测更新会话及用户信息
  10. UserModel.getInstance().updateUserInfo(event, new UpdateCacheListener() {
  11. @Override
  12. public void done(BmobException e) {
  13. BmobIMMessage msg = event.getMessage();
  14. //用户自定义的消息类型,其类型值均为0
  15. if(BmobIMMessageType.getMessageTypeValue(msg.getMsgType())==0){
  16. //自行处理自定义消息类型
  17. Logger.i(msg.getMsgType() + "," + msg.getContent() + "," + msg.getExtra());
  18. }else{//SDK内部内部支持的消息类型
  19. if (BmobNotificationManager.getInstance(context).isShowNotification()){
  20. //如果需要显示通知栏,可以使用BmobNotificationManager类提供的方法,也可以自己写通知栏显示方法
  21. }else{//直接发送消息事件
  22. Logger.i("当前处于应用内,发送event");
  23. EventBus.getDefault().post(event);
  24. }
  25. }
  26. }
  27. });
  28. }
  29. @Override
  30. public void onOfflineReceive(final OfflineMessageEvent event) {
  31. //每次调用connect方法时会查询一次离线消息,如果有,此方法会被调用
  32. Map<String,List<MessageEvent>> map =event.getEventMap();
  33. Logger.i("离线消息属于"+map.size()+"个用户");
  34. for (Map.Entry<String, List<MessageEvent>> entry : map.entrySet()) {
  35. List<MessageEvent> list =entry.getValue();
  36. //挨个检测离线用户信息是否需要更新
  37. UserModel.getInstance().updateUserInfo(list.get(0), new UpdateCacheListener() {
  38. @Override
  39. public void done(BmobException e) {
  40. EventBus.getDefault().post(event);
  41. }
  42. });
  43. }
  44. }
  45. }

同样,别忘记在Application的onCreate方法中注册这个DemoMessageHandler

  1. public class BmobIMApplication extends Application{
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. //注册消息接收器
  6. BmobIM.registerDefaultMessageHandler(new DemoMessageHandler(this));
  7. }
  8. }
4.5.1.3、NewIM_V2.0.1的NewBmobIM SDK版本

如果你使用的SDK版本是NewIM_V2.0.1,那么你需要在应用中创建一个BroadcastReceiver广播消息接收器,用于接收服务器发来的消息。

  1. public class MessageReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(final Context context, Intent intent) {
  4. if(intent!=null){
  5. final MessageEvent event =(MessageEvent)intent.getSerializableExtra("event");
  6. //可以统一在此检测更新会话及用户信息
  7. UserModel.getInstance().updateUserInfo(event, new UpdateCacheListener() {
  8. @Override
  9. public void done(BmobException e) {
  10. BmobIMMessage msg = event.getMessage();
  11. //用户自定义的消息类型,其类型值均为0
  12. if(BmobIMMessageType.getMessageTypeValue(msg.getMsgType())==0){
  13. //自行处理自定义消息类型
  14. Logger.i(msg.getMsgType() + "," + msg.getContent() + "," + msg.getExtra());
  15. }else{//SDK内部内部支持的消息类型
  16. if (BmobNotificationManager.getInstance(context).isShowNotification()){
  17. //如果需要显示通知栏,可以使用BmobNotificationManager类提供的方法,也可以自己写通知栏显示方法
  18. }else{//直接发送消息事件
  19. Logger.i("当前处于应用内,发送event");
  20. EventBus.getDefault().post(event);
  21. }
  22. }
  23. }
  24. });
  25. }
  26. }

别忘记在AndroidManifest.xml中注册这个receiver

  1. <receiver
  2. android:name="程序包名.MessageReceiver"
  3. android:enabled="true">
  4. <intent-filter>
  5. <action android:name="cn.bmob.im.action.MESSAGE"/>
  6. </intent-filter>
  7. </receiver>

4.5.2、应用内消息接收

V2.0.1的SDK内部集成EventBus库(V2.0.2SDK内部不再集成EventBus,开发者可以自行使用新版EventBus)来进行应用内消息的分发,故在应用内需要接收消息的地方注册和解注册EventBus即可。

SDK内部有两种事件:MessageEvent(聊天消息)OfflineMessageEvent(离线消息)

1、注册EventBus

  1. EventBus.getDefault().register(this);

2、解注册EventBus

  1. EventBus.getDefault().unregister(this);

3、处理聊天消息

  1. /**聊天消息接收事件
  2. * @param event
  3. */
  4. public void onEventMainThread(MessageEvent event){
  5. //处理聊天消息
  6. }

4、处理离线消息

  1. /**离线消息接收事件
  2. * @param event
  3. */
  4. public void onEventMainThread(OfflineMessageEvent event){
  5. //处理离线消息
  6. }

4.5.3、应用外通知栏提醒

SDK新增BmobNotificationManager类,并提供如下两个方法供开发者展示通知栏:

  1. 多个用户的多条消息合并成一条通知:有XX个联系人发来了XX条消息
  1. /**显示通知:多个用户的多条消息合并显示一条通知
  2. * @param event 某个消息事件:包含消息、会话及发送用户的信息
  3. * @param intent 跳转intent
  4. */
  5. BmobNotificationManager.getInstance(context).showNotification(MessageEvent event,Intent pendingIntent);
  1. 自定义通知消息:始终只有一条通知,新消息覆盖旧消息
  1. /**显示通知
  2. * @param largerIcon 通知栏图标 开发者可传应用图标,也可以将聊天头像转成bitmap
  3. * @param title 标题
  4. * @param content 内容
  5. * @param ticker 状态栏上显示的内容
  6. * @param intent 跳转的intent
  7. */
  8. BmobNotificationManager.getInstance(context).showNotification(Bitmap largerIcon,String title, String content, String ticker,Intent intent);

注:为了使SDK能够区分当前应用是否退出,开发者需进行以下几个步骤:

1、在会话和聊天的Activity类实现’ObseverListener’监听器;

2、在onResume方法中调用BmobNotificationManager.getInstance(context).addObserver(this)方法添加观察者;
onPause方法中调用BmobNotificationManager.getInstance(context).removeObserver(this)方法移除观察者

3、在主Activity的onDestroy方法中调用BmobNotificationManager.getInstance(context).clearObserver()清空观察者。

4.6、自定义消息

4.6.1、设置额外信息

有些时候,开发者需要在发送消息时携带一些额外信息,例如发送方的设备类型、图片的拍摄地点或者音频的来源等,那么开发者可以通过 BmobIMExtraMessage.extraMap属性来解决,任何继承BmobIMExtraMessage类的消息均支持设置额外信息。

  1. BmobIMAudioMessage audio =new BmobIMAudioMessage();
  2. image.setRemoteUrl("远程音频地址");
  3. //设置音频文件的来源
  4. Map<String,Object> map =new HashMap<>();
  5. map.put("from", "优酷");
  6. audio.setExtraMap(map);
  7. c.sendMessage(audio, listener);

4.6.2、创建新的消息类型

如果设置额外信息无法满足开发者的需求,那么开发者也可以自定义自己的消息类型。

4.6.2.1、创建自定义消息
  1. 继承自BmobIMExtraMessage类;
  2. 重写getMsgType方法,填写自定义的消息类型;
  3. 重写isTransient方法。
  1. public class AddFriendMessage extends BmobIMExtraMessage{
  2. @Override
  3. public String getMsgType() {
  4. return "add";
  5. }
  6. @Override
  7. public boolean isTransient() {
  8. //设置为true,表明为暂态消息,那么这条消息并不会保存到对方的本地db中
  9. //设置为false,则会保存到对方指定会话的本地数据库中
  10. return true;
  11. }
  12. public AddFriendMessage(){}
  13. }
4.6.2.2、发送自定义消息
  1. //启动一个会话,如果isTransient设置为true,则不会创建在本地会话表中创建该会话,
  2. //设置isTransient设置为false,则会在本地数据库的会话列表中先创建(如果没有)与该用户的会话信息,且将用户信息存储到本地的用户表中
  3. BmobIMConversation c = BmobIM.getInstance().startPrivateConversation(info, true,null);
  4. //这个obtain方法才是真正创建一个管理消息发送的会话
  5. BmobIMConversation conversation = BmobIMConversation.obtain(BmobIMClient.getInstance(), c);
  6. AddFriendMessage msg =new AddFriendMessage();
  7. User currentUser = BmobUser.getCurrentUser(this,User.class);
  8. msg.setContent("很高兴认识你,可以加个好友吗?");//给对方的一个留言信息
  9. Map<String,Object> map =new HashMap<>();
  10. map.put("name", currentUser.getUsername());//发送者姓名,这里只是举个例子,其实可以不需要传发送者的信息过去
  11. map.put("avatar",currentUser.getAvatar());//发送者的头像
  12. map.put("uid",currentUser.getObjectId());//发送者的uid
  13. msg.setExtraMap(map);
  14. conversation.sendMessage(msg, new MessageSendListener() {
  15. @Override
  16. public void done(BmobIMMessage msg, BmobException e) {
  17. if (e == null) {//发送成功
  18. toast("好友请求发送成功,等待验证");
  19. } else {//发送失败
  20. toast("发送失败:" + e.getMessage());
  21. }
  22. }
  23. });

4.7、用户管理

BmobNewIM SDK只是即时通讯的消息收发渠道,本身并不提供用户体系。开发者可使用BmobSDK提供的用户管理方面功能,也可使用开发者自己的用户体系。

BmobNewIM SDK内部会自动创建本地用户表,并对外提供方法供开发者调用来操作本地用户表。开发者只需要调用updateUserInfo方法即可更新本地用户信息。

4.7.1、BmobIMUserInfo介绍

BmobNewIM SDK中用户的实体类为BmobIMUserInfo,其有四个属性,开发者只需要关心后三个即可。

属性名 属性含义
id 本地数据库用户表的id值,开发者无需关心
userId 用户唯一id(Demo中用的是BmobUser的objectId)
name 用户名 (Demo中是用的是BmobUser的username)
avatar 用户头像

4.7.2、更新本地用户信息

以下两种情况需要更新用户信息:

  1. 当注册或登录成功后,需要更新下当前用户的信息到本地数据库的用户表中,这样才能通过getUserInfo方法获取到本地的用户信息。
  2. 当接收到某人消息的时候,同样需要更新A的用户信息到本地用户表中,否则在会话界面将默认显示的是用户的userId,也就是Demo中的BmobUser的objectId值。
4.7.2.1、更新单一本地用户信息
  1. BmobIM.getInstance().updateUserInfo(BmobIMUserInfo info)
4.7.2.2、批量更新本地用户信息
  1. BmobIM.getInstance().updateBatchUserInfo(List<BmobIMUserInfo> list)

4.7.3、获取本地用户信息

BmobNewIM SDK内部会自动创建了一个本地数据库用来存储用户信息,开发者需要先调用updateUserInfo更新用户信息到本地数据库中,才能通过getUserInfo(uid)获取到本地用户信息。

  1. BmobIM.getInstance().getUserInfo(String uid)

4.8、好友管理

BmobNewIM SDK中并没有集成好友管理相关的功能,为了方便开发者建立基于好友之间的聊天模式,在v2.0.4版本开始的Demo中使用Data SDK新建了Friend表来进行好友管理。

  1. /**好友表
  2. * @author smile
  3. * @project Friend
  4. * @date 2016-04-26
  5. */
  6. public class Friend extends BmobObject{
  7. //用户
  8. private User user;
  9. //好友
  10. private User friendUser;
  11. //getter setter...
  12. }

4.8.1、获取好友列表

以下摘自UserModel(cn.bmob.imdemo.model)类:

  1. /**
  2. * 查询好友
  3. * @param listener
  4. */
  5. public void queryFriends(final FindListener<Friend> listener){
  6. BmobQuery<Friend> query = new BmobQuery<>();
  7. User user =BmobUser.getCurrentUser(getContext(), User.class);
  8. query.addWhereEqualTo("user", user);
  9. query.include("friendUser");
  10. query.order("-updatedAt");
  11. query.findObjects(getContext(), new FindListener<Friend>() {
  12. @Override
  13. public void onSuccess(List<Friend> list) {
  14. if (list != null && list.size() > 0) {
  15. listener.onSuccess(list);
  16. } else {
  17. listener.onError(0, "暂无联系人");
  18. }
  19. }
  20. @Override
  21. public void onError(int i, String s) {
  22. listener.onError(i, s);
  23. }
  24. });
  25. }

4.8.2、删除好友

以下摘自UserModel(cn.bmob.imdemo.model)类:

  1. /**
  2. * 删除好友
  3. * @param f
  4. * @param listener
  5. */
  6. public void deleteFriend(Friend f,DeleteListener listener){
  7. Friend friend =new Friend();
  8. friend.delete(getContext(),f.getObjectId(),listener);
  9. }

4.8.3、添加好友

Demo中创建了一个NewFriend的本地数据库类用来存储所有的添加好友请求。

  1. /**本地的好友请求表
  2. * @author :smile
  3. * @project:NewFriend
  4. * @date :2016-04-26-17:28
  5. */
  6. public class NewFriend implements java.io.Serializable {
  7. private Long id;
  8. //用户uid
  9. private String uid;
  10. //留言消息
  11. private String msg;
  12. //用户名
  13. private String name;
  14. //头像
  15. private String avatar;
  16. //状态:未读、已读、已添加、已拒绝等
  17. private Integer status;
  18. //请求时间
  19. private Long time;
  20. //getter setter...
  21. }

Demo中创建了一个AddFriendMessage类来展示如何发送自定义的添加好友请求的消息。

  1. /**添加好友请求-自定义消息类型
  2. * @author :smile
  3. * @project:AddFriendMessage
  4. * @date :2016-01-30-17:28
  5. */
  6. public class AddFriendMessage extends BmobIMExtraMessage{
  7. public AddFriendMessage(){}
  8. @Override
  9. public String getMsgType() {
  10. //自定义一个`add`的消息类型
  11. return "add";
  12. }
  13. @Override
  14. public boolean isTransient() {
  15. //设置为true,表明为暂态消息,那么这条消息并不会保存到本地db中,SDK只负责发送出去
  16. //设置为false,则会保存到指定会话的数据库中
  17. return true;
  18. }
  19. ...
  20. }

Demo中创建了一个AgreeAddFriendMessage类来展示如何发送自定义的同意添加好友请求的消息,并在对方的本地会话表中新增消息类型。

  1. /**同意添加好友请求-仅仅只用于发送同意添加好友的消息
  2. * @author smile
  3. * @project AgreeAddFriendMessage
  4. * @date 2016-03-04-10:41
  5. */
  6. public class AgreeAddFriendMessage extends BmobIMExtraMessage{
  7. //以下均是从extra里面抽离出来的字段,方便获取
  8. private String uid;//最初的发送方
  9. private Long time;
  10. private String msg;//用于通知栏显示的内容
  11. @Override
  12. public String getMsgType() {
  13. return "agree";
  14. }
  15. @Override
  16. public boolean isTransient() {
  17. //如果需要在对方的会话表中新增一条该类型的消息,则设置为false,表明是非暂态会话
  18. //此处将同意添加好友的请求设置为false,为了演示怎样向会话表和消息表中新增一个类型,在对方的会话列表中增加`我通过了你的好友验证请求,我们可以开始聊天了!`这样的类型
  19. return false;
  20. }
  21. //getter setter...
  22. ...
  23. }

4.8.4、发送添加好友的请求

以下摘自UserInfoActivity(cn.bmob.imdemo.ui)类:

  1. /**
  2. * 发送添加好友的请求
  3. */
  4. private void sendAddFriendMessage(){
  5. //启动一个暂态会话,也就是isTransient为true,表明该会话仅执行发送消息的操作,不会保存会话和消息到本地数据库中,
  6. BmobIMConversation c = BmobIM.getInstance().startPrivateConversation(info, true,null);
  7. //这个obtain方法才是真正创建一个管理消息发送的会话
  8. BmobIMConversation conversation = BmobIMConversation.obtain(BmobIMClient.getInstance(), c);
  9. //新建一个添加好友的自定义消息实体
  10. AddFriendMessage msg =new AddFriendMessage();
  11. User currentUser = BmobUser.getCurrentUser(this,User.class);
  12. msg.setContent("很高兴认识你,可以加个好友吗?");//给对方的一个留言信息
  13. Map<String,Object> map =new HashMap<>();
  14. map.put("name", currentUser.getUsername());//发送者姓名,这里只是举个例子,其实可以不需要传发送者的信息过去
  15. map.put("avatar",currentUser.getAvatar());//发送者的头像
  16. map.put("uid",currentUser.getObjectId());//发送者的uid
  17. msg.setExtraMap(map);
  18. conversation.sendMessage(msg, new MessageSendListener() {
  19. @Override
  20. public void done(BmobIMMessage msg, BmobException e) {
  21. if (e == null) {//发送成功
  22. toast("好友请求发送成功,等待验证");
  23. } else {//发送失败
  24. toast("发送失败:" + e.getMessage());
  25. }
  26. }
  27. });
  28. }

4.8.5、发送同意添加好友的请求

以下摘自NewFriendHolder(cn.bmob.imdemo.adapter)类:

  1. /**
  2. * 发送同意添加好友的请求
  3. */
  4. private void sendAgreeAddFriendMessage(final NewFriend add,final SaveListener listener){
  5. //发给谁,就填谁的用户信息
  6. BmobIMUserInfo info = new BmobIMUserInfo(add.getUid(), add.getName(), add.getAvatar());
  7. //启动一个暂态会话,也就是isTransient为true,表明该会话仅执行发送消息的操作,不会保存会话和消息到本地数据库中,
  8. BmobIMConversation c = BmobIM.getInstance().startPrivateConversation(info,true,null);
  9. //这个obtain方法才是真正创建一个管理消息发送的会话
  10. BmobIMConversation conversation = BmobIMConversation.obtain(BmobIMClient.getInstance(),c);
  11. //而AgreeAddFriendMessage的isTransient设置为false,表明我希望在对方的会话数据库中保存该类型的消息
  12. AgreeAddFriendMessage msg =new AgreeAddFriendMessage();
  13. User currentUser = BmobUser.getCurrentUser(getContext(), User.class);
  14. msg.setContent("我通过了你的好友验证请求,我们可以开始聊天了!");//---这句话是直接存储到对方的消息表中的
  15. Map<String,Object> map =new HashMap<>();
  16. map.put("msg",currentUser.getUsername()+"同意添加你为好友");//显示在通知栏上面的内容
  17. map.put("uid",add.getUid());//发送者的uid-方便请求添加的发送方找到该条添加好友的请求
  18. map.put("time", add.getTime());//添加好友的请求时间
  19. msg.setExtraMap(map);
  20. conversation.sendMessage(msg, new MessageSendListener() {
  21. @Override
  22. public void done(BmobIMMessage msg, BmobException e){
  23. if (e == null) {//发送成功
  24. //修改本地的好友请求记录
  25. NewFriendManager.getInstance(getContext()).updateNewFriend(add.getUid(),add.getTime(),Config.STATUS_VERIFIED);
  26. listener.onSuccess();
  27. } else {//发送失败
  28. listener.onFailure(e.getErrorCode(),e.getMessage());
  29. }
  30. }
  31. });
  32. }

4.8.6、接收并处理好友相关的请求

以下摘自DemoMessageHandler(cn.bmob.imdemo)类:

  1. /**
  2. * 处理自定义消息类型:用户自定义的消息类型,其类型值均为0
  3. * @param msg
  4. */
  5. private void processCustomMessage(BmobIMMessage msg,BmobIMUserInfo info){
  6. String type =msg.getMsgType();
  7. //发送页面刷新的广播
  8. EventBus.getDefault().post(new RefreshEvent());
  9. //处理消息
  10. if(type.equals("add")){//接收到的添加好友的请求
  11. NewFriend friend = AddFriendMessage.convert(msg);
  12. //本地好友请求表做下校验,本地没有的才允许显示通知栏--有可能离线消息会有些重复
  13. long id = NewFriendManager.getInstance(context).insertOrUpdateNewFriend(friend);
  14. if(id>0){
  15. showAddNotify(friend);
  16. }
  17. }else if(type.equals("agree")){//接收到的对方同意添加自己为好友,此时需要做的事情:1、添加对方为好友,2、显示通知
  18. AgreeAddFriendMessage agree = AgreeAddFriendMessage.convert(msg);
  19. addFriend(agree.getFromId());//添加消息的发送方为好友
  20. //这里应该也需要做下校验--来检测下是否已经同意过该好友请求,我这里省略了
  21. showAgreeNotify(info,agree);
  22. }else{
  23. Toast.makeText(context,"接收到的自定义消息:"+msg.getMsgType() + "," + msg.getContent() + "," + msg.getExtra(),Toast.LENGTH_SHORT).show();
  24. }
  25. }

4.8.7、添加到Friend表中

以下摘自DemoMessageHandler(cn.bmob.imdemo)类:

  1. /**
  2. * 添加对方为自己的好友
  3. * @param uid
  4. */
  5. private void addFriend(String uid){
  6. User user =new User();
  7. user.setObjectId(uid);
  8. //添加到Friend表中
  9. UserModel.getInstance().agreeAddFriend(user, new SaveListener() {
  10. @Override
  11. public void onSuccess() {
  12. Log.i("bmob", "onSuccess");
  13. }
  14. @Override
  15. public void onFailure(int i, String s) {
  16. Log.i("bmob", "onFailure:"+s+"-"+i);
  17. }
  18. });
  19. }

5. 混淆

  1. # 不混淆im sdk
  2. -keep class cn.bmob.newim.**{*;}
  3. -dontwarn cn.bmob.newim.**
  4. # 不混淆greenDao类
  5. -dontwarn de.greenrobot.dao.**
  6. -keep class de.greenrobot.dao.** { *;}
  7. -keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
  8. public static java.lang.String TABLENAME;
  9. }
  10. -keep class **$Properties
  11. # 不混淆async
  12. -dontwarn com.koushikdutta.async.**
  13. -keep class com.koushikdutta.async.** { *;}