分享下android webview中的websocket解决方案
分享下android的websocket结局方案
本文基于DCloud 5+SDK
不过原理同样使用于H5与java交互的方案
-----------------------------------------------------------------------
- 2017.1.9
- 最近在做一个外勤应用,里面要做即时通讯,最终选择的是自己写websocket封装协议,没有使用融云这些,原因是系统会给用户私有云部署,同时也不想太依赖于第三方
- ios下面的websocket是没有任何问题的
- 但是android上是有问题的 虽然官方说4.4以上支持,但是经测试 我的一台4.4的机器也是不支持,服务端报错是 protocol error
- 我们做应用的 除非是公司品牌特别牛像微信支付宝这类,否则你放弃了4.4一下的用户,他们也就放弃了你
网上找了很久,其中也搜到这里
WebSocket 问题总结 - DCloud问答
也尝试了下不是很好
最好只好自己尝试解决
目标有三个
1:使用第三方websocket js库 这样代码改动基本是最小的
2:自己写一个dcloud插件
第一个方案 找了很多 包括jwebsocket
http://
socket.io
最后发现问题依旧,原因就不说了
开始尝试第二个方案
但是看了半天dcloud的文档,发现自己写一个插件的复杂度太大,主要是官方很多地方文档描述不清
随后静下心来,我本身就是在原生的基础上来加的h5+sdk,所以可以尝试原生与js混合通信的方式
写到这里 我再次吐槽一下,我也用过apicloud,里面我觉得最好的一个是apicloud与原生之间的一个事件通知,不需要使用webview,随手写随手通知
回归正题
原有的js中websocke的部分,需要完成3个事情:
1 websocket初始化连接
2 发送消息
3 接受消息
所以我们只需要在java中写一个辅助类
1在需要的时候初始化连接
2可以接受js的发送请求,将数据发出
3在收到消息时候通知js
下面贴代码
js部分
```javascript
function createWs() {
var WsUrl = ws_host + getMemberId();
if(mui.os.ios) {
if('WebSocket' in window) {
debug("WebSocket")
wsClient = new WebSocket(WsUrl);
} else if('MozWebSocket' in window) {
debug("MozWebSocket")
wsClient = new MozWebSocket(WsUrl);
}
wsClient.onopen = function() {
onOpen()
};
wsClient.onclose = function() {
onClose()
};
wsClient.onmessage = function(evt) {
onMessage(evt)
};
wsClient.onerror = function() {
onError()
};
} else if(mui.os.android) {
var Toolkit = plus.android.importClass("com.HBuilder.integrate.WsHelper");
if(Toolkit) {
//var wifiInfo = new Toolkit();
Toolkit.webConnect(WsUrl);
} else {
plus.nativeUI.alert("IM服务器连接失败");
}
}
}
```
原理一看就明白,如果是ios 则使用html5的websocket,如果是案桌,就使用原生的方法去创建websocket
下面是java原生,java原生有很多websocket客户端库,我这里用的是AndroidAsync
java 实现初始化websocket连接,以及实现向js通讯消息
```javascript
public static void webConnect(final String url) {
if (webSocket == null) {
try {
AsyncHttpClient.getDefaultInstance().websocket(url, null, new AsyncHttpClient.WebSocketConnectCallback() {
@Override
public void onCompleted(Exception ex, WebSocket _webSocket) {
webSocket = _webSocket;
//发送心跳
webSocket.send("{\"messageType\":3}");
webSocket.setStringCallback(new WebSocket.StringCallback() {
@Override
public void onStringAvailable(String s) {
Log.d("qwe", "hello");
//获取webview
ArrayList<IWebview> ss = SDK.obtainAllIWebview();
for (IWebview iWebview : ss) {
if (iWebview.getOriginalUrl().equals("messageList.html")) {
iWebview.evalJS("wsRecive('" + s + "')");
// JSUtil.broadcastWebviewEvent(iWebview, iWebview.getWebviewUUID(), "wsRecive", s);
//JSUtil.execCallback(iWebview, "wsRecive", s, JSUtil.OK, false);
break;
}
}
}
});
webSocket.setClosedCallback(new CompletedCallback() {
@Override
public void onCompleted(Exception ex) {
try {
if (ex != null)
Log.e("WebSocket", "Error");
} finally {
if (tryTime <= 3) {
tryTime += 1;
webConnect(url);
}
}
}
});
}
});
}
finally {
if (tryTime <= 3) {
tryTime += 1;
webConnect(url);
}
}
} else {
webSocket.send("{\"messageType\":3}");
}
}
```
这里又要吐槽一下,官方的h5+sdk文档实在是太糟糕,花了很长时间才摸索出来,主要是获取指定的webview 这点没有apicloud做得好 ,apicloud后台java发起一个事件,前面任何一个页面都可以监听,5+sdk我找了半天没有找到,可能也有但是不知道在哪里
首先查找所有的webview,然后调用这个页面的js方法
```javascript
ArrayList<IWebview> ss = SDK.obtainAllIWebview();
for (IWebview iWebview : ss) {
if (iWebview.getOriginalUrl().equals("messageList.html")) {
iWebview.evalJS("wsRecive('" + s + "')");
break;
}
}
```
下面是js发送消息
```javascript
function sendMsg(msg) {
if(mui.os.ios) {
//缓存本地
if(wsClient.readyState == WebSocket.OPEN) {
wsClient.send(JSON.stringify(msg));
_msg = null;
} else {
_msg = msg;
createWs();
}
} else if(mui.os.android) {
var Toolkit = plus.android.importClass("com.HBuilder.integrate.WsHelper");
if(Toolkit) {
//var wifiInfo = new Toolkit();
Toolkit.sendMsg(JSON.stringify(msg));
} else {
plus.nativeUI.alert("IM服务器连接失败");
}
}
}
```
也是先要判断,如果ios就走h5直接发送,否则就走原生android发送
```javascript
public static void sendMsg(String msg) {
if (webSocket != null && webSocket.isOpen()) {
webSocket.send(msg);
}
}
```
至此,android的websocket完美解决,无论多少版本,统一走底层
思路不一定是最好的 欢迎加我微信(ming-lsard)交流
希望有更好的解决思路一起分享
谢谢大家
本文未经许可,禁止转载