yun2win-Android IM SDK使用方法   简介 开发准备 注册 登录 当前用户 用户会话 联系人 群组 Session SessionMember 消息

yun2win-Android im-SDK下载地址:https://github.com/yun2win/yun2win-sdk-android

yun2win官网:www.yun2win.com

简介

yun2win即时通讯云安卓客户端主要由聊天实例和推送服务组成,其中聊天服务组件由开发者从Github获得源码,自行修改定义,保证开发者对界面功能的绝对自主。

开发准备

  • 到 github下载yun2winSDK及demo
  • 下载源码详解

    app为主体显示Module uikit为公共服务Module

    app下libs的yun2win-0.1.jar为推送SDK

    主体Module结构图

    yun2win-Android IM SDK使用方法
 
简介
开发准备
注册
登录
当前用户
用户会话
联系人
群组
Session
SessionMember
消息

    base文件夹:app初始相关类

    Bridge文件夹:推送连接、接收和发送

    common文件夹:公共配置等

    db文件夹:数据库管理

    entities文件夹:实体集合

    manage文件夹:模型实体管理

    model文件夹:模型集合

    service文件夹:服务管理

    ui文件夹:界面相关

  • 配置信息

    在清单文件AndroidManifest.xml里加入以下权限,以及写上你注册的appkey

    权限配置(实际开发中可能需要更多的权限,可参考demo):

    复制
       
    <?xml version="1.0" encoding="utf-8" ?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yun2win.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" />
            <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
            <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
            <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
            <uses-permission android:name="android.permission.WRITE_SETTINGS" />
            <!-- 手机状态 -->
            <uses-permission android:name="android.permission.GET_TASKS" />
            <uses-permission android:name="android.permission.FLASHLIGHT" />
            <uses-permission android:name="android.permission.VIBRATE" />
            <uses-permission android:name="android.permission.WAKE_LOCK" />
            <uses-permission android:name="android.permission.BLUETOOTH" />
            <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
            <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
            <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
            <!-- 读写文件 -->
            <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
            <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
            <!-- 多媒体 -->
            <uses-permission android:name="android.permission.CAMERA" />
            <uses-permission android:name="android.permission.RECORD_AUDIO" />
            <uses-permission android:name="android.permission.READ_PHONE_STATE" />
            <application android:name="y2w.base.AppContext"
            android:allowbackup="true"
            android:icon="@drawable/lyy_icon"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">
                <!-- 设置yun2win应用的appkey -->
                <meta-data android:name="YUN2WIN_APP_KEY"
                android:value="CerAgk970T8MlUmz" /> 
            </application>
    </manifest>

    关于YUN2WIN_APP_KEY对应的value获取,在创建应用后,申请APPKEY并进行相关配置。

  • app打包混淆

    在proguard文件中加入以下keep

    -keep class com.yun2win.** {*;}

    -dontwarn com.yun2win.**

注册

发送注册请求

复制
   
       //account  pwd username设置账户 密码 用户名
Users.getInstance().getRemote().register(account, pwd, username,new Back.Result<user>() {
            @override
            public void onsuccess(user user) { />/注册成功 返回当前用户信息 跳转界面
                    UserInfo.setUserInfo(user.getEntity().getAccount(),"","","","","","");
                    Intent intent = new Intent(context,LoginActivity.class);
                    startActivity(intent);
                    finish();
            }
            @Override
            public void onError(int errorCode,String error) {
            //注册失败 
            }
            }
    });

登录

发送登陆请求获取当前用户数据

复制
   
Users.getInstance().getRemote().login(account, password, new Back.Result<currentuser>() 
    {
        @Override
        public void onSuccess(CurrentUser currentUser) {
            //同步会话联系人
            Users.getInstance().getCurrentUser().getRemote().sync(new Back.Callback() 
               {
                    @Override
                    public void onSuccess() {
                    startActivity(new Intent(LoginActivity.this, MainActivity.class));
                    finish();
                    }
                    @Override
                    public void onError(int errorCode, String error) {
                        //同步失败
                    }
              });
        }
        @Override
        public void onError(int errorCode, String error) {
          //注册失败
        }
    });

登陆成功,在跳转页面onCreate方法里面添加如下代码(此处为MainActivity)

复制
   
//推送服务器连接
Users.getInstance().getCurrentUser().getImBridges().connect();

当前用户

用户属性

