android集成环信步骤
来源:互联网 发布:神农架值不值得去 知乎 编辑:程序博客网 时间:2024/06/01 08:14
前一阵时间一直以为环信不能被个人用户注册,结果现在想试试结果真的注册进来了,各种打脸。今天趁着晚上有时间把环信继承的步骤做一个记录,方便以后的童鞋们能够快速的集成。
1.第一步:肯定是创建应用喽
那么具体步骤为了避免大家看的烦躁,我就不一一截图了,而是将官网的连接地址给大家po过来
http://docs.easemob.com/im/000quickstart/10register
当然从这个连接中可以清楚的看到
感觉这一巴掌真痛!!!
当然官方的文档多少有点出入,没关系,只需要创建好自己的应用就可以了。
第一步so easy
2.第二步:下载sdk
不用多说,照着文档下载就行。po上网址:
http://www.easemob.com/download/im
解压后是这样的。
考虑到开发者需求不一样,在下载的 SDK 中,提供了两个不同的 jar 包:
- 一个是 libs 下带实时语音功能和实时视频功能的 jar 包和 so 文件。
- 如果你不需要实时语音、实时视频功能,那就直接用 libs.without.audio 文件夹下的 jar 包及 so 文件。
在这里主要介绍后面四个文件夹内容:
- doc 文件夹:SDK 相关 API 文档
- examples 文件夹:ChatDemoUI3.0(Demo,依赖 EaseUI 库)、EaseUI
- libs 文件夹:包含IM和实时音视频功能所需要的 jar 和 so 文件
- libs.without.audio 文件夹:无实时语音、实时视频功能的 SDK 包,如果项目中只用到聊天功能,可以把项目里的 jar 和 so 文件替换成此文件夹里的
简单的说,就是往你的项目中去粘贴东西就行了。
在自行开发的应用中,集成环信聊天需要把 libs 文件夹下的 jar 及 so 文件复制到你的项目的 libs 文件夹相应位置,如果不需要语音和视频通话功能,导入libs.without.audio 下的文件即可。
如图:
引入so文件有两种方法:
方法一:
· 在“src/main”目录中新建名为“jniLibs”的目录;
· 将so文件复制、粘贴到“jniLibs”目录内。
注:如果没有引用so文件,可能会在程序执行的时候加载类库失败,有类似如下的DEBUG提示:
java.lang.UnsatisfiedLinkError: Couldn't load library xxxx from loader dalvik.system.PathClassLoader
方法二:
· 把so文件拷贝到libs文件夹下
· 在build.gradle文件中配置
好啦,这样就可以轻松的把so文件引入到你的工程中了。
4.第四步,配置代码环境
在清单文件 AndroidManifest.xml 里加入以下权限,以及写上你注册的 AppKey。
权限配置(实际开发中可能需要更多的权限,可参考 Demo):
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="us.mifeng.guaju.huanxin">
- <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.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:name="app.MyApp"
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name=".LoginActivity">
- </activity>
- <activity
- android:name=".ChatActivity"
- android:windowSoftInputMode="adjustResize|stateHidden">
- </activity>
- <meta-data android:name="EASEMOB_APPKEY" android:value="guajujerry#im" />
- <!-- 声明SDK所需的service SDK核心功能-->
- <service android:name="com.hyphenate.chat.EMChatService" 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>
关于 EASEMOB_APPKEY 对应的 value 获取,在创建应用后,申请 AppKey 并进行相关配置。(环信 Demo 中 AppKey 为 easemob-demo#chatdemoui)
接下来是对自己创建的application进行初始化配置:
- package app;
- import android.app.ActivityManager;
- import android.app.Application;
- import android.content.Context;
- import com.hyphenate.chat.EMClient;
- import com.hyphenate.chat.EMOptions;
- import java.util.Iterator;
- import java.util.List;
- /**
- * Created by guaju on 2016/9/12.
- */
- public class MyApp extends Application {
- // 上下文菜单
- private Context mContext;
- // 记录是否已经初始化
- private boolean isInit = false;
- @Override
- public void onCreate() {
- super.onCreate();
- mContext = this;
- // 初始化环信SDK
- initEasemob();
- }
- /**
- *
- */
- private void initEasemob() {
- // 获取当前进程 id 并取得进程名
- 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())) {
- // 则此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("guaju");
- // 设置自动登录
- options.setAutoLogin(true);
- // 设置是否需要发送已读回执
- options.setRequireAck(true);
- // 设置是否需要发送回执,TODO 这个暂时有bug,上层收不到发送回执
- options.setRequireDeliveryAck(true);
- // 设置是否需要服务器收到消息确认
- options.setRequireServerAck(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
- EMClient.getInstance().init(mContext, options);
- // 设置开启debug模式
- EMClient.getInstance().setDebugMode(true);
- // 设置初始化已经完成
- isInit = true;
- }
- /**
- * 根据Pid获取当前进程的名字,一般就是当前app的包名
- *
- * @param pid 进程的id
- * @return 返回进程的名字
- */
- private String getAppName(int pid) {
- String processName = null;
- ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- List list = activityManager.getRunningAppProcesses();
- Iterator i = list.iterator();
- while (i.hasNext()) {
- ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());
- try {
- if (info.pid == pid) {
- // 根据进程的信息获取当前进程的名字
- processName = info.processName;
- // 返回当前进程名
- return processName;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- // 没有匹配的项,返回为null
- return null;
- }
- }
主界面
app启动后默认会进入到MainActivity
,不过在主界面会先判断一下是否登录成功过,如果没有,就会跳转到登录页面,然后我们调用登录的时候,在登录方法的onSuccess()
回调中我们进行了界面的跳转,跳转到主界面,在主界面我们可以发起回话。
看下主界面的详细代码实现:
- package us.mifeng.guaju.huanxin;
- import android.content.Intent;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.text.TextUtils;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.Toast;
- import com.hyphenate.EMCallBack;
- import com.hyphenate.chat.EMClient;
- public class MainActivity extends AppCompatActivity {
- // 发起聊天 username 输入框
- private EditText mChatIdEdit;
- // 发起聊天
- private Button mStartChatBtn;
- // 退出登录
- private Button mSignOutBtn;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // 判断sdk是否登录成功过,并没有退出和被踢,否则跳转到登陆界面
- if (!EMClient.getInstance().isLoggedInBefore()) {
- Intent intent = new Intent(MainActivity.this, LoginActivity.class);
- startActivity(intent);
- finish();
- return;
- }
- setContentView(R.layout.activity_main);
- initView();
- }
- /**
- * 初始化界面
- */
- private void initView() {
- mChatIdEdit = (EditText) findViewById(R.id.ec_edit_chat_id);
- mStartChatBtn = (Button) findViewById(R.id.ec_btn_start_chat);
- mStartChatBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // 获取我们发起聊天的者的username
- String chatId = mChatIdEdit.getText().toString().trim();
- if (!TextUtils.isEmpty(chatId)) {
- // 获取当前登录用户的 username
- String currUsername = EMClient.getInstance().getCurrentUser();
- if (chatId.equals(currUsername)) {
- Toast.makeText(MainActivity.this, "不能和自己聊天", Toast.LENGTH_SHORT).show();
- return;
- }
- // 跳转到聊天界面,开始聊天
- Intent intent = new Intent(MainActivity.this, ChatActivity.class);
- intent.putExtra("ec_chat_id", chatId);
- startActivity(intent);
- } else {
- Toast.makeText(MainActivity.this, "Username 不能为空", Toast.LENGTH_LONG).show();
- }
- }
- });
- mSignOutBtn = (Button) findViewById(R.id.ec_btn_sign_out);
- mSignOutBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- signOut();
- }
- });
- }
- /**
- * 退出登录
- */
- private void signOut() {
- // 调用sdk的退出登录方法,第一个参数表示是否解绑推送的token,没有使用推送或者被踢都要传false
- EMClient.getInstance().logout(false, new EMCallBack() {
- @Override
- public void onSuccess() {
- Log.i("lzan13", "logout success");
- // 调用退出成功,结束app
- finish();
- }
- @Override
- public void onError(int i, String s) {
- Log.i("lzan13", "logout error " + i + " - " + s);
- }
- @Override
- public void onProgress(int i, String s) {
- }
- });
- }
- }
- }
登录及注册界面
- package us.mifeng.guaju.huanxin;
- import android.app.Activity;
- import android.app.ProgressDialog;
- import android.content.Intent;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.Toast;
- import com.hyphenate.EMCallBack;
- import com.hyphenate.EMError;
- import com.hyphenate.chat.EMClient;
- import com.hyphenate.exceptions.HyphenateException;
- public class LoginActivity extends Activity {
- // 弹出框
- private ProgressDialog mDialog;
- // username 输入框
- private EditText mUsernameEdit;
- // 密码输入框
- private EditText mPasswordEdit;
- // 注册按钮
- private Button mSignUpBtn;
- // 登录按钮
- private Button mSignInBtn;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_login);
- initView();
- }
- /**
- * 初始化界面控件
- */
- private void initView() {
- mUsernameEdit = (EditText) findViewById(R.id.ec_edit_username);
- mPasswordEdit = (EditText) findViewById(R.id.ec_edit_password);
- mSignUpBtn = (Button) findViewById(R.id.ec_btn_sign_up);
- mSignUpBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- signUp();
- }
- });
- mSignInBtn = (Button) findViewById(R.id.ec_btn_sign_in);
- mSignInBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- signIn();
- }
- });
- }
- /**
- * 注册方法
- */
- private void signUp() {
- // 注册是耗时过程,所以要显示一个dialog来提示下用户
- mDialog = new ProgressDialog(this);
- mDialog.setMessage("注册中,请稍后...");
- mDialog.show();
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- String username = mUsernameEdit.getText().toString().trim();
- String password = mPasswordEdit.getText().toString().trim();
- EMClient.getInstance().createAccount(username, password);
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (!LoginActivity.this.isFinishing()) {
- mDialog.dismiss();
- }
- Toast.makeText(LoginActivity.this, "注册成功", Toast.LENGTH_LONG).show();
- }
- });
- } catch (final HyphenateException e) {
- e.printStackTrace();
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (!LoginActivity.this.isFinishing()) {
- mDialog.dismiss();
- }
- /**
- * 关于错误码可以参考官方api详细说明
- * http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1_e_m_error.html
- */
- int errorCode = e.getErrorCode();
- String message = e.getMessage();
- Log.d("lzan13", String.format("sign up - errorCode:%d, errorMsg:%s", errorCode, e.getMessage()));
- switch (errorCode) {
- // 网络错误
- case EMError.NETWORK_ERROR:
- Toast.makeText(LoginActivity.this, "网络错误 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
- break;
- // 用户已存在
- case EMError.USER_ALREADY_EXIST:
- Toast.makeText(LoginActivity.this, "用户已存在 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
- break;
- // 参数不合法,一般情况是username 使用了uuid导致,不能使用uuid注册
- case EMError.USER_ILLEGAL_ARGUMENT:
- Toast.makeText(LoginActivity.this, "参数不合法,一般情况是username 使用了uuid导致,不能使用uuid注册 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
- break;
- // 服务器未知错误
- case EMError.SERVER_UNKNOWN_ERROR:
- Toast.makeText(LoginActivity.this, "服务器未知错误 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
- break;
- case EMError.USER_REG_FAILED:
- Toast.makeText(LoginActivity.this, "账户注册失败 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
- break;
- default:
- Toast.makeText(LoginActivity.this, "ml_sign_up_failed code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
- break;
- }
- }
- });
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }).start();
- }
- /**
- * 登录方法
- */
- private void signIn() {
- mDialog = new ProgressDialog(this);
- mDialog.setMessage("正在登陆,请稍后...");
- mDialog.show();
- String username = mUsernameEdit.getText().toString().trim();
- String password = mPasswordEdit.getText().toString().trim();
- EMClient.getInstance().login(username, password, new EMCallBack() {
- /**
- * 登陆成功的回调
- */
- @Override
- public void onSuccess() {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mDialog.dismiss();
- // 加载所有会话到内存
- EMClient.getInstance().chatManager().loadAllConversations();
- // 加载所有群组到内存,如果使用了群组的话
- // EMClient.getInstance().groupManager().loadAllGroups();
- // 登录成功跳转界面
- Intent intent = new Intent(LoginActivity.this, MainActivity.class);
- startActivity(intent);
- finish();
- }
- });
- }
- /**
- * 登陆错误的回调
- * @param i
- * @param s
- */
- @Override
- public void onError(final int i, final String s) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mDialog.dismiss();
- Log.d("lzan13", "登录失败 Error code:" + i + ", message:" + s);
- /**
- * 关于错误码可以参考官方api详细说明
- * http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1_e_m_error.html
- */
- switch (i) {
- // 网络异常 2
- case EMError.NETWORK_ERROR:
- Toast.makeText(LoginActivity.this, "网络错误 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- // 无效的用户名 101
- case EMError.INVALID_USER_NAME:
- Toast.makeText(LoginActivity.this, "无效的用户名 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- // 无效的密码 102
- case EMError.INVALID_PASSWORD:
- Toast.makeText(LoginActivity.this, "无效的密码 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- // 用户认证失败,用户名或密码错误 202
- case EMError.USER_AUTHENTICATION_FAILED:
- Toast.makeText(LoginActivity.this, "用户认证失败,用户名或密码错误 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- // 用户不存在 204
- case EMError.USER_NOT_FOUND:
- Toast.makeText(LoginActivity.this, "用户不存在 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- // 无法访问到服务器 300
- case EMError.SERVER_NOT_REACHABLE:
- Toast.makeText(LoginActivity.this, "无法访问到服务器 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- // 等待服务器响应超时 301
- case EMError.SERVER_TIMEOUT:
- Toast.makeText(LoginActivity.this, "等待服务器响应超时 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- // 服务器繁忙 302
- case EMError.SERVER_BUSY:
- Toast.makeText(LoginActivity.this, "服务器繁忙 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- // 未知 Server 异常 303 一般断网会出现这个错误
- case EMError.SERVER_UNKNOWN_ERROR:
- Toast.makeText(LoginActivity.this, "未知的服务器异常 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- default:
- Toast.makeText(LoginActivity.this, "ml_sign_in_failed code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
- break;
- }
- }
- });
- }
- @Override
- public void onProgress(int i, String s) {
- }
- });
- }
- }
界面布局
界面的实现也是非常简单,这里直接贴一下:
activity_main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <EditText
- android:id="@+id/ec_edit_chat_id"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="对方的username"/>
- <Button
- android:id="@+id/ec_btn_start_chat"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="发起聊天"/>
- <Button
- android:id="@+id/ec_btn_sign_out"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="退出登录"/>
- </LinearLayout>
- </RelativeLayout>
activity_login.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <EditText
- android:id="@+id/ec_edit_username"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="username"/>
- <EditText
- android:id="@+id/ec_edit_password"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="password"/>
- <Button
- android:id="@+id/ec_btn_sign_up"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="注册"/>
- <Button
- android:id="@+id/ec_btn_sign_in"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="登录"/>
- </LinearLayout>
- </RelativeLayout>
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- >
- <!--输入框-->
- <RelativeLayout
- android:id="@+id/ec_layout_input"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true">
- <Button
- android:id="@+id/ec_btn_send"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:text="Send"/>
- <EditText
- android:id="@+id/ec_edit_message_input"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@id/ec_btn_send"/>
- </RelativeLayout>
- <!--展示消息内容-->
- <TextView
- android:id="@+id/ec_text_content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_above="@id/ec_layout_input"
- android:maxLines="15"
- android:scrollbars="vertical"/>
- </RelativeLayout>
我是分割线-------------------------------------------------
补上ChatActivity的代码
- package us.mifeng.guaju.huanxin;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.support.v7.app.AppCompatActivity;
- import android.text.TextUtils;
- import android.text.method.ScrollingMovementMethod;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
- import com.hyphenate.EMCallBack;
- import com.hyphenate.EMMessageListener;
- import com.hyphenate.chat.EMClient;
- import com.hyphenate.chat.EMCmdMessageBody;
- import com.hyphenate.chat.EMConversation;
- import com.hyphenate.chat.EMMessage;
- import com.hyphenate.chat.EMTextMessageBody;
- import java.util.List;
- /**
- * Created by guaju on 2016/9/12.
- */
- public class ChatActivity extends AppCompatActivity implements EMMessageListener {
- // 聊天信息输入框
- private EditText mInputEdit;
- // 发送按钮
- private Button mSendBtn;
- // 显示内容的 TextView
- private TextView mContentText;
- // 消息监听器
- private EMMessageListener mMessageListener;
- // 当前聊天的 ID
- private String mChatId;
- // 当前会话对象
- private EMConversation mConversation;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_chat);
- // 获取当前会话的username(如果是群聊就是群id)
- mChatId = getIntent().getStringExtra("ec_chat_id");
- mMessageListener = this;
- initView();
- initConversation();
- }
- /**
- * 初始化界面
- */
- private void initView() {
- mInputEdit = (EditText) findViewById(R.id.ec_edit_message_input);
- mSendBtn = (Button) findViewById(R.id.ec_btn_send);
- mContentText = (TextView) findViewById(R.id.ec_text_content);
- // 设置textview可滚动,需配合xml布局设置
- mContentText.setMovementMethod(new ScrollingMovementMethod());
- // 设置发送按钮的点击事件
- mSendBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- String content = mInputEdit.getText().toString().trim();
- if (!TextUtils.isEmpty(content)) {
- mInputEdit.setText("");
- // 创建一条新消息,第一个参数为消息内容,第二个为接受者username
- EMMessage message = EMMessage.createTxtSendMessage(content, mChatId);
- // 将新的消息内容和时间加入到下边
- mContentText.setText(mContentText.getText() + "\n" + content + " -> " + message.getMsgTime());
- // 调用发送消息的方法
- EMClient.getInstance().chatManager().sendMessage(message);
- // 为消息设置回调
- message.setMessageStatusCallback(new EMCallBack() {
- @Override
- public void onSuccess() {
- // 消息发送成功,打印下日志,正常操作应该去刷新ui
- Log.i("lzan13", "send message on success");
- }
- @Override
- public void onError(int i, String s) {
- // 消息发送失败,打印下失败的信息,正常操作应该去刷新ui
- Log.i("lzan13", "send message on error " + i + " - " + s);
- }
- @Override
- public void onProgress(int i, String s) {
- // 消息发送进度,一般只有在发送图片和文件等消息才会有回调,txt不回调
- }
- });
- }
- }
- });
- }
- /**
- * 初始化会话对象,并且根据需要加载更多消息
- */
- private void initConversation() {
- /**
- * 初始化会话对象,这里有三个参数么,
- * 第一个表示会话的当前聊天的 useranme 或者 groupid
- * 第二个是绘画类型可以为空
- * 第三个表示如果会话不存在是否创建
- */
- mConversation = EMClient.getInstance().chatManager().getConversation(mChatId, null, true);
- // 设置当前会话未读数为 0
- mConversation.markAllMessagesAsRead();
- int count = mConversation.getAllMessages().size();
- if (count < mConversation.getAllMsgCount() && count < 20) {
- // 获取已经在列表中的最上边的一条消息id
- String msgId = mConversation.getAllMessages().get(0).getMsgId();
- // 分页加载更多消息,需要传递已经加载的消息的最上边一条消息的id,以及需要加载的消息的条数
- mConversation.loadMoreMsgFromDB(msgId, 20 - count);
- }
- // 打开聊天界面获取最后一条消息内容并显示
- if (mConversation.getAllMessages().size() > 0) {
- EMMessage messge = mConversation.getLastMessage();
- EMTextMessageBody body = (EMTextMessageBody) messge.getBody();
- // 将消息内容和时间显示出来
- mContentText.setText(body.getMessage() + " - " + mConversation.getLastMessage().getMsgTime());
- }
- }
- /**
- * 自定义实现Handler,主要用于刷新UI操作
- */
- Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case 0:
- EMMessage message = (EMMessage) msg.obj;
- // 这里只是简单的demo,也只是测试文字消息的收发,所以直接将body转为EMTextMessageBody去获取内容
- EMTextMessageBody body = (EMTextMessageBody) message.getBody();
- // 将新的消息内容和时间加入到下边
- mContentText.setText(mContentText.getText() + "\n" + body.getMessage() + " <- " + message.getMsgTime());
- break;
- }
- }
- };
- @Override
- protected void onResume() {
- super.onResume();
- // 添加消息监听
- EMClient.getInstance().chatManager().addMessageListener(mMessageListener);
- }
- @Override
- protected void onStop() {
- super.onStop();
- // 移除消息监听
- EMClient.getInstance().chatManager().removeMessageListener(mMessageListener);
- }
- /**
- * --------------------------------- Message Listener -------------------------------------
- * 环信消息监听主要方法
- */
- /**
- * 收到新消息
- *
- * @param list 收到的新消息集合
- */
- @Override
- public void onMessageReceived(List<EMMessage> list) {
- // 循环遍历当前收到的消息
- for (EMMessage message : list) {
- if (message.getFrom().equals(mChatId)) {
- // 设置消息为已读
- mConversation.markMessageAsRead(message.getMsgId());
- // 因为消息监听回调这里是非ui线程,所以要用handler去更新ui
- Message msg = mHandler.obtainMessage();
- msg.what = 0;
- msg.obj = message;
- mHandler.sendMessage(msg);
- } else {
- // 如果消息不是当前会话的消息发送通知栏通知
- }
- }
- }
- /**
- * 收到新的 CMD 消息
- *
- * @param list
- */
- @Override
- public void onCmdMessageReceived(List<EMMessage> list) {
- for (int i = 0; i < list.size(); i++) {
- // 透传消息
- EMMessage cmdMessage = list.get(i);
- EMCmdMessageBody body = (EMCmdMessageBody) cmdMessage.getBody();
- Log.i("lzan13", body.action());
- }
- }
- /**
- * 收到新的已读回执
- *
- * @param list 收到消息已读回执
- */
- @Override
- public void onMessageReadAckReceived(List<EMMessage> list) {
- }
- /**
- * 收到新的发送回执
- * TODO 无效 暂时有bug
- *
- * @param list 收到发送回执的消息集合
- */
- @Override
- public void onMessageDeliveryAckReceived(List<EMMessage> list) {
- }
- /**
- * 消息的状态改变
- *
- * @param message 发生改变的消息
- * @param object 包含改变的消息
- */
- @Override
- public void onMessageChanged(EMMessage message, Object object) {
- }
- }
- android集成环信步骤
- 最新Android集成环信步骤详解
- Android微信支付集成步骤
- android微信支付集成步骤
- Android 集成微信支付步骤详解
- iOS 环信UI集成步骤
- 环信3.0版本的集成步骤
- Android微信登录以及分享集成步骤
- Android微信登录以及分享集成步骤
- android集成环信流程
- Android 环信集成 fileuriexposedexception
- android studio集成环信
- Android 集成环信EaseUI
- iOS开发:环信集成步骤以及常见错误
- 环信Android客户端集成文档
- Android使用EaseUI集成环信3.0
- Android环信EaseUI的快速集成
- 环信IM集成到android项目
- yii-模板继承
- 生产环境使用kubernetes的经验
- qemu介绍、编译及使用简介
- EasyDarwin开源云平台接入海康威视EasyCamera摄像机之快照获取与上传
- EditText支持Search按键搜索
- android集成环信步骤
- MFC下SOCKET编程
- 假期作业:翔鹰帝国第12届火箭筒杯
- xcode 8 新功能:检测线程竞态,很棒的功能,文章也写的很好,推荐给大家
- 导入到android studio的项目不能运行
- UVA 1374 Power Calculus(IDA*)
- C++中的bitset类型
- c++的类的内存布局
- gradle编译脚本需要重新下载gradle问题