標籤:android style blog http color os io strong
接上篇:
(一)用戶端與伺服器建立串連
上一篇寫到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怎麼處理,本人還沒有研究過。
到此,根據記錄的log日誌,此訊息已經發布了。用戶端與伺服器建立串連的過程,這裡已經完成。這裡只是一部分,關於用戶端訊息的發送,這部分內容也應該不少。
(二)伺服器推送訊息
從伺服器推送訊息的時候,會調用NotificationManager類裡面的方法,分別為廣播和對單個使用者發送。這裡主要看廣播。
首先是構造IQ訊息體,createNotificationIQ方法來構造。
/** * 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:
<iq type="set" id="860-0" to="[email protected]/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。
用戶端源碼分析:
用戶端代碼很簡單的,依靠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"); }
當然,其他還有許多細節,先到這裡,感謝網上那麼多博主寫的一些資料。