复制
   
String id;//用户ID
String name;//用户名字
String account;//用户账号
String createdAt;//创建时间
String updatedAt;//更新时间
String avatarUrl;//用户名字

当前用户属性

复制
   
String appKey;
String secret;
String token;
MToken imToken;//用于连接y2wIM消息推送服务器
Contacts contacts;//联系人对象
Sessions sessions;//会话对象
UserConversations userConversations;//用户会话对象
UserSessions userSessions;//群组对象
IMBridges imBridges;//消息推送代理对象
Remote remote;//远程方法封装对象
CurrentUser user;//当前会话对象

获取当前登陆的用户信息(yun2win支持多用户登陆)

复制
   
//获取当前用户的名字
Users.getInstance().getCurrentUser().getEntity().getName();
//获取当前用户的头像
Users.getInstance().getCurrentUser().getEntity().getAvatarUrl();
//获取当前用户其它信息亦然

用户会话

用户会话实体UserConversation属性

复制
  
String id;//会话ID
String targetId;//如果是群卫会话ID 个人对个人是对方用户ID
String name;//会话名称
String type;//会话类型
boolean top;//是否置顶
boolean visiable;//是否可见
int unread;//未读消息
//最后一条消息发送者 唯一标识码
String lastSender;
String lastType;
//最后一条消息展示类容
String lastContent;
boolean isDelete;//是否被删除
String createdAt;
String updatedAt;
String avatarUrl;//头像地址

为了保证消息的完整性,我们采取同步服务端数据到本地数据库,同时通过查询本地数据库更新界面,同步时拿本地最后一条更新数据的时间同步后面的数据(默认时间1990-01-01 00:00:00),联系人和聊天消息亦然

同步处理机制

通过CallBackUpdate管理界面和更新消息通知,当创建一个当前界面时添加CallBackUpdate实例,销毁当前界面时,移除当前CallBackUpdate实例

接收消息通知

复制
   
Handler updatesessionHandler= new Handler()
 {
    @Override
    public void handleMessage(Message msg) {
           super.handleMessage(msg);
            if(msg.what ==0){//更新界面
            conversationAdapter.updateListView();
            }else if(msg.what==1){//接收更新,本地服务器获取新的内容
                    conversations = Users.getInstance().
                    getCurrentUser().getUserConversations().getUserConversations();
                    conversationAdapter.setCOnversations(conversations);
                    updatesessionHandler.sendEmptyMessage(0);
            }
    }
};

添加CallBackUpdate

复制
 
//CallBackUpdate.updateType.userConversation.toString() 当前页面标识 
AppData.getInstance().getUpdateHashMap().
put(CallBackUpdate.updateType.userConversation.toString(),callBackUpdate);

移除CallBackUpdate

复制
 
//CallBackUpdate.updateType.userConversation.toString() 当前页面标识 
 AppData.getInstance().getUpdateHashMap().remove(CallBackUpdate.updateType.userConversation.toString());

同步会话

复制
 
Users.getInstance().getCurrentUser().getUserConversations().getRemote().sync(new Back.Result<list<userconversation>>() {
        @Override
        public void onSuccess(List<userconversation>userConversationList) {
                //同步到的消息添加到本地数据库
                Users.getInstance().getCurrentUser().getUserConversations().add(userConversationList);
                //返回更新成功,通知界面更新
                //AppData.getInstance().getUpdateHashMap().
                get(CallBackUpdate.updateType.userConversation.toString()).updateUI();
                callback.onSuccess();
        }
        @Override
        public void onError(int errorCode,String error) {
                callback.onError(errorCode,error);
        }
});

联系人

联系人Contacts属性

复制
 
//联系人唯一标识码
String id;
//用户唯一标识码
String userId;
String name;//名字
String email;//邮箱
String createdAt;//创建时间
String updatedAt;//更新时间
String avatarUrl;//头像地址
String role;//角色
String status;//状态
String jobTitle;//工作
boolean isDelete;//是否删除
String phone;//电话
String address;//地址

同步参考用户会话

联系人排序

复制
 
