Android IM之基於Openfire+Smack的聊天伺服器的搭建與測試

來源:互聯網
上載者:User

Android IM之基於Openfire+Smack的聊天伺服器的搭建與測試

XMPP協議(Extensible Messaging and PresenceProtocol,可擴充訊息處理現場協議)是一種基於XML的協議,目的是為瞭解決及時通訊標準而提出來的,最早是在Jabber上實現的。它繼承了在XML環境中靈活的發展性。因此,基於XMPP的應用具有超強的可擴充性。並且XML很易穿過防火牆,所以用XMPP構建的應用不易受到防火牆的阻礙。利用XMPP作為通用的傳輸機制,不同組織內的不同應用都可以進行有效通訊。

先來瞭解幾個概念

Openfire主要是作為伺服器,負責管理用戶端的通訊串連,以及提供用戶端一些通訊資訊和串連資訊。

Smack主要是xmpp協議的實現,提供了一套很好的api,所以下面操作xmpp都是通過使用Smack的api來實現,從4.1.0開始,它就支援Android了,所以我們直接使用Smack即可,當然在這不支援之前是使用Asmack這個包的,裡面方法跟smack包差不多。

Spark 是IM用戶端的實現,其實就是使用了Smack 的api實現的。

 

第二個是一套基於XMPP實現的API,我們直接引用其即可,在Android Studio中,我們直接在gradle中添加依賴即可。

    compile 'org.igniterealtime.smack:smack-android-extensions:4.1.4'    compile 'org.igniterealtime.smack:smack-tcp:4.1.4'

然後我們需要添加網路許可權

    

接下來我們先不管android端,我們先進行兩個軟體的安裝。首先安裝openfire.

點擊安裝包開啟進行初始化

選擇語言,這裡選擇中文

確定後再點下一步

同意許可點擊下一步

選擇安裝目錄點擊下一步,這裡是預設目錄

繼續下一步

耐心等待檔案解壓完成

點擊完成後運行Openfire

運行成功後點擊Launch Admin進入後台完成剩下的安裝工作

選擇語言


伺服器配置,我們將域修改為原生區域網路IP地址

我們需要獲得我們電腦的IP地址。

獲得的IP地址為10.0.0.24,將域修改為這個值

資料庫我們選擇使用外部資料庫,所以勾選第一個

接下來就是一些值,第一項的下拉選擇mysql,之後值會被填充。接下來我們就需要在mysql中添加一個資料庫。

這裡假設你的本地有mysql伺服器,開啟後台,添加一個使用者,勾選建立與使用者名稱同名的資料庫並授予所有許可權

把database name和hostname修改成對應的值,使用者名稱和密碼為你剛才mysql中建立的使用者和密碼

選擇初始設定

設定openfire管理員帳號密碼,這裡帳號設定為admin,密碼自己設定

點擊登入到管理主控台

進入到後台,輸入帳號密碼進行登陸

登陸成功後就是後台了

然後安裝Spark,點擊下載的安裝包

選擇安裝目錄

點擊下一步

繼續點擊下一步

等待安裝完成

點擊finish運行spark

使用我們的管理員帳號admin進行登陸,伺服器為本地,127.0.0.1

如果登陸成功了就會出現下面的介面

然後我們添加兩個測試帳號,在openfire後台,輸入這些資訊進行添加使用者

添加了兩個測試帳號,分別為test和test1

接下來最重要的事就是Android端了,在這之前,我們需要讓我們的手機和電腦出於同一個區域網路內,如果你使用的是模擬器,那麼,不存在這個問題。

獲得的IP地址為10.0.0.24,接下來就是編寫代碼進行登陸了。

獲得一個串連

 private XMPPTCPConnection getConnection(){        String server=10.0.0.24;        int port=5222;        XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();        builder.setServiceName(server);        builder.setHost(server);        builder.setPort(port);        builder.setCompressionEnabled(false);        builder.setDebuggerEnabled(true);        builder.setSendPresence(true);        builder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);        XMPPTCPConnection connection = new XMPPTCPConnection(builder.build());        return connection;    }

