分享下android的websocket结局方案
先占个坑
明天写  
- 2017.1.9
 - 最近在做一个外勤应用,里面要做即时通讯,最终选择的是自己写websocket封装协议,没有使用融云这些,原因是系统会给用户私有云部署,同时也不想太依赖于第三方
 - ios下面的websocket是没有任何问题的
 - 但是android上是有问题的 虽然官方说4.4以上支持,但是经测试 我的一台4.4的机器也是不支持,服务端报错是 protocol error
 - 我们做应用的 除非是公司品牌特别牛像微信支付宝这类,否则你放弃了4.4一下的用户,他们也就放弃了你
网上找了很久,其中也搜到这里 http://ask.dcloud.net.cn/article/302
也尝试了下不是很好
最好只好自己尝试解决
目标有三个
1:使用第三方websocket js库 这样代码改动基本是最小的
2:自己写一个dcloud插件 
第一个方案 找了很多 包括jwebsocket socket.io
最后发现问题依旧,原因就不说了
开始尝试第二个方案
但是看了半天dcloud的文档,发现自己写一个插件的复杂度太大,主要是官方很多地方文档描述不清
随后静下心来,我本身就是在原生的基础上来加的h5+sdk,所以可以尝试原生与js混合通信的方式
写到这里 我再次吐槽一下,我也用过apicloud,里面我觉得最好的一个是apicloud与原生之间的一个事件通知,不需要使用webview,随手写随手通知  
回归正题
原有的js中websocke的部分,需要完成3个事情:
1 websocket初始化连接
2 发送消息
3 接受消息  
所以我们只需要在java中写一个辅助类
1在需要的时候初始化连接
2可以接受js的发送请求,将数据发出
3在收到消息时候通知js  
下面贴代码
js部分
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通讯消息
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方法
  ArrayList<IWebview> ss = SDK.obtainAllIWebview();  
                                for (IWebview iWebview : ss) {  
                                    if (iWebview.getOriginalUrl().equals("messageList.html")) {  
                                        iWebview.evalJS("wsRecive('" + s + "')");  
                                        break;  
                                    }  
                                }
下面是js发送消息
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发送
public static void sendMsg(String msg) {  
        if (webSocket != null && webSocket.isOpen()) {  
            webSocket.send(msg);  
        }  
    }
至此,android的websocket完美解决,无论多少版本,统一走底层
思路不一定是最好的 欢迎加我微信(ming-lsard)交流
希望有更好的解决思路一起分享
谢谢大家  
本文未经许可,禁止转载,只发在dcloud官方论坛
            
            
            
            
10 个评论
要回复文章请先登录或注册
huangr_001
1***@qq.com
QTD
freedemon
夜帝
移动达人
猫猫猫猫
前端的程序狗
Danny
四阿哥