接上篇:android
(一)客戶端與服務器創建鏈接api
上一篇寫到ClientSession createClientSession這裏,建立一個客戶端的session。在SessionManager類中建立了session以後,這裏拼接了兩個xml內容的text。一個是Build the start packet response,建立一個頭條包,做爲迴應。另一個是:XMPP 1.0 needs stream features,是xmpp1.0所須要的文件結構。兩個消息的格式內容以下:服務器
<?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1"
id="bdef9c6a" xml:lang="en" version="1.0">
<stream:features> <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls> <auth xmlns="http://jabber.org/features/iq-auth"/> <register xmlns="http://jabber.org/features/iq-register"/> </stream:features>
而後,調用connection的deliverRawText方法,將這兩個xml內容經過IOSession的writer方法,傳輸到mina裏面。具體mina怎麼處理,本人尚未研究過。session
到此,根據記錄的log日誌,此消息已經發布了。客戶端與服務器創建鏈接的過程,這裏已經完成。這裏只是一部分,關於客戶端消息的發送,這部份內容也應該很多。mybatis
(二)服務器推送消息dom
從服務器推送消息的時候,會調用NotificationManager類裏面的方法,分別爲廣播和對單個用戶發送。這裏主要看廣播。源碼分析
首先是構造IQ消息體,createNotificationIQ方法來構造。ui
/** * Creates a new notification IQ and returns it. * 構造消息體格式 */ private IQ createNotificationIQ(String apiKey, String title, String message, String uri) { Random random = new Random(); String id = Integer.toHexString(random.nextInt()); // String id = String.valueOf(System.currentTimeMillis()); Element notification = DocumentHelper.createElement(QName.get( "notification", NOTIFICATION_NAMESPACE)); notification.addElement("id").setText(id); notification.addElement("apiKey").setText(apiKey); notification.addElement("title").setText(title); notification.addElement("message").setText(message); notification.addElement("uri").setText(uri); IQ iq = new IQ(); iq.setType(IQ.Type.set); iq.setChildElement(notification); return iq; }
構造後的xml:spa
<iq type="set" id="860-0" to="159b356f005e4710a1f1c8aa0547e4ce@127.0.0.1/AndroidpnClient"> <notification xmlns="androidpn:iq:notification"> <id>11218d6c</id> <apiKey>1234567890</apiKey> <title>你好</title> <message>你好啊</message> <uri></uri> </notification> </iq>
在ClientSession中查找指定用戶名的session,若是存在,則發送此條IQ消息。調用connectin的deliver方法,經過ioSession.write(buffer),將xml信息傳輸給mina,而且將發送記錄加1。hibernate
客戶端源碼分析:
客戶端代碼很簡單的,依靠xmppmanager維持鏈接。這裏說一下大概流程。
當客戶端推送消息過來的時候,NotificationReceiver類的onReceive方法接收到消息,在這裏,這時候,已經得到了全部發過來的數據。在這裏,已經能夠作本身的事情了,由於已經有了須要的數據。不過貌似挺多人喜歡在notifier的notify方法中來進行處理。
其餘就是本身的業務了。
還有一個是關於客戶端的用戶名和密碼,這個默認是自動生成,也能夠自動指定。在XMPPManager的run方法裏面能夠修改。修改後會出現一些問題,就是服務器端註冊的時候,會出現用戶名已經存在,重複插入的問題。這個須要在服務器端插入數據的時候修改一下代碼,在UserServiceImpl中修改,爲了業務須要,本人把hibernate修改成了mybatis,因此方法略有不一樣:
public User saveUser(User user) throws UserExistsException { try { //修改成本身的用戶登陸 try { user=getUserByUsername(user.getUsername()); } catch (UserNotFoundException e) { // TODO Auto-generated catch block log.info(user.getUsername()+" is not exist in db ...."); userDao.saveUser(user); e.printStackTrace(); } } catch (DataIntegrityViolationException e) { e.printStackTrace(); log.warn(e.getMessage()); throw new UserExistsException("User '" + user.getUsername() + "' already exists!"); } catch (EntityExistsException e) { // needed for JPA e.printStackTrace(); log.warn(e.getMessage()); throw new UserExistsException("User '" + user.getUsername() + "' already exists!"); } return user; }
這樣就能夠了。
關於短線重連,網上也有不少解決方法,是客戶端加一行代碼:
private void addTask(Runnable runnable) { Log.d(LOGTAG, "addTask(runnable)..."); taskTracker.increase(); synchronized (taskList) { if (taskList.isEmpty() && !running) { running = true; futureTask = taskSubmitter.submit(runnable); if (futureTask == null) { taskTracker.decrease(); } } else { //解決服務器端重啓後,客戶端不能成功鏈接androidpn服務器 runTask(); taskList.add(runnable); } } Log.d(LOGTAG, "addTask(runnable)... done"); }
固然,其餘還有許多細節,先到這裏,感謝網上那麼多博主寫的一些資料。