1. 程式人生 > >環信即時通訊整合過程

環信即時通訊整合過程

最近一直挺忙,使用了一些第三方的東西,也遇見了不少的問題,前面使用的一些還好,比如推送,分享這些第三方都比較容易整合,這次整合環信的即時通訊還是費了一些周折,剛弄完,趕緊記錄一下。

一.前期需要注意的地方

總的來說環信的開發文件和SDK做的已經很簡單了,但是畢竟是第一次整合,使用別人的東西難免有點摸不著頭。這次使用環信3.0版本來整合。基本上前面的操作都可以按著文件的說明進行了,這裡感覺新增sdk前需要注意幾個地方。

1.先對文件進行一個全面的閱讀

我剛開始在做其他的第三方整合時也很著急,想著怎麼趕緊找到一個入口。最後發現著急沒用,所以先閱讀以下文件,知道自己需要的功能大體怎麼處理,需要整合哪一些jar包等。這次我開始就沒有注意,閱讀文件時就把獨立的sdk的jar和so包都複製到了專案中,最後發現,有一個更好用一些的東西EaseUI 這個module,直接匯入這個module就可以不用再去新增各種jar和so檔案了。所以,我們有一個整體的把握很重要。

2.瞭解easeUI包

easeUI這個包下包含了好些jar還有百度地圖的包,在【Android SDK 介紹和匯入】這個地方說明的包基本都是這裡的。


瞭解這些方便我們處理後邊的衝突等問題。比如我的專案之前放入了百度sdk的jar,這裡也有,但是版本不同可能引發問題,也可能由於重複引入jar導致問題。

二.新增整合

1.整合easeUI

我使用了easeUI這個module直接整合的,這樣我們可以使用環信提供的一些UI,比如EaseChatFragment ,這是一個聊天介面,一般來說自己處理這個頁面還是有一些困難或者問題。整合出現的問題。


這個也是官方提出的,首先我們要處理這個,我覺得還是把這個module的v4包版本號增加大這個方式好一些,例如使用:把 v4 包的版本號加大,譬如 compile 'com.android.support:support-v4:23.2.1這樣編譯就可以了。下面就是按照文件找到自己需要的API集成了。從註冊,到登入,然後獲取好友列等操作

2.API整合出現的問題

1).一些異常比如出現:unknow server exception(異常資訊沒有截圖),這個問題其實是我們沒有按照文件說明去做,

//群主加人呼叫此方法

EMClient.getInstance().groupManager().addUsersToGroup(groupId, newmembers);//需非同步處理

上面介面說了使用非同步處理,我沒有使用非同步也就出現了異常。

2).

3.使用easeUI

我們在環信註冊了使用者之後就會有一個環信的id,通過這個id我們就可以和對方進行簡答的通訊了。使用EaseChatFragment。

按照文件說明建立一個Activity,然後寫一下的程式碼:

EaseChatFragment chatFragment = new EaseChatFragment();

        Bundle args = new Bundle();

        args.putInt(EaseConstant.EXTRA_CHAT_TYPE, EaseConstant.CHATTYPE_SINGLE);

        args.putString(EaseConstant.EXTRA_USER_ID, getIntent().getStringExtra("userID"));

        chatFragment.setArguments(args);

        FragmentManager supportFragmentManager = getSupportFragmentManager();

        getSupportFragmentManager().beginTransaction().add(R.id.container, chatFragment).commit();

//container是你建立的activity的根佈局的id


 /**

     * 發起聊天 這個是從MainActivty或者其他頁面發起聊天,傳入一個你註冊的環信id

     * @param input

     */

    private void startChat(String input) {

        //new出EaseChatFragment或其子類的例項

        if(!TextUtils.isEmpty(input)){

            Intent intent = new Intent(MainActivity.this, ChatActivity.class);

            intent.putExtra("userID",input);

            startActivity(intent);

        }else{

            Toast.makeText(this, "請輸入一個使用者id", Toast.LENGTH_SHORT).show();

        }

    }

