yun2win-Android IM SDK使用方法
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结构图
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