1. 程式人生 > >android studio如何快速整合環信EaseUI

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" />