完成上述的註冊,登入和EaseChatFragment後通訊功能基本上就可以實現了。如圖:


到此環信的整合主要功能也就是完成的,其他的可能會用到聊天列表,通訊錄這些按照文件整合就可以,不過環信不對通訊錄進行維護,也就是說要是儲存使用者資訊什麼的東西,需要我們自己的伺服器來儲存,然後在使用時根據環信id去伺服器獲取這個使用者的其他資訊。

4.修改使用者頭像和使用者名稱

上面的那個圖我們看到了使用者頭像是預設的沒有圖片,這個怎麼處理?環信只是給出了一個思路,demo中有實現的邏輯,但是找出來還是不太容易。

環信給出的兩個方案:

1).從app伺服器獲取使用者資料頭像

2).從訊息擴充套件中獲取使用者資料

最後我選了第二重方案,我也不知道怎麼就選了第二種方法,剛開始對這個問題很暈,沒有一點思路,在網上找了幾個相關的,所以兩個方法弄的有點暈,然後就沒辦法,按照一個方式嘗試,最後逐漸明白,其實這個方式相對來聽容易實現,就是要知道從什麼地方下手。看看最後結果如圖:

圖片中已經有了頭像了。

我們在使用整合的過程中可能需要對EaseChatFragment進行一個重寫,就像上圖圖右上角是一個垃圾桶圖示,我們自己需要一個點選進入使用者資訊的頁面,所以從寫這個EaseChatFragment的一個方法:

 @Override

    protected void setUpView() {

        super.setUpView();

        //messageList.init(toChatUsername, chatType, new CustomChatRowProvider());//messageList初始化??

        titleBar.setRightImageResource(R.mipmap.user);

        titleBar.getRightLayout().setOnClickListener(new View.OnClickListener() {//處理點選

            @Override

            public void onClick(View v) {

                if (chatType == EaseConstant.CHATTYPE_GROUP ) {//群聊,傳遞當前的 emGroup

                    Intent intent = new Intent(getActivity(), IMDiscussInfoActivity.class);//群組,需要一個id

                    intent.putExtra("conversationID", toChatUsername);

                    startActivity(intent);

                } else{// 單聊EaseConstant.CHATTYPE_SINGLE

                    Intent intent = new Intent(getActivity(), IMPersonalInfoActivity.class);//個人

                    intent.putExtra("conversationID", toChatUsername);//回話id就是手機號碼

                    startActivity(intent);

                }

            }

        });

    }

我們在 EaseChatFragment找上述方法重寫的過程可能會發現有一個介面:EaseChatFragmentHelper,如果你有了這個印象後邊可能就容易了,網上的其他資料讓你能快速想起來然後處理他。這個介面就是文件說的傳送擴擴充套件訊息要使用的,所以按照文件說明從寫介面的方法:

 /**

     * 實現EaseChatFragmentHelper介面方法

     * 希望通過設定附加訊息實現頭像傳遞

     * @param message

     */

    @Override

    public void onSetMessageAttributes(EMMessage message) {

        //傳送訊息時附加引數p

        LogUtils.e("TAG","onSetMessageAttributes");

        Preferences preferences = new Preferences(getActivity());

        message.setAttribute(ConstantValue.IM_USER_ID, preferences.getUserPhoneNumber());//標識使用者的手機號

        message.setAttribute(ConstantValue.IM_NICK_NAME, preferences.getUserName());

        message.setAttribute(ConstantValue.IM_USER_IMAGE, preferences.getString("userImage")) ;

        //這裡用是圖片的完整連結地址,如果要取縮圖,需要服務端配合;

        LogUtils.e("TAG","fasong使用者頭像:"+preferences.getString("userImage"));

    }


寫完不要忘記了在你的這個Fragment中在重寫一個方法比如:onCreate().因為我們要註冊這個介面的實現。

