https://skydrive.live.com/?cid=cf7746837803bc50&id=CF7746837803BC50%211278&authkey=!AKImvowSw7Ab2bE
可使用HTML + CSS + Javascript构建跨平台的移动引用,确实很不错,值得推荐。
更棒的,可以利用其云构建服务(https://build.phonegap.com/apps ) ,本机编写好应用之后(保证首页为index.html,涉及到的css/js存放在一起),打包成zip,上传,自动会为我们自动构建不同平台下的部署包,十分方便。
表面上看,一切都很完美,但部署到Android系统之后,发现socket.io无法使用websocket双向的通道,socket.io默认采用xhr-long polling通信模式。有些无奈。
在实时交互数据量很大的情况下,相比xhr-long polling, jsonp polling,Websocket/Flashsocket具有无法超越的速度优势,同时双向数据传输通道,通过观察可以很明显的感觉到。
起因
- 我的android系统是2.3的,其原生的浏览器不支持websocket通信协议(ucweb,qq,opear mini 等都支持较为完整的HTML5规范)。
- Phonegap转换的APK包,会调用android内置浏览器,因此导致websocket无法使用。
- 据调研Android 2/3.* 原生浏览器不支持websocket,至于Android 4.*,没有测试过。
如何确认浏览器对html5的支持情况, 浏览器访问 http://html5test.com 即可查询对HTML5的支持情况,以及跑分等。
嗯,据传言,Phonegap会在2.0版本之后,添加对Android的websocket支持,但目前版本为1.7。
解决方式
animesh kumar 开发的websocket-android-phonegap项目,已经做到了让Phonegap支持websocket客户端协议,使用java nio编写websocket客户端协议连接,同时Phonegap支持自定义组件,支持JS和JAVA代码的相互调用开放架构,这样就促成了伪装的webscoket.js。
其有些DWR的味道,但更为灵活。
另外还有一个单纯的socket.io android客户端实现:
https://github.com/koush/android-websockets#readme
有兴趣者,可以参考一下。
本打算使用Netty构建一个websocket客户端,然后结合js等,但有开源实现,不再闭门造车。
- 在Eclipse中新建Android Project项目chatdemo
- 把animesh kumar的websocket-android-phonegap项目java文件打成phonegap-websocket-support.jar包,存放在 android project的libs目录下
- 把websocket.js存放在 assets/www/js目录下
- 修改项目启动类App.java
- 添加<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"
);
}
}
|
确保继承DroidGap,并且指定绑定语句:
// 绑定websocket支持
appView.addJavascriptInterface(new WebSocketFactory(appView),
"WebSocketFactory");
JAVA端设定完毕。
2. 客户端的修改
需要在html页面端做些手脚,优先加载websocket.js进行一些环境变量的设定,这样socket.io就可以检测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.'
);
};
// 其它原型函数,省略......
})();
|
需要注意其初始化代码:
// 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的检测函数:
WS.check = function () {
return ('WebSocket' in global && !('__addTask' in WebSocket))
|| 'MozWebSocket' in global;
};
很自然的,自定义的websocket.js 和 socket.io两者就能够很自然的衔接在一起了。
因此,必须的页面JS加载顺序为:
<!--android平台需要添加,其它移动平台,比如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平台下socket.io优先选择websocket,很简单,也很使用。
至于其它平台,则不需要考虑这么,仅仅把/chatdemo/assets/www目录下打包成zip包(切记把<script src="js/websocket.js"></script>去除掉),上传到云构建平台自动构建即可。
小总结
Phonegap下让android平台支持websocket,步骤很简单:
- 在eclipse下搭建android project
- 拷贝jar以及socekt.js到相应目录
- 修改App.java(其它android启动类,方法名不一样,但方法体一致)
- 在首页或者需要的页面,在 socket.io js医用的前面,添加<script src="js/websocket.js"></script>引用即可
示范代码
- socket.io 框架内置的chat聊天示范和socketio-netty所提供聊天示范完全一致,除了服务器端实现不同
- 简单包装成android项目,仅用于演示使用,因此界面有些大
- 需要一个服务器端,socket.io或者socketio-netty的都可以
- 本文Android示范chat下载 下载
- phonegap-websocket-support.jar
转自:http://www.blogjava.net/yongboy/archive/2012/05/10/377787.html