先上图吧就两张静止图片吧:
接三方SDK官方文档先看(http://docs-im.easemob.com/im/android/sdk/import)
按照官方文档一步一步来,注册并创建应用,到环信官网下载环信 SDK。然后根据自己的需要导入自己想要的功能。我这里主要是单聊,以及圆形头像与昵称的保存。保存数据用的是ormlite。主要记录一下坑。这里就不具体讲登录注册了。
问题:public class MyChatFragment extends EaseChatFragment implements EaseChatFragment.EaseChatFragmentHelper 如果报错的话需要依赖
implementation 'android.arch.lifecycle:extensions:1.1.1'
问题:设置圆形头像找到EaseUserUtils
public static void setUserAvatar(Context context, String username, ImageView imageView){
EaseUser user = getUserInfo(username);
RequestOptions optionsCircle = new RequestOptions();
DrawableTransitionOptions transitionOptions = new DrawableTransitionOptions();
optionsCircle.placeholder(R.drawable.icon_head);
optionsCircle.transform(new GlideCircleTransform());
optionsCircle.diskCacheStrategy(DiskCacheStrategy.ALL);
if(user != null && user.getAvatar() != null){
try {
int avatarResId = Integer.parseInt(user.getAvatar());
Glide.with(context)
.load(avatarResId)
.apply(optionsCircle)
// .transition(transitionOptions.crossFade())
.into(imageView);
} catch (Exception e) {
Glide.with(context)
.load(user.getAvatar())
.apply(optionsCircle)
// .transition(transitionOptions.crossFade())
.into(imageView);
}
}else Glide.with(context)
.load(R.drawable.icon_head)
.apply(optionsCircle)
// .transition(transitionOptions.crossFade())
.into(imageView);
}
问题:发送的缩略图大小修改在EaseChatRowImage类里面 ,接收 登录环信后台修改大小
new AsyncTask<Object, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Object... args) {
File file = new File(thumbernailPath);
if (file.exists()) {
return EaseImageUtils.decodeScaleImage(thumbernailPath, 480, 480);
} else if (new File(imgBody.thumbnailLocalPath()).exists()) {
return EaseImageUtils.decodeScaleImage(imgBody.thumbnailLocalPath(), 480, 480);
} else {
if (message.direct() == EMMessage.Direct.SEND) {
if (localFullSizePath != null && new File(localFullSizePath).exists()) {
return EaseImageUtils.decodeScaleImage(localFullSizePath, 480, 480);
} else {
return null;
}
} else {
return null;
}
}
}
protected void onPostExecute(Bitmap image) {
if (image != null) {
imageView.setImageBitmap(image);
EaseImageCache.getInstance().put(thumbernailPath, image);
}
}
}.execute();
问题:UserCacheManager 获取用户个人信息默认通过本地数据库里面查询,有则使用本地的信息,没有则调取服务器信息
代码注释的地方则是从服务器上获取
/**
* 获取用户信息
* @param userId 用户环信ID
* @return
*/
public static UserCacheInfo get(final String userId){
UserCacheInfo info = null;
// 如果本地缓存不存在或者过期,则从存储服务器获取
if (notExistedOrExpired(userId)){
// HttpHelper.getInstance().getImInfo(context,userId, new NetWorkDataProcessingCallBack() {
// @Override
// public void onSuccess(Object response, String urlType, String msg) {
// if (response == null) return;
//
// UserBean userBean = (UserBean) response;
// save(userId,userBean.getName(),userBean.getImg());
// }
//
// @Override
// public void onError(String urlType, String msg) {}
// });
}
// 从本地缓存中获取用户数据
info = getFromCache(userId);
return info;
}
CjImHelper 这个类主要是环信的初始化之类的东西,以及消息的监听
public class CjImHelper {
private final String LOG_TAG = getClass().getSimpleName();
private Context mContext;
private EaseUI easeUI;
public boolean isVideoCalling;
public boolean isVoiceCalling;
// 记录是否已经初始化
private boolean isInit = false;
//监听
private EMConversationListener convListener;
public void setConvListener(EMConversationListener convListener) {
this.convListener = convListener;
}
private static CjImHelper mInstance;
private CjImHelper() {
}
public synchronized static CjImHelper getInstance() {
if (mInstance == null) {
mInstance = new CjImHelper();
}
return mInstance;
}
/**
* init helper
*
* @param context
* application context
*/
public void init(Context context) {
this.mContext =context;
initEasemob();
}
private void initEasemob(){
int pid = android.os.Process.myPid();
String processAppName = getAppName(pid);
// 如果APP启用了远程的service,此application:onCreate会被调用2次
// 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次
// 默认的APP会在以包名为默认的process name下运行,如果查到的process name不是APP的process name就立即返回
if (processAppName == null ||!processAppName.equalsIgnoreCase(mContext.getPackageName())) {
Log.e(LOG_TAG, "enter the service process!");
// 则此application::onCreate 是被service 调用的,直接返回
return;
}
if(isInit){
return ;
}
/**
* SDK初始化的一些配置
* 关于 EMOptions 可以参考官方的 API 文档
* http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_options.html
*/
EMOptions options = new EMOptions();
// 设置Appkey,如果配置文件已经配置,这里可以不用设置
// options.setAppKey("lzan13#hxsdkdemo");
// 设置自动登录
options.setAutoLogin(true);
// 设置是否需要发送已读回执
options.setRequireAck(true);
// 设置是否需要发送回执,TODO 这个暂时有bug,上层收不到发送回执
options.setRequireDeliveryAck(true);
// 设置是否需要服务器收到消息确认
options.setAutoTransferMessageAttachments(true);
// 收到好友申请是否自动同意,如果是自动同意就不会收到好友请求的回调,因为sdk会自动处理,默认为true
options.setAcceptInvitationAlways(false);
// 设置是否自动接收加群邀请,如果设置了当收到群邀请会自动同意加入
options.setAutoAcceptGroupInvitation(false);
// 设置(主动或被动)退出群组时,是否删除群聊聊天记录
options.setDeleteMessagesAsExitGroup(false);
// 设置是否允许聊天室的Owner 离开并删除聊天室的会话
options.allowChatroomOwnerLeave(true);
// 设置google GCM推送id,国内可以不用设置
// options.setGCMNumber(MLConstants.ML_GCM_NUMBER);
// 设置集成小米推送的appid和appkey
// options.setMipushConfig(MLConstants.ML_MI_APP_ID, MLConstants.ML_MI_APP_KEY);
// 调用初始化方法初始化sdk
EaseUI.getInstance().init(mContext, options);
easeUI = EaseUI.getInstance();
setEaseUIProviders();
// 设置开启debug模式
EMClient.getInstance().setDebugMode(true);
registerMessageListener();
// 设置初始化已经完成
isInit = true;
}
private String getAppName(int pID) {
String processName = null;
ActivityManager am = (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE);
List l = am.getRunningAppProcesses();
Iterator i = l.iterator();
PackageManager pm = mContext.getPackageManager();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());
try {
if (info.pid == pID) {
processName = info.processName;
return processName;
}
} catch (Exception e) {
// Log.d("Process", "Error>> :"+ e.toString());
}
}
return null;
}
protected void setEaseUIProviders() {
// set profile provider if you want easeUI to handle avatar and nickname
easeUI.setUserProfileProvider(UserCacheManager::getEaseUser);
//set notification options, will use default if you don't set it
easeUI.getNotifier().setNotificationInfoProvider(new EaseNotifier.EaseNotificationInfoProvider() {
@Override
public String getTitle(EMMessage message) {
//you can update title here
return null;
}
@Override
public int getSmallIcon(EMMessage message) {
//you can update icon here
return 0;
}
@Override
public String getDisplayedText(EMMessage message) {
// be used on notification bar, different text according the message type.
String ticker = EaseCommonUtils.getMessageDigest(message, mContext.getApplicationContext());
if(message.getType() == EMMessage.Type.TXT){
ticker = ticker.replaceAll("\\[.{2,3}\\]", "[表情]");
}
EaseUser user = getUserInfo(message.getFrom());
if(user != null){
if(EaseAtMessageHelper.get().isAtMeMsg(message)){
return String.format("%s在群聊中@了你", user.getNickname());
}
return user.getNickname() + ": " + ticker;
}else{
if(EaseAtMessageHelper.get().isAtMeMsg(message)){
return String.format("%s在群聊中@了你", message.getFrom());
}
return message.getFrom() + ": " + ticker;
}
}
@Override
public String getLatestText(EMMessage message, int fromUsersNum, int messageNum) {
// here you can customize the text.
// return fromUsersNum + "contacts send " + messageNum + "messages to you";
return null;
}
@Override
public Intent getLaunchIntent(EMMessage message) {
// you can set what activity you want display when user click the notification
Intent intent = new Intent(mContext,ChatActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP );
// open calling activity if there is call
if(isVideoCalling){
// intent = new Intent(appContext, VideoCallActivity.class);
}else if(isVoiceCalling){
// intent = new Intent(appContext, VoiceCallActivity.class);
}else{
EMMessage.ChatType chatType = message.getChatType();
if (chatType == EMMessage.ChatType.Chat) { // single chat message
intent.putExtra("userId", message.getFrom());
intent.putExtra("chatType", EaseConstant.CHATTYPE_SINGLE);
} else { // group chat message
// message.getTo() is the group id
intent.putExtra("userId", message.getTo());
if(chatType == EMMessage.ChatType.GroupChat){
intent.putExtra("chatType", EaseConstant.CHATTYPE_GROUP);
}else{
intent.putExtra("chatType", EaseConstant.CHATTYPE_CHATROOM);
}
}
}
return intent;
}
});
}
EMMessageListener messageListener;
protected void registerMessageListener() {
messageListener = new EMMessageListener() {
private BroadcastReceiver broadCastReceiver = null;
@Override
public void onMessageReceived(List<EMMessage> messages) {
for (EMMessage message : messages) {
EMLog.d(LOG_TAG, "onMessageReceived id : " + message.getMsgId());
//接收并处理扩展消息
String userName = message.getStringAttribute(UserCacheManager.kChatUserNick, "");
String userId = message.getStringAttribute(UserCacheManager.kChatUserId, "");
String userPic = message.getStringAttribute(UserCacheManager.kChatUserPic, "");
String hxIdFrom = message.getFrom();
EaseUser easeUser = new EaseUser(hxIdFrom);
easeUser.setAvatar(userPic);
easeUser.setNickname(userName);
UserCacheManager.save(hxIdFrom,userName,userPic);
easeUI.getNotifier().notify(message);
}
if (convListener!=null)
convListener.onCoversationUpdate();
}
@Override
public void onCmdMessageReceived(List<EMMessage> messages) {
for (EMMessage message : messages) {
EMLog.d(LOG_TAG, "receive command message");
}
}
@Override
public void onMessageRead(List<EMMessage> messages) {
}
@Override
public void onMessageDelivered(List<EMMessage> message) {
}
@Override
public void onMessageRecalled(List<EMMessage> list) {
}
@Override
public void onMessageChanged(EMMessage message, Object change) {
}
};
EMClient.getInstance().chatManager().addMessageListener(messageListener);
}
}
问题:混淆崩溃问题附上自己的百度地图,环信,Ormlite的混淆代码。。。最开始用demo里面的easeui混淆之后百度地图老是崩溃,最后发现替换里面的百度地图架包和so文件用最新的就好了,这是个大坑。。。。附上demo地址:https://github.com/lcjiang1993/CjEaseUiDemo 。 希望对出现问题的朋友有所帮助吧。
#****************baiduMap****************************
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-dontwarn com.baidu.**
#****************baiduMap****************************
#环信
-keep class org.xmlpull.** {*;}
-keep class com.hyphenate.** {*;}
-keep class com.hyphenate.chat.** {*;}
-dontwarn com.hyphenate.**
-keep class org.jivesoftware.** {*;}
-keep class org.apache.** {*;}
#2.0.9后加入语音通话功能,如需使用此功能的api,加入以下keep
-keep class net.java.sip.** {*;}
-keep class org.webrtc.voiceengine.** {*;}
-keep class org.bitlet.** {*;}
-keep class org.slf4j.** {*;}
-keep class ch.imvs.** {*;}
-keep class com.superrtc.** { *; }
#华为混淆
-keep class com.huawei.hms.update.** {
*;
}
-dontwarn com.huawei.hms.update.**
# OrmLite uses reflection
-keep class com.j256.**
-keepclassmembers class com.j256.** { *; }
-keep enum com.j256.**
-keepclassmembers enum com.j256.** { *; }
-keep interface com.j256.**
-keepclassmembers interface com.j256.** { *; }
-keepattributes *Annotation*
-keepclassmembers class com.package.bo.** { *; }
-keepclassmembers class * {
@com.j256.ormlite.field.DatabaseField *;
}
-keepattributes Signature