contacts =  Users.getInstance().getCurrentUser().getContacts().getContacts();
for (Contact data : contacts) {
SortModel sm = new SortModel();
sm.setId(data.getEntity().getId());
sm.setUserId(data.getEntity().getUserId());
sm.setName(data.getEntity().getName());
sm.setPinyin(data.getEntity().getName());
sm.setEmail(data.getEntity().getEmail());
sm.setAvatarUrl(data.getEntity().getAvatarUrl());
sm.setStatus(data.getEntity().getStatus());
sm.setRole(data.getEntity().getRole());
sm.setSortLetters(StringUtil.getPinYinSortLetters(characterParser,sm.getPinyin()));
SourceDataList.add(sm);
}
// 根据a-z进行排序源数据
Collections.sort(SourceDataList, pinyinComparator);
contactAdapter.setListViewdate(SourceDataList);

同步联系人

复制
 
//同步会话联系人
Users.getInstance().getCurrentUser().getRemote().sync(new Back.Callback() {
        @Override
        public void onSuccess() {
                Users.getInstance().getCurrentUser().getContacts().add(contacts);
                //返回更新成功,通知界面更新
                //AppData.getInstance().getUpdateHashMap().
                get(CallBackUpdate.updateType.contact.toString()).updateUI();
        }
        @Override
        public void onError(int errorCode, String error) {
        }
});

查找用户

复制
 
Users.getInstance().getRemote().search(keyword, new Back.Result<list<contactentity>>() {
        @Override
        public void onSuccess(List<contactentity> entities) {
                if (entities==null||entities.size()<=0) {
                ToastUtil.ToastMessage(AddContactActivity.this, "抱歉,没有查询到任何用户");
                return;
                }
                //更新界面
                Message msg = new Message();
                msg.what = 1;
                msg.obj = entities;
                updatelistHandler.sendMessage(msg);
        }
        @Override
        public void onError(int errorCode, String error) {
                ToastUtil.ToastMessage(AddContactActivity.this, "抱歉,没有查询到任何用户");
        }
});

获得个人用户信息

复制
 
  //_otheruserid 查找人的用户ID
Users.getInstance().getRemote().userGet(_otheruserid, new Back.Result<user>() {
        @Override
        public void onSuccess(User user) {
                account = user.getEntity().getAccount();
                username = user.getEntity().getName();
                avatarUrl =user.getEntity().getAvatarUrl();
                updatefriendHandler.sendEmptyMessage(0);
        }
        @Override
        public void onError(int Code, String error) {
        }
});

添加用户到联系人

添加好友,是把某人添加到自己联系人,不需要对方确认,也不会出现在对方联系人,除非对方也添加

复制
 
//_otherId 联系人ID
Users.getInstance().getCurrentUser().getContacts().getRemote().contactDelete(_otherId, new Back.Callback() {
        @Override
        public void onSuccess() {
                ToastUtil.ToastMessage(context, "删除联系人成功");
                //通知更新联系人界面
                AppData.getInstance().getUpdateHashMap().
                get(CallBackUpdate.updateType.contact.toString()).syncDate();
                finish();
        }
        @Override
        public void onError(int errorCode,String error) {
              ToastUtil.ToastMessage(context, "删除失败");
        }
});

提醒

请记下联系人ID不是用户ID,添加一个用户到我的联系人,就会生成一个相对这个用户的联系人ID

从联系人删除用户

复制
 
//_otheruserid 对方用户ID 对方账户 名字 头像
Users.getInstance().getCurrentUser().getContacts().getRemote().contactAdd(_otheruserid, account, username, avatarUrl, new Back.Result<contact>() {
        @Override
        public void onSuccess(Contact contact) {
                ToastUtil.ToastMessage(context, "添加联系人成功");
                //得到联系人ID
                _otherId = contact.getEntity().getId();
                //通知更新联系人界面
                AppData.getInstance().getUpdateHashMap().
                get(CallBackUpdate.updateType.contact.toString()).syncDate();
                isfriend = true;
                updatefriendHandler.sendEmptyMessage(2);
        }
        @Override
        public void onError(int errorCode, String error) {
               ToastUtil.ToastMessage(context, "添加失败");
        }
});

群组

群组UserSession属性

复制
 
//会话id
String id;
//会话类型为p2p时,对方Id
String sessionId;
//会话名称
String name;
//会话类型
boolean isDelete;
//会话创建时间
String createdAt;
//会话更新时间
String updatedAt;
//会话头像
String avatarUrl;

添加群组

复制
 
