EaseUI 快速集成(注意:自 V3.7.3 版本 easeUI 停止更新)

[EaseIMKit] EaseUI 的升级版 EaseIMKit 正式发布远程依赖库,版本号与 IM SDK 一致,详情请见:EaseIMKit 使用指南

在您阅读此文档时,我们假定您已经具备了基础的 Android 应用开发经验,并能够理解相关基础概念。此文档是针对导入EaseUI库的快速集成文档,如果只是导入SDK去集成使用,请移步 Android SDK集成

注册环信开发者账号并创建后台应用

详细操作步骤见 开发者注册及管理后台。 Appkey:一个 APP 的唯一标识

IM 用户:一个 appkey 下的唯一标识用户,用来登录环信服务器进行收发消息的用户。 可以在创建好的应用内注册两个 IM 用户(也可以称为环信 id),例如: 账号:user1,密码:123 ; 账号:user2,密码:123,用来通过 SDK 登录环信服务器,收发消息测试。

在环信 Console 后台,点击创建好的应用 → IM 用户 → 创建 IM 用户

建议创建两个 IM 用户,用于后面集成 SDK 之后聊天使用。例如登录 user1 ,在初始化聊天页面时传入 user2 ,user1 给 user2 发消息测试。

EaseUI是环信提供的UI库,封装了 IM 功能常用的控件、fragment 等等,旨在帮助开发者快速集成环信 SDK。 EaseUI里封装了三个fragment,分别是

  • EaseChatFragment – 聊天界面
  • EaseConversationFragment – 会话界面
  • EaseContactFragment – 通讯录界面

具体了解详见 EaseUI使用指南

EaseUI 中用到的第三方库:

  • glide-4.7.1:图片处理库,显示用户头像时用到
  • BaiduLBS_Android.jar:百度地图的 jar 包,相关 so 还有 libBaiduMapSDK_base_v4_0_0.so、libBaiduMapSDK_map_v4_0_0.so、libBaiduMapSDK_util_v4_0_0.so 及 liblocSDK7.so。如果不用百度可以把这些删除掉,删除掉后项目会报错,修改相应的报错(报错的代码很少,很容易就修改完成)

环信官网点击下载SDK+Demo源码

下载下来的压缩包解压后内容如下:

环信的EaseUI位置在examples路径下,与ChatDemoUI3.0平级,内部已经导入了带有实时音视频功能的IM SDK,不需要再去导入。

打开Android Studio,File–New–Import Module,选中demo路径下的easeui导入。

等待编译完成,然后将其添加依赖于app module下。

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

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="Your Package"
    android:versionCode="100"
    android:versionName="1.0.0">
  
    <!-- Required -->
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>  
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:name="Your Application">
  
   	<!-- 设置环信应用的AppKey -->
    	<meta-data android:name="EASEMOB_APPKEY"  android:value="Your AppKey" />
    	<!-- 声明SDK所需的service SDK核心功能-->
    	<service android:name="com.hyphenate.chat.EMChatService" android:exported="true"/>
        <service android:name="com.hyphenate.chat.EMJobService"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:exported="true"
            />
        <!-- 声明SDK所需的receiver -->
        <receiver android:name="com.hyphenate.chat.EMMonitorReceiver">
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                <data android:scheme="package"/>
            </intent-filter>
            <!-- 可选filter -->
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.USER_PRESENT" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

适配Android 7.0需在AndroidManifest.xml里配置FileProvider

<!-- 适配Android 7.0, 需要将下方的com.hyphenate.chatuidemo替换为你的app包名 -->
<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.hyphenate.chatuidemo.fileProvider"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

file_paths.xml内容如下,需将com/hyphenate/chatuidemo替换为你的包名路径

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path path="Android/data/com/hyphenate/chatuidemo/" name="files_root" />
    <external-path path="." name="external_storage_root" />

在application的onCreate下调用初始化EaseUI的方法。:EaseUi初始化里已包含SDK的初始化,不需要再去调用SDK的初始化。

//EaseUI初始化
if(EaseUI.getInstance().init(context, options)){
//在做打包混淆时,关闭debug模式,避免消耗不必要的资源
EMClient.getInstance().setDebugMode(true);
//EaseUI初始化成功之后再去调用注册消息监听的代码
...
}
//传入在应用(appkey)下注册的IM用户的账号和密码,用于登录环信服务器
EMClient.getInstance().login(userName,password,new EMCallBack() {//回调
    @Override
    public void onSuccess() {
        EMClient.getInstance().groupManager().loadAllGroups();
        EMClient.getInstance().chatManager().loadAllConversations();
            	
    }

    @Override
    public void onProgress(int progress, String status) {

    }

    @Override
    public void onError(int code, String message) {
        
    }
});
  • 如果在集成调试阶段,可以在初始化环信 SDK 完成之后,就调用登录方法。
  • 如果项目上线,建议开发者在登录自己服务器成功之后,再调用环信 SDK 登录方法使用用户绑定的环信id登录环信服务器(开发者给自己用户在自己服务器创建账号的同时,调用环信的 rest 接口在给用户授权注册一个环信 id,一起返回给 app 端,app 端拿到用户的账号密码以及环信 id 密码分别登录自己的服务器以及环信服务器)。