初始設定變數

private EditText account, password,to,content;private Button login,logout,send;private  XMPPTCPConnection connection;connection=getConnection();account = (EditText) findViewById(R.id.account);password = (EditText) findViewById(R.id.password);to = (EditText) findViewById(R.id.to);content = (EditText) findViewById(R.id.content);login = (Button) findViewById(R.id.login);logout = (Button) findViewById(R.id.logout);send = (Button) findViewById(R.id.send);login.setOnClickListener(this);logout.setOnClickListener(this);send.setOnClickListener(this);

對應的點擊事件的實現,也就是登陸,登出,發送訊息的邏輯

@Override    public void onClick(View view) {        switch (view.getId()){            case R.id.login:{                final String a = account.getText().toString();                final String p = password.getText().toString();                if (TextUtils.isEmpty(a) || TextUtils.isEmpty(p)) {                    Toast.makeText(getApplicationContext(), 帳號或密碼不可為空, Toast.LENGTH_LONG).show();                    return;                }                new Thread(new Runnable() {                    @Override                    public void run() {                        try {                            connection.connect();                            connection.login(a, p);                            Presence presence = new Presence(Presence.Type.available);                            presence.setStatus(我是線上狀態);                            connection.sendStanza(presence);                            ChatManager chatmanager = ChatManager.getInstanceFor(connection);                            chatmanager.addChatListener(new ChatManagerListener() {                                @Override                                public void chatCreated(Chat chat, boolean createdLocally) {                                    chat.addMessageListener(new ChatMessageListener() {                                        @Override                                        public void processMessage(Chat chat, Message message) {                                            String content=message.getBody();                                            if (content!=null){                                                Log.e(TAG, from: + message.getFrom() +  to: + message.getTo() +  message: + message.getBody());                                                android.os.Message message1= android.os.Message.obtain();                                                message1.what=1;                                                message1.obj=收到訊息: + message.getBody()+ 來自:+message.getFrom();                                                mHandler.sendMessage(message1);                                            }                                        }                                    });                                }                            });                        } catch (SmackException e) {                            e.printStackTrace();                        } catch (IOException e) {                            e.printStackTrace();                        } catch (XMPPException e) {                            e.printStackTrace();                        }                    }                }).start();                break;            }            case R.id.logout:                connection.disconnect();                break;            case R.id.send:                final String t = to.getText().toString();                final String c = content.getText().toString();                if (TextUtils.isEmpty(t)||TextUtils.isEmpty(c)) {                    Toast.makeText(getApplicationContext(), 接收方或內容, Toast.LENGTH_LONG).show();                    return;                }                try {                    ChatManager chatmanager = ChatManager.getInstanceFor(connection);                    Chat mChat = chatmanager.createChat(t+@10.0.0.24);                    mChat.sendMessage(c);                }                catch (SmackException.NotConnectedException e) {                    e.printStackTrace();                }                break;        }    }

收到訊息後需要在主線程裡操作,簡單的Toast一下

private Handler mHandler=new Handler(){    @Override    public void handleMessage(android.os.Message msg) {        switch (msg.what){            case 1:                Toast.makeText(getApplicationContext(),msg.obj+,Toast.LENGTH_SHORT).show();                break;        }        super.handleMessage(msg);    }};

這時候如果你使用測試帳號進行登陸,你會發現登陸不了,會報一個錯誤

解決方案也比較簡單,到Openfire的安裝目錄中,尋找conf/openfire.xml檔案

在最後一個節點閉合前加入代碼

       PLAIN   

重啟OpenFire,這時候你會發現成功登陸了,並能正常的設定使用者的線上狀態了

將我們的Spark使用測試帳號test1登陸,Android端使用test登陸,測試訊息是否能成功送到。

源碼。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.