Users.getInstance().getCurrentUser().getUserSessions().getRemote().sessionStore( session.getEntity().getId(),  session.getEntity().getName(),  session.getEntity().getAvatarUrl(),  new Back.Result<usersession>(){
        @Override
        public void onSuccess(UserSession userSession) {
        }
        @Override
        public void onError(int Code, String error) {
        }
});

删除群组

复制
 
Users.getInstance().getCurrentUser().getUserSessions().getRemote().userSessionDelete( session.getEntity().getId(),new Back.Callback(){
        @Override
        public void onSuccess() {
        }
        @Override
        public void onError(int Code, String error) {
        }
});

同步群组

复制
 
Users.getInstance().getCurrentUser().getUserSessions().getRemote().sync( new Back.Result<list<usersession>>(){
        @Override
        public void onSuccess(List<usersessionentity> entities) {
        }
        @Override
        public void onError(int Code, String error) {
        }
});

提醒

我的群会话只有收藏才能加入到我的群,发起群聊人默认把群会话加入我的群收藏

Session

Session属性

复制
 
SessionEntity entity;//session实体
SessionMembers members;//session成员
Messages messages;//session消息

SessionEntity属性

复制
 
//会话id
String id;
//会话类型为p2p时,对方Id
String otherSideId;
//会话名称
String name;
//会话类型
String type;
//安全类型
String secureType;
//会话简介
String description;
//成员变更时间戳
String createMTS;
//成员信息变更时间戳
String updateMTS;
//会话创建时间
String createdAt;
//会话更新时间
String updatedAt;
//会话头像
String avatarUrl;

发起群聊,创建Session

复制
 
  /**
* 创建会话
* @param names session名字
* @param secureType 安全类型级别 public private
* @param SessionType 会话类型   p2p,group,single
* @param Urls.User_Avatar_Def 头像
*/
Users.getInstance().getCurrentUser().getSessions().getRemote().sessionCreate(names, secureType, EnumManage.sessionType, Urls.User_Avatar_Def, new Back.Result<session>() {
        @Override
        public void onSuccess(Session session) {
                addMytoGroupMembers(session);
        }
        @Override
        public void onError(int errorCode, String error) {
                ToastUtil.ToastMessage(SessionStartActivity.this, "创建失败");
                pd.dismiss();
        }
});

获得Session详情

复制
 
String targetId = EnumManage.SessionType.p2p.toString().equals(sessionType) ? otheruserID:sessionId;
/**
* 创建会话
* @param targetId 如何使一对一的聊天为对方用户ID否则为sessionID
* @param SessionType 会话类型   p2p,group,single
* @param Urls.User_Avatar_Def 头像
*/
Users.getInstance().getCurrentUser().getSessions().getSessionByTargetId(targetId, sessionType, new Back.Result<session>() {
            @Override
            public void onSuccess(Session session) {
                      _session = session;
            }
            @Override
            public void onError(int errorCode,String error) {
            }
            });
}

提醒

会话类型分为p2p个人对个人group群聊group其它

SessionMember

添加会话成员

复制
 
/**
* 创建会话
* @param userid 用户ID
* @param userName 用户名字
* @param groupRole 成员在群里的角色  master admin user
* @param userAvatarUrl 用户头像
* @param UserStatus 用户状态 active inactive
*/
session.getMembers().getRemote().sessionMemberAdd(userid,
userName,groupRole, userAvatarUrl, UserStatus, new Back.Result<sessionmember>(){
        @Override
        public void onSuccess(SessionMember sessionMember) {
                membersCount--;
                if(membersCount==0 && !iscreate){
                    pd.dismiss();
                    finish();
                }
        }
        @Override
        public void onError(int errorCode,String error) {
        }
});

提醒

发起群聊,先把自己添加进去,groupRole设置为master

删除会话成员

复制
 
session.getMembers().getRemote().sessionMemberDelete(sessionMember,new Back.Callback(){
        @Override
        public void onSuccess() {
        }
        @Override
        public void onError(int errorCode, String error) {
        }
});

同步会话成员

复制
 
session.getMembers().getRemote().sync(new Back.Result<list<sessionmember>>(){
@Override
public void onSuccess(List<sessionmember>
sessionMembers) {
}
@Override
public void onError(int Code, String error) {
}
})

消息

消息同步

MessageEntity属性

复制
 
String id;//消息ID
String sender;//发送者账号
String content;//消息内容
String createdAt;//创建时间
String updatedAt;//更新时间
String type;//消息类型
String status;//发送状态
String sessionId;//会话ID