@Override

    public void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setChatFragmentListener(this);//註冊介面,EaseChatFragment提供的方法

    }

這樣看,基本上完成了擴充套件訊息的傳送。接下來就是訊息的接收和儲存了。

在最初閱讀文件按照步驟做的時候有沒有注意到demo的Application中註冊了這樣一句:

 //init demo helper

 DemoHelper.getInstance().init(applicationContext);

文件說我們要這樣註冊:

EMOptions options = new EMOptions();

// 預設新增好友時,是不需要驗證的,改成需要驗證

options.setAcceptInvitationAlways(false);

...

//初始化

EMClient.getInstance().init(applicationContext, options);

//在做打包混淆時,關閉debug模式,避免消耗不必要的資源

EMClient.getInstance().setDebugMode(true);

這就導致了我當初沒有看清楚demo中的那句話。現在我們點選進去看看:

/**
 * init helper
 * @param context application context
 */
public void init(Context context) {
    demoModel = new DemoModel(context);
    EMOptions options = initChatOptions();
    //use default options if options is null
if (EaseUI.getInstance().init(context, options)) {
       appContext = context;
       //debug mode, you'd better set it to false, if you want release your App officially.
EMClient.getInstance().setDebugMode(true);
       //get easeui instance
easeUI = EaseUI.getInstance();
       //to set user's profile and avatar
setEaseUIProviders();
      //initialize preference manager
PreferenceManager.init(context);
      //initialize profile manager
getUserProfileManager().init(context);

      // TODO: set Call options 此處省略中間若干剛...

       setGlobalListeners();
      //broadcastManager = LocalBroadcastManager.getInstance(appContext);
       // initDbDao();
   }
}

這裡完成了我們的註冊和其他的操作。

這裡我們需要知道的就是除了EaseUI註冊的那幾行之外的程式碼:

setEaseUIProviders();

setGlobalListeners();

下面是我修改後的專案中的程式碼:

 *

     * @param context application context

     */

    public void init(Context context) {

        //demoModel = new DemoModel(context);

        EMOptions options = new EMOptions();

        options.setAcceptInvitationAlways(false);//新增好友不需要驗證

        //use default options if options is null

        if (EaseUI.getInstance().init(context, options)) {

            appContext = context;

            //debug mode, you'd better set it to false, if you want release your App officially.

            EMClient.getInstance().setDebugMode(true);

            //get easeui instance

            easeUI = EaseUI.getInstance();

            //to set user's profile and avatar

            preferences = new Preferences(context);

            setEaseUIProviders();

        }

    }


對比發現除了註冊的之外關鍵的就是

setEaseUIProviders();這句話

你可以自己在demo中看看這,其實最主要的就是他。進入這個方法發現有一段程式碼:

easeUI.setUserProfileProvider(new EaseUserProfileProvider() {
    
    @Override
public EaseUser getUser(String username) {
        return getUserInfo(username);
    }
});
突然明白了getUserInfo(username)就是返回最後使用者訊息的那個方法,他返回一個EaseUser物件。我重寫後的getUserInfo(username)如下:

