環信即時通訊集成過程

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

一.前期需要注意的地方

總的來說環信的開發文檔和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

2.http://www.imgeek.org/article/825307856




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章