初次进入消息聊天界面

1.获得最后一条同步消息的更新时间

2.如果消息时间为默认时间,为了防止历史消息太多,加载时间长,加载最近20条直接显示(此数据不存储至数据库), 同时进行消息同步存到数据库,标记正在同步,如果正在同步中,接收到的新消息和发消息都不存到本地数据库,直接界面显示

复制
 
int cout =Config.LOAD_MESSAGE_COUNT//默认加载20条
//获得最近历史消息
_session.getMessages().getRemote().getLastMessages(cout, new Back.Result<list<messagemodel>>() {
        @Override
        public void onSuccess(List<messagemodel>
        messageModels) {
                //更新界面    
                messageList.clear();
                messageList.addAll(messageModels);
                refreshMessageList();
                scrollToBottom();
        }
        @Override
        public void onError(int errorCode,String error) {
        }
});
//开始同步
synMessagedate =new synMessagedate();
synMessagedate.start();
复制
 
boolean issyndate =false;//是否正在同步
class synMessagedate extends Thread{//同步消息
        @Override
        public void run() {
                super.run();
                //标记正在同步
                issyndate =true;
                boolean isstore= true;//是否存储到本地数据库
                String updateAt =_session.getMessages().getMessageUpdateAt();获取本地数据最后一个消息的更新时间
                _session.getMessages().getRemote().sync(isstore,updateAt, Config.LOAD_MESSAGE_COUNT, 
                        new Back.Result<list<messagemodel>>() {
                        @Override
                        public void onSuccess(List<messagemodel> models) {
                                if (models.size() < Config.LOAD_MESSAGE_COUNT) {//同步完成
                                    //每次取20条数据,如果取到的数据小于20条表示更新完成
                                    issyndate=false;
                                    messageDisplay();
                                } else {
                                   //没有更新完成,继续更新
                                    run();
                                }
                                //标记消息已读
                                setMessagenum(models.size());
                        }
                        @Override
                        public void onError(int errorCode,String error) {
                        }
                });
        }
}

如果消息时间不为默认时间,但是未读消息大于20条执行上面第2条操作,如果未读消息小于或者等于20条,直接同步更新

复制
 
_session.getMessages().getRemote().sync(true,_session.getMessages().getMessageUpdateAt(), unread, new Back.Result<list<messagemodel>
>() {
@Override
public void onSuccess(List<messagemodel>
models) {
    setMessagenum(models.size());
    //初始化listview加载本地消息更新
    messageDisplay();
}
@Override
public void onError(int errorCode,String error) {
      messageDisplay();
}
});

有新的消息,同步新消息

为了防止频繁同步消息,如果接收到消息通知,先判断messageLoading是否正在同步消息,如果正在同步, 标记hasNewMessage,表示有新的消息过来,等上次同步完成判断hasNewMessage是否有新消息,如果有,继续同步

复制
 
if(messageLoading){
      hasNewMessage = true;
}else{
      loadNewMessage();
}
复制
 
private void loadNewMessage(){
            final int unread = 50;//默认一次加载消息条数
            messageLoading = true;//标记正在同步消息
            hasNewMessage = false;//标记没有新消息
            //issyndate判断是否有初始同步消息如果有就不存储到数据库
            _session.getMessages().getRemote().sync(!issyndate,_session.getMessages().getMessageUpdateAt(), 
                        unread, new Back.Result<list <messagemodel>>() {
                        @Override
                        public void onSuccess(List<messagemodel>
                        models) {
                                boolean istobottom =false;
                                int lastnum =lv_message.getLastVisiblePosition();
                                if(lastnum >=(messageList.size()-1))
                                istobottom =true;
                                if(models!=null&&models.size()>0){
                                boolean find =false;
                                List<messagemodel>
                                tempmodels = new ArrayList<messagemodel>();
                                //去掉重复的
                                for(int i =0;i<messagelist.size();i++){ if(!find) {
                                    if (models.get(0).getentity().getid().equals
                                     (messagelist.get(i).getentity().getid())) {
                                        find=true;
                                        tempmodels.add(messagelist.get(i));
                                    }
                                    }else{
                                         tempmodels.add(messagelist.get(i));
                                    }
                                }
                                if(find){
                                    messagelist.removeall(tempmodels);
                                }
                                messagelist.addall(models