private EaseUser getUserInfo(String username) {

        EaseUser user = null;

        if (username.equals(EMClient.getInstance().getCurrentUser())) {

            //如果使用者是本人,就設定自己的頭像

            user = new EaseUser(username);

            user.setAvatar(preferences.getString(ConstantValue.USER_IMAGE));

            user.setNick(preferences.getUserName());

            return user;

        }else if(!username.equals(EMClient.getInstance().getCurrentUser())){

            DbManager dbManager = x.getDb(MainApplication.getInstance().initDB());

            try {

                IMContract imContract = dbManager.findById(IMContract.class, username);

                if(imContract!=null){

                    LogUtils.e(TAG,"資料庫查詢結果:"+imContract.getContraactPhone());

                    user = new EaseUser(username);

                    user.setAvatar(imContract.getImageUrl());

                    user.setNick(imContract.getNickName());

                    return user;

                }

            } catch (DbException e) {

                e.printStackTrace();

            }

        }

這個方法給EaseUser物件賦值了。這裡還有一點沒有說明。前面在

EaseChatFragmentHelper 介面中添加了擴充套件訊息,我們還沒有取出來呢。

現在看看環信demo中和我寫的不一樣的地方:就是有一個

setGlobalListeners();

這個方法,這個就是環信接收訊息的地方。當時點選進去發現一大片。我們在這個方法的最後發現了這麼一句:

registerMessageListener();

這才是真正接收訊息的地方。在回憶一下當初看文件的時候,在訊息這個模組中有這個藉口:

EMClient.getInstance().chatManager().addMessageListener(msgListener);

EMMessageListener msgListener = new EMMessageListener(){...}

現在需要做的就是在這裡實現介面方法,我研究後重寫的:

@Override

        public void onMessageReceived(List<EMMessage> list) {

            LogUtils.e(TAG, "onMessageReceived執行訊息監聽..");

            receivedListener.onMessageReceived(list);

            for (EMMessage message : list) {//儲存下資料

                String chatUserId = message.getStringAttribute(ConstantValue.IM_USER_ID, "");

                String avatarUrl = message.getStringAttribute(ConstantValue.IM_USER_IMAGE, "");

                String nickName = message.getStringAttribute(ConstantValue.IM_NICK_NAME, "");

                LogUtils.e("TAG", "appjieshou訊息獲取的資料是chatUserId:" + chatUserId);

                DbManager db = x.getDb(initDB());

                IMContract imContract = new IMContract();

                imContract.setContraactPhone(chatUserId);

                imContract.setImageUrl(avatarUrl);

                imContract.setNickName(nickName);

                try {

                    db.saveOrUpdate(imContract);

                } catch (DbException e) {

                    e.printStackTrace();

                    LogUtils.e(TAG,"資料庫操作異常:"+e.getMessage());

                }

                ChatHelper.getInstance().getNotifier().onNewMsg(message);

            }

        }

這裡獲取當初傳送的訊息並儲存在資料庫中,就好了,我們在使用的時候根據環信的id去查資料庫就可以拿到使用者資訊了。這裡我使用的是xUtils3中的資料庫操作。

ChatHelper.getInstance().getNotifier().onNewMsg(message);//ChatHelper就是demo中的DemoHelper這個是接收到訊息後傳送一個通知的.

現在回到前面的getUserInfo(username)方法中,可以看到這裡只是根據username進行了資料庫查詢,然後返回一個EsaseUser物件。這樣我們就完成了使用者頭像和其他資訊的傳遞。在一次聊天就會發現有頭像和使用者名稱資訊了。

這裡需要注意,頭像這裡直接傳遞一個圖片的url就好了,環信已經封裝好了對他的處理。

如果你在研究的過程發現了EaseUserUtils這個你就知道了:

/**
 * set user avatar
 * @param username
*/
public static void setUserAvatar(Context context, String username, ImageView imageView){
    Log.e("TAG","setUserAvatar設定頭像返回:"+username);
   EaseUser user = getUserInfo(username);
    if(user != null && user.getAvatar() != null){
        try {
            int avatarResId = Integer.parseInt(user.getAvatar());
            Glide.with(context).load(avatarResId).into(imageView);
        } catch (Exception e) {
            //use default avatar
Glide.with(context).load(user.getAvatar()).diskCacheStrategy(DiskCacheStrategy.ALL).placeholder(R.drawable.ease_default_avatar).into(imageView);
        }
    }else{
        Glide.with(context).load(R.drawable.ease_default_avatar).into(imageView);
    }
}

可以看到在這裡使用了Glide來載入圖片,沒有圖片的url時使用本地的這個替代。


參考資料:

1..http://www.cnblogs.com/zhang-cb/p/6292254.html