聶永的博客

          記錄工作/學(xué)習(xí)的點(diǎn)點(diǎn)滴滴。

          為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇

          廣而告之

          使用socket.io作為跨瀏覽器平臺(tái)的實(shí)時(shí)推送首選,經(jīng)測(cè)試在各個(gè)主流瀏覽器上測(cè)試都確實(shí)具有良好的下實(shí)時(shí)表現(xiàn)。這里為推廣socketio-netty服務(wù)器端實(shí)現(xiàn)哈,做次廣告,同時(shí)預(yù)熱一下:

          socketio-netty : 又一款socket.io服務(wù)器端實(shí)現(xiàn),兼容0.9-1.0版本~

           

          示范目的

           

          我們要構(gòu)建一個(gè)在市面上常見瀏覽器上都可以正常運(yùn)行的集體聊天應(yīng)用,保證在IE6+,F(xiàn)irefox,Chrome,Safari,Opear,IOS,Android等可以正常運(yùn)轉(zhuǎn),根據(jù)具體環(huán)境自動(dòng)選擇最佳的通信通道。

          嗯,既然是跨瀏覽器平臺(tái),那自然選擇socket.io(客戶端js) 了。它也是本文的重心,本文的最終是讓socket.io(客戶端js) 版本在Phonegap包裝的Android Apk程序中可以使用Websocket協(xié)議,以達(dá)到快速交換數(shù)據(jù)的目的,提高交換性能。

          同時(shí)也保證我們的示范應(yīng)用盡可能的做到編寫一次,到處運(yùn)行哈。

          還好,有了socket.io(客戶端js) + socketio-netty(socket.io服務(wù)器端JAVA實(shí)現(xiàn)) + Phonegap, 我們構(gòu)建各種交互性非常強(qiáng)的的跨瀏覽器、跨移動(dòng)應(yīng)用的HTML應(yīng)用,是個(gè)不錯(cuò)的選擇。

          另,本文示范項(xiàng)目為僅僅為演示其功能,不保證樣式。

           

          Phonegap

          官網(wǎng)

          官網(wǎng)定義為:

          PhoneGap is an HTML5 app platform that allows you to author native applications with web technologies and get access to APIs and app stores.

          中文翻譯為:

          PhoneGap是一個(gè)開源的開發(fā)框架,使用HTML,CSS和JavaScript來構(gòu)建跨平臺(tái)的的移動(dòng)應(yīng)用程序

          可使用HTML + CSS + Javascript構(gòu)建跨平臺(tái)的移動(dòng)引用,確實(shí)很不錯(cuò),值得推薦。

          更棒的,可以利用其云構(gòu)建服務(wù)(https://build.phonegap.com/apps ) ,本機(jī)編寫好應(yīng)用之后(保證首頁為index.html,涉及到的css/js存放在一起),打包成zip,上傳,自動(dòng)會(huì)為我們自動(dòng)構(gòu)建不同平臺(tái)下的部署包,十分方便。

          表面上看,一切都很完美,但部署到Android系統(tǒng)之后,發(fā)現(xiàn)socket.io無法使用websocket雙向的通道,socket.io默認(rèn)采用xhr-long polling通信模式。有些無奈。

          在實(shí)時(shí)交互數(shù)據(jù)量很大的情況下,相比xhr-long polling, jsonp polling,Websocket/Flashsocket具有無法超越的速度優(yōu)勢(shì),同時(shí)雙向數(shù)據(jù)傳輸通道,通過觀察可以很明顯的感覺到。

           

          起因

          1. 我的android系統(tǒng)是2.3的,其原生的瀏覽器不支持websocket通信協(xié)議(ucweb,qq,opear mini 等都支持較為完整的HTML5規(guī)范)。
          2. Phonegap轉(zhuǎn)換的APK包,會(huì)調(diào)用android內(nèi)置瀏覽器,因此導(dǎo)致websocket無法使用。
          3. 據(jù)調(diào)研Android 2/3.* 原生瀏覽器不支持websocket,至于Android 4.*,沒有測(cè)試過。

          如何確認(rèn)瀏覽器對(duì)html5的支持情況, 瀏覽器訪問 http://html5test.com 即可查詢對(duì)HTML5的支持情況,以及跑分等。

          嗯,據(jù)傳言,Phonegap會(huì)在2.0版本之后,添加對(duì)Android的websocket支持,但目前版本為1.7。

           

          解決方式

          animesh kumar 開發(fā)的websocket-android-phonegap項(xiàng)目,已經(jīng)做到了讓Phonegap支持websocket客戶端協(xié)議,使用java nio編寫websocket客戶端協(xié)議連接,同時(shí)Phonegap支持自定義組件,支持JS和JAVA代碼的相互調(diào)用開放架構(gòu),這樣就促成了偽裝的webscoket.js。

          其有些DWR的味道,但更為靈活。

          另外還有一個(gè)單純的socket.io android客戶端實(shí)現(xiàn):

          https://github.com/koush/android-websockets#readme

          有興趣者,可以參考一下。

          本打算使用Netty構(gòu)建一個(gè)websocket客戶端,然后結(jié)合js等,但有開源實(shí)現(xiàn),不再閉門造車。

          1. 在Eclipse中新建Android Project項(xiàng)目chatdemo
          2. animesh kumarwebsocket-android-phonegap項(xiàng)目java文件打成phonegap-websocket-support.jar包,存放在 android project的libs目錄下
          3. websocket.js存放在 assets/www/js目錄下
          4. 修改項(xiàng)目啟動(dòng)類App.java
          5. 添加<script src="js/websocket.js"></script>

           

          簡單說明

          1. App.java修改后:

          package com.yongboy.chatdemo;
          import org.apache.cordova.DroidGap;
          import android.os.Bundle;
          import com.strumsoft.websocket.phonegap.WebSocketFactory;
          /**
          *
          * @author yongboy
          * @time 2012-5-10
          * @version 1.0
          */
          public class App extends DroidGap {
          @Override
          public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          super.loadUrl("file:///android_asset/www/index.html");
          // 绑定websocket支持
          appView.addJavascriptInterface(new WebSocketFactory(appView),
          "WebSocketFactory");
          }
          }
          view raw App.java hosted with ❤ by GitHub

          確保繼承DroidGap,并且指定綁定語句:

          // 綁定websocket支持

          appView.addJavascriptInterface(new WebSocketFactory(appView),

          "WebSocketFactory");

          JAVA端設(shè)定完畢。

          2. 客戶端的修改

          需要在html頁面端做些手腳,優(yōu)先加載websocket.js進(jìn)行一些環(huán)境變量的設(shè)定,這樣socket.io就可以檢測(cè)websocket的支持。

          websocekt.js的初始化代碼:

          (function() {
          // window object
          var global = window;
          // WebSocket Object. All listener methods are cleaned up!
          var WebSocket = global.WebSocket = function(url) {
          // get a new websocket object from factory (check com.strumsoft.websocket.WebSocketFactory.java)
          this.socket = WebSocketFactory.getInstance(url);
          // store in registry
          if(this.socket) {
          WebSocket.store[this.socket.getId()] = this;
          } else {
          throw new Error('Websocket instantiation failed! Address might be wrong.');
          }
          };
          // storage to hold websocket object for later invokation of event methods
          WebSocket.store = {};
          // static event methods to call event methods on target websocket objects
          WebSocket.onmessage = function (evt) {
          WebSocket.store[evt._target]['onmessage'].call(global, evt);
          }
          WebSocket.onopen = function (evt) {
          WebSocket.store[evt._target]['onopen'].call(global, evt);
          }
          WebSocket.onclose = function (evt) {
          WebSocket.store[evt._target]['onclose'].call(global, evt);
          }
          WebSocket.onerror = function (evt) {
          WebSocket.store[evt._target]['onerror'].call(global, evt);
          }
          // instance event methods
          WebSocket.prototype.send = function(data) {
          this.socket.send(data);
          }
          WebSocket.prototype.close = function() {
          this.socket.close();
          }
          WebSocket.prototype.getReadyState = function() {
          this.socket.getReadyState();
          }
          ///////////// Must be overloaded
          WebSocket.prototype.onopen = function(){
          throw new Error('onopen not implemented.');
          };
          // alerts message pushed from server
          WebSocket.prototype.onmessage = function(msg){
          throw new Error('onmessage not implemented.');
          };
          // 其它原型函数,省略......
          })();
          view raw websocket.js hosted with ❤ by GitHub

          需要注意其初始化代碼:

          // window object
          var global = window;

          // WebSocket Object. All listener methods are cleaned up!
          var WebSocket = global.WebSocket = function(url)

          ......

           

          socket.io client websocket 代碼片段:

          (function (exports, io, global) {
          exports.websocket = WS;
          function WS (socket) {
          io.Transport.apply(this, arguments);
          };
          io.util.inherit(WS, io.Transport);
          WS.prototype.name = 'websocket';
          WS.prototype.open = function () {
          var query = io.util.query(this.socket.options.query)
          , self = this
          , Socket
          if (!Socket) {
          Socket = global.MozWebSocket || global.WebSocket;
          }
          this.websocket = new Socket(this.prepareUrl() + query);
          this.websocket.onopen = function () {
          self.onOpen();
          self.socket.setBuffer(false);
          };
          this.websocket.onmessage = function (ev) {
          self.onData(ev.data);
          };
          this.websocket.onclose = function () {
          self.onClose();
          self.socket.setBuffer(true);
          };
          this.websocket.onerror = function (e) {
          self.onError(e);
          };
          return this;
          };
          WS.prototype.send = function (data) {
          this.websocket.send(data);
          return this;
          };
          WS.prototype.payload = function (arr) {
          for (var i = 0, l = arr.length; i < l; i++) {
          this.packet(arr[i]);
          }
          return this;
          };
          WS.prototype.close = function () {
          this.websocket.close();
          return this;
          };
          WS.prototype.onError = function (e) {
          this.socket.onError(e);
          };
          WS.prototype.scheme = function () {
          return this.socket.options.secure ? 'wss' : 'ws';
          };
          WS.check = function () {
          return ('WebSocket' in global && !('__addTask' in WebSocket))
          || 'MozWebSocket' in global;
          };
          WS.xdomainCheck = function () {
          return true;
          };
          io.transports.push('websocket');
          })(
          'undefined' != typeof io ? io.Transport : module.exports
          , 'undefined' != typeof io ? io : module.parent.exports
          , this
          );

          看一下websocket的檢測(cè)函數(shù):

          WS.check = function () {
            return ('WebSocket' in global && !('__addTask' in WebSocket))
                  || 'MozWebSocket' in global;
          };

          很自然的,自定義的websocket.js 和 socket.io兩者就能夠很自然的銜接在一起了。

           

          因此,必須的頁面JS加載順序?yàn)椋?/p>

          <!--android平臺(tái)需要添加,其它移動(dòng)平臺(tái),比如ios則不需要 -->
          <!--一定要放在socket.io.min.js前面 -->
          <script src="js/websocket.js"></script>
          <script src="js/socket.io.min.js"></script>

          在HTML頁面端,我們僅僅需要添加一行<script src="js/websocket.js"></script>引用,就做到了讓android平臺(tái)下socket.io優(yōu)先選擇websocket,很簡單,也很使用。

          至于其它平臺(tái),則不需要考慮這么,僅僅把/chatdemo/assets/www目錄下打包成zip包(切記把<script src="js/websocket.js"></script>去除掉),上傳到云構(gòu)建平臺(tái)自動(dòng)構(gòu)建即可。

           

          小總結(jié)

          Phonegap下讓android平臺(tái)支持websocket,步驟很簡單:

          1. 在eclipse下搭建android project
          2. 拷貝jar以及socekt.js到相應(yīng)目錄
          3. 修改App.java(其它android啟動(dòng)類,方法名不一樣,但方法體一致)
          4. 在首頁或者需要的頁面,在 socket.io js醫(yī)用的前面,添加<script src="js/websocket.js"></script>引用即可

           

          示范代碼

          1. socket.io 框架內(nèi)置的chat聊天示范和socketio-netty所提供聊天示范完全一致,除了服務(wù)器端實(shí)現(xiàn)不同
          2. 簡單包裝成android項(xiàng)目,僅用于演示使用,因此界面有些大
          3. 需要一個(gè)服務(wù)器端,socket.io或者socketio-netty的都可以
          4. 本文Android示范chat下載 下載
          5. phonegap-websocket-support.jar

           

          參考資料

          1. Phonegap:
             http://phonegap.com/
          2. WebSocket support in Android’s Phonegap apps
            http://anismiles.wordpress.com/2011/02/03/websocket-support-in-android%E2%80%99s-phonegap-apps/

          3. websocket-android-phonegap
            https://github.com/anismiles/websocket-android-phonegap

          posted on 2012-05-10 14:10 nieyong 閱讀(24887) 評(píng)論(12)  編輯  收藏 所屬分類: socket.io

          評(píng)論

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2012-05-10 17:14 ge_star

          animesh kumar 開發(fā)的websocket-android-phonegap項(xiàng)目只支持DRAFT75/76的協(xié)議~對(duì)于目前的很多服務(wù)器不支持,例如tomcat7,tomcat7采用RCFRFC 6455,所以需要自己改握手和通訊協(xié)議  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2012-05-11 08:33 tb

          這個(gè)好啊 方便我們的手機(jī)開發(fā)  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2012-05-11 09:43 nieyong

          @ge_star
          采用Netty,或者http://socket.io,或者http://code.google.com/p/socketio-netty/
          或者,直接增加對(duì)RCFRFC 6455的支持等。  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2012-06-07 17:52 josh

          請(qǐng)教一下 我利用IFRAME 去崁入http://www.websocket.org/echo.html

          語法如下:
          <iframe src="http://www.websocket.org/echo.html" width="100%" height="100%" ></iframe>

          但卻出現(xiàn)不支援 可否請(qǐng)教原因  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2012-06-11 09:09 nieyong

          @josh
          您是什么平臺(tái) ?若是android,默認(rèn)的瀏覽器不支持websocket協(xié)議。  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇[未登錄] 2012-07-26 17:14 jarry

          socket.io client websocket 代碼片段:最后一部分貌似有問題?module不存在。。。(
          'undefined' != typeof io ? io.Transport : module.exports
          , 'undefined' != typeof io ? io : module.parent.exports
          , this
          )  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2012-08-29 10:35 零度火云

          感謝您詳細(xì)的方案,正好需要  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2013-05-28 18:33 FreezeSoul

          請(qǐng)問,為什么切換連接后會(huì)報(bào)超時(shí),但我本地用chrome打開是可以
          (注釋websocket.js)

          連接:http://192.168.23.1:9000/chat

          異常:DroidGap: TIMEOUT ERROR! - calling webViewClient
            回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2013-09-13 15:13 yimengyuanyun

          鏈接不上服務(wù)器,不明白為什么
          var s = new WebSocket("ws://127.0.0.1:8000/");
          這個(gè)url是服務(wù)器的端口嗎?為什么我這個(gè)就不可以呢  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2013-12-16 09:28 唐鑫

          為什么報(bào) has no method 'getintance'錯(cuò)呢?  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2014-07-02 16:19 馬躍

          為什么報(bào) has no method 'getintance'錯(cuò)呢? 我也遇到了同樣的問題  回復(fù)  更多評(píng)論   

          # re: 為Phonegap Android平臺(tái)增加websocket支持,使默認(rèn)成為socket.io首選通道選擇 2014-07-02 16:20 馬躍

          有解決的幫下忙好嗎  回復(fù)  更多評(píng)論   

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請(qǐng)標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2012年6月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          1234567

          統(tǒng)計(jì)

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個(gè)人收藏

          最新隨筆

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 远安县| 林芝县| 社会| 南丰县| 万盛区| 潮州市| 荥阳市| 仁化县| 惠水县| 台江县| 阳城县| 蛟河市| 阜新| 开阳县| 大冶市| 兴城市| 历史| 宽城| 三门峡市| 武乡县| 德昌县| 通辽市| 博罗县| 巴里| 古浪县| 罗定市| 清水县| 吉安市| 贡嘎县| 文安县| 赫章县| 若羌县| 日照市| 日土县| 深州市| 迁安市| 平山县| 晋城| 广平县| 呼图壁县| 河北区|