EaseUI里提供的EaseChatFragment可以直接拿来使用,也可创建Fragment去继承EaseChatFragment实现,如:需实现实时音视频通话。可参考demo的ChatFragment。 在项目里创建ChatActivity去加载EaseChatFragment

public class ChatActivity extends BaseActivity {
    public static ChatActivity activityInstance;
    private EaseChatFragment chatFragment;

    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        setContentView(R.layout.em_activity_chat);
        activityInstance = this;
        
        //use EaseChatFratFragment
        chatFragment = new EaseChatFragment();
        //pass parameters to chat fragment
        chatFragment.setArguments(getIntent().getExtras());
        getSupportFragmentManager().beginTransaction().add(R.id.container, chatFragment).commit();

    }

}

之后就可以通过调用Intent携带聊天对方的环信id跳转ChatActivity实现聊天

Intent intent = new Intent(this, ChatActivity.class);
//username为对方的环信id
intent.putExtra(EaseConstant.EXTRA_USER_ID, username);
startActivity(intent);

会话列表

需创建Fragment去继承EaseConversationFragment实现点击item跳转聊天界面,可参考demo的ConversationListFragment

conversationListView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                EMConversation conversation = conversationListView.getItem(position);
                String username = conversation.conversationId();
                if (username.equals(EMClient.getInstance().getCurrentUser()))
                    Toast.makeText(getActivity(), R.string.Cant_chat_with_yourself, Toast.LENGTH_SHORT).show();
                else {
                    // start chat acitivity
                    Intent intent = new Intent(getActivity(), ChatActivity.class);
                    if(conversation.isGroup()){
                        if(conversation.getType() == EMConversationType.ChatRoom){
                            // it's group chat
                            intent.putExtra(EaseConstant.EXTRA_CHAT_TYPE, EaseConstant.CHATTYPE_CHATROOM);
                        }else{
                            intent.putExtra(EaseConstant.EXTRA_CHAT_TYPE, EaseConstant.CHATTYPE_GROUP);
                        }
                        
                    }
                    // it's single chat
                    intent.putExtra(EaseConstant.EXTRA_USER_ID, username);
                    startActivity(intent);
                }
            }
        });

好友列表

好友列表同会话列表一样,都需要创建Fragment去继承EaseContactListFragment实现点击item跳转

listView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                EaseUser user = (EaseUser)listView.getItemAtPosition(position);
                if (user != null) {
                    String username = user.getUsername();
                    // demo中直接进入聊天页面,实际一般是进入用户详情页
                    startActivity(new Intent(getActivity(), ChatActivity.class).putExtra("userId", username));
                }
            }
        });

好友列表还需要去设置数据,通过调用setContactsMap(m)去设置,数据需要是Map<String, EaseUser>格式的,key是环信id。

:会话列表和好友列表都需要对应的Activity来加载,也可以都加载在同一个activity里,然后根据导航栏的点击来切换,譬如环信的demo那样。

实时音视频通话这块在EaseUI里是没有实现的,需要在项目里自行实现。可以直接从demo中去copy相关的类来快速实现。 首先需要在初始化之后去注册通话广播接收者,来监听通话请求。

IntentFilter callFilter = new IntentFilter(EMClient.getInstance().callManager().getIncomingCallBroadcastAction());
        if(callReceiver == null){
            callReceiver = new CallReceiver();
        }
 //register incoming call receiver
        appContext.registerReceiver(callReceiver, callFilter); 

CallReceiver代码如下

public class CallReceiver extends BroadcastReceiver{

	@Override
	public void onReceive(Context context, Intent intent) {
		if(!DemoHelper.getInstance().isLoggedIn())
		    return;
		//username
		String from = intent.getStringExtra("from");
		//call type
		String type = intent.getStringExtra("type");
		if("video".equals(type)){ //video call
		    context.startActivity(new Intent(context, VideoCallActivity.class).
                    putExtra("username", from).putExtra("isComingCall", true).
                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
		}else{ //voice call
		    context.startActivity(new Intent(context, VoiceCallActivity.class).
		            putExtra("username", from).putExtra("isComingCall", true).
		            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
		}
		EMLog.d("CallReceiver", "app received a incoming call");
	}
}

接着将demo中的VideoCallActivity、VoiceCallActivity、CallActivity以及它们需要的文件到copy过来。 然后在ChatFragment中registerExtendMenuItem方法中添加发起音视频通话的图标,实现对应的点击事件–携带参数跳转通话界面。

//视频通话就是跳转VideoCallActivity
startActivity(new Intent(getActivity(), VoiceCallActivity.class).putExtra("username", toChatUsername)
                    .putExtra("isComingCall", false));

可参考demo的ChatFragment。