AndroidPn源碼分析(二)

接上篇: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"); 
    } 

固然,其餘還有許多細節,先到這裏,感謝網上那麼多博主寫的一些資料。

相關文章
相關標籤/搜索