android studio如何快速整合環信EaseUI
最近專案中要使用即時通訊,為什麼會選環信呢,這是因為之前負責這一塊的那位兄弟跟老闆說這是免費的,老闆一聽免費的,好,就它了,後來這位兄弟跑路了,就讓我來接手了.....,無力吐槽,廢話不多說,我們開始吧。
下面我就來分享一下我在整合環信EaseUi中遇到的問題。
ps:官方的文件說的不是很明白,一不小心就會掉進坑裡,切記切記........
1.註冊環信並建立應用,建立好了之後會生成AppKey,先記下來待會我們會在 AndroidManifast.xml 中要用到
2.下載SDK
我們選擇 SDK+Demo 原始碼下載
下載解壓之後會得到這幾個資料夾
官方對這幾個資料夾的解釋是這樣的
因為我們是整合EaseUI,所以我們要用到examples資料夾下的easeui這個資料夾,EaseUI是一個庫,裡面封裝了 IM 功能常用的控制元件,fragment等等
3.匯入easeui
注意:匯入AS中的時候要把build.gradle檔案刪除
開啟你的 AS 專案→File→New→Import Module→選擇或輸入 EaseUI 庫路徑
easyui資料夾裡面有兩個檔案,simpledemo裡面是個可執行的專案,咱們只用easeui庫,選中之後點選 Finish
匯入成功之後我們還需要將easeui同步到我們專案當中去,在專案上右鍵,Open Module Settings
4.配置資訊
在檔案 AndroidManifest.xml 里加入以下許可權,以及寫上你註冊的 AppKey
<?xml version="1.0" encoding="utf-8"?> <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>
5.初始化EaseUI
我們需要在專案最開始執行的時候對其進行初始化,所以要寫在appication裡(注意不要忘記去AndroidManifests檔案中註冊)
public class MyApp extends Application {
private static final String TAG = "MyApp";
private static MyApp myApp;
// 記錄是否已經初始化
private boolean isInit = false;
@Override
public void onCreate() {
super.onCreate();
myApp = this;
// 初始化環信SDK
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(myApp.getPackageName())) {
Log.e(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(this, options);
// 設定開啟debug模式
EMClient.getInstance().setDebugMode(true);
// 設定初始化已經完成
isInit = true;
}
private String getAppName(int pID) {
String processName = null;
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List l = am.getRunningAppProcesses();
Iterator i = l.iterator();
PackageManager pm = this.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;
}
public static MyApp getInstance() {
return myApp;
}
}
1.建立登入和註冊頁面,這個自行建立,下面是我寫的Demo(必須登入,否則無法聊天)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="15dp"
android:orientation="vertical"
tools:context="com.meris.em_master.pojo.ui.ECLoginActivity">
<EditText
android:hint="賬號"
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:hint="密碼"
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:text="註冊"
android:id="@+id/register"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:text="登入"
android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
2.註冊的方法,這裡需要注意的是這步是非同步操作,所以我們需要把它寫在子執行緒中
public void register() {
new Thread(new Runnable() {
@Override
public void run() {
try {
EMClient.getInstance().createAccount(mName.getText().toString().trim(), mPwd.getText().toString().trim());
ToastUtils.showLong("註冊成功,使用者名稱是:" + mName.getText().toString() + " 快開始聊天吧");
} catch (final HyphenateException e) {
e.printStackTrace();
/**
* 關於錯誤碼可以參考官方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();
switch (errorCode) {
case EMError.NETWORK_ERROR:
ToastUtils.showLong("網路異常,請檢查網路! code: " + errorCode + ",message: " + message);
break;
case EMError.USER_ALREADY_EXIST:
ToastUtils.showLong("使用者名稱已存在,請嘗試登入! code: " + errorCode + ",message: " + message);
break;
case EMError.USER_ALREADY_LOGIN:
ToastUtils.showLong("使用者已登入! code: " + errorCode + ",message: " + message);
break;
case EMError.USER_AUTHENTICATION_FAILED:
ToastUtils.showLong("使用者id或密碼錯誤! code: " + errorCode + ",message: " + message);
break;
case EMError.SERVER_UNKNOWN_ERROR:
ToastUtils.showLong("伺服器位置錯誤! code: " + errorCode + ",message: " + message);
break;
case EMError.USER_REG_FAILED:
ToastUtils.showLong("註冊失敗! code: " + errorCode + ",message: " + message);
break;
default:
ToastUtils.showLong("ml_sign_up_failed code: " + errorCode + ",message: " + message);
break;
}
}
}
}).start();
}
public void login() {
EMClient.getInstance().login(mName.getText().toString(), mPwd.getText().toString(), new EMCallBack() {
@Override
public void onSuccess() {
// 載入所有群組到記憶體,如果使用了群組的話
// EMClient.getInstance().groupManager().loadAllGroups();
// 載入所有會話到記憶體
EMClient.getInstance().chatManager().loadAllConversations();
ToastUtils.showLong("登入,成功開始聊天吧");
ECMainActivity.show(mContext);
finish();
}
@Override
public void onError(final int i, final String s) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDialog.dismiss();
ToastUtils.showLong("登入失敗 code: " + i + ",message: " + s);
switch (i) {
case EMError.NETWORK_ERROR:
ToastUtils.showLong("網路異常,請檢查網路! code: " + i + ",message: " + s);
break;
case EMError.INVALID_USER_NAME:
ToastUtils.showLong("無效使用者名稱! code: " + i + ",message: " + s);
break;
case EMError.INVALID_PASSWORD:
ToastUtils.showLong("使用者密碼不正確! code: " + i + ",message: " + s);
break;
case EMError.USER_AUTHENTICATION_FAILED:
ToastUtils.showLong("使用者名稱或密碼不正確! code: " + i + ",message: " + s);
break;
case EMError.USER_NOT_FOUND:
ToastUtils.showLong("使用者不存在! code: " + i + ",message: " + s);
break;
case EMError.SERVER_NOT_REACHABLE:
ToastUtils.showLong("無法連線到伺服器! code: " + i + ",message: " + s);
break;
case EMError.SERVER_BUSY:
ToastUtils.showLong("伺服器繁忙,請稍後.... code: " + i + ",message: " + s);
break;
case EMError.SERVER_TIMEOUT:
ToastUtils.showLong("等待伺服器響應超時! code: " + i + ",message: " + s);
break;
case EMError.SERVER_UNKNOWN_ERROR:
ToastUtils.showLong("未知伺服器錯誤! code: " + i + ",message: " + s);
break;
case EMError.USER_ALREADY_LOGIN:
ToastUtils.showLong("使用者已登入! code: " + i + ",message: " + s);
break;
}
}
});
}
@Override
public void onProgress(int i, String s) {
}
});
}
3.退出登入方法,哪裡需要寫哪裡
public void logOut() {
EMClient.getInstance().logout(false, new EMCallBack() {
@Override
public void onSuccess() {
LogUtils.d("logout success");
finish();
}
@Override
public void onError(int i, String s) {
LogUtils.d("logout error" + i + s);
}
@Override
public void onProgress(int i, String s) {
}
});
}
4.環信聊天頁面
public class ChatActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.chat1);
EaseChatFragment easeChatFragment = new EaseChatFragment(); //環信聊天介面
easeChatFragment.setArguments(getIntent().getExtras()); //需要的引數
getSupportFragmentManager().beginTransaction().add(R.id.layout_chat,easeChatFragment).commit(); //Fragment切換
}
}
5.環信聊天頁面佈局檔案
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/layout_chat"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
6.啟動會話列表
public class ChatListActivity extends AppCompatActivity {
private static EMMessageListener emMessageListener;
private EaseConversationListFragment conversationFragment;
public static void show(Context context) {
Intent intent = new Intent(context, ChatListActivity.class);
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_list_activity);
initView();
}
public void initView() {
conversationFragment = new EaseConversationListFragment();
getSupportFragmentManager().beginTransaction().add(R.id.chat_list,conversationFragment).commit();
conversationFragment.setConversationListItemClickListener(new EaseConversationListFragment.EaseConversationListItemClickListener() {
@Override
public void onListItemClicked(EMConversation conversation) {
startActivity(new Intent(ChatListActivity.this, ChatActivity.class).putExtra(EaseConstant.EXTRA_USER_ID,conversation.conversationId()));
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
EMClient.getInstance().chatManager().removeMessageListener(emMessageListener);
}
}
7.會話列表佈局檔案
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/chat_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
8.圓形頭像
easeui 庫中設定圓形頭像的類如下圖:
EaseuserUtils這個類相當重要 這裡邊 有 設定頭像 設定暱稱 等方法 其用的正好是Glide圖片載入框架
在EaseuserUtils這個類里加入一個內部類處理頭像:
/**
* Glide圓形頭像轉換 內部類
*/
private static class GlideCircleTransform extends BitmapTransformation {
private GlideCircleTransform(Context context) {
super(context);
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return circleCrop(pool, toTransform);
}
private Bitmap circleCrop(BitmapPool pool, Bitmap source) {
if (source == null) return null;
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
// TODO this could be acquired from the pool too
Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
if (result == null) {
result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
return result;
}
@Override
public String getId() {
return getClass().getName();
}
}
檢視大圖奔潰和地圖,在androidManifest.xml中加入以下,百度地圖的API_KEY可以自己去申請
<!--點選檢視大圖崩潰-->
<activity
android:name="com.hyphenate.easeui.ui.EaseShowBigImageActivity"
android:screenOrientation="portrait"
android:theme="@style/horizontal_slide" />
<!-- 地圖 -->
<activity
android:name="com.hyphenate.easeui.ui.EaseBaiduMapActivity"
android:screenOrientation="portrait"
android:theme="@style/horizontal_slide" />
<!-- 百度地圖所需的service -->
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" />
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="3ecea51f560650b1ed8a4b99808f52e8" />