当前位置:   article > 正文

Websocket 通信演示(h5/andorid/java)_android 实现app和h5 socket连接发送复制粘贴消息

android 实现app和h5 socket连接发送复制粘贴消息

H5和H5之间通信

H5和Andorid之间通信

Andorid和Andorid之间通信

H5通过http协议调用接口发送消息-给移动Andorid、H5等

后台支持语言:java

前端支持语言:Andorid(java)、H5(html)、jsp等

发送:发送给所有连接者、发送给所有在线者、发送给指定用户、及(发送对象)用户不在线处理

注:把连接地址改了,可以直接使用复制代码测试使用;

H5和Andorid测试页面:

Andorid测试页面 --消息发送者 发送指定用户 【消息接收者1】,也可以发送所有人
Andorid测试页面.jpg
消息接收者1消息接收者2
测试页面1.jpg测试页面2.jpg
通过Http发送测试页面
发送消息给所有在线用户发送消息给指定在线用户 --【测试用户 -张三】
http测试发送消息给所有在线用户.jpghttp测试发送消息给指定在线用户.jpg
测试用户李四测试用户张三
测试用户【李四】.jpg测试用户【张三】.jpg

java后台代码

引入依赖:
<!--集成移动和H5的java_websocket-->
		<dependency>
			<groupId>org.java-websocket</groupId>
			<artifactId>Java-WebSocket</artifactId>
			<version>1.3.0</version>
		</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

springboot项目结构,也可用spring项目,和框架没有关系,没有影响

代码类路径.png

1.WebSocketPool自定义工具类

主要是连接池,存用户和WebSocket连接

自定义 WebSocketPool.java

package com.dist.utils;

import org.java_websocket.WebSocket;

import java.util.*;

public class WebSocketPool {
    //连接-用户名
	private static final Map<WebSocket, String> userconnections = new HashMap<WebSocket, String>();
	  
    /** 
     * 获取用户名 
     * @param conn 
     * @return 
     */  
    public static String getUserByKey(WebSocket conn) {  
        return userconnections.get(conn);  
    }  
  
    /** 
     * 获取在线总数 
     * @return 
     */  
    public static int getUserCount() {  
        return userconnections.size();  
    }  
  
    /** 
     * 获取WebSocket 
     * @param user 
     * @return 
     */  
    public static WebSocket getWebSocketByUser(String user) {  
        Set<WebSocket> keySet = userconnections.keySet();
        synchronized (keySet) {  
            for (WebSocket conn : keySet) {  
                String cuser = userconnections.get(conn);  
                if (cuser.equals(user)) {  
                    return conn;  
                }  
            }  
        }  
        return null;  
    }  
  
    /** 
     * 向连接池中添加连接 
     * @param user 
     * @param conn 
     */  
    public static void addUser(String user, WebSocket conn) {  
        userconnections.put(conn, user); // 添加连接  
    }

    /**
     * 获取所有连接池
     */
    public static Set<WebSocket> getAllWebSocket() {
            return userconnections.keySet();
    }

    /**
     * 移除连接池中的连接
     * @param conn
     * @return
     */
    public static boolean removeUser(WebSocket conn) {
        if (userconnections.containsKey(conn)) {
            userconnections.remove(conn); // 移除连接
            return true;
        } else
            return false;
    }
  
    /** 
     * 获取所有的在线用户 
     * @return 
     */  
    public static Collection<String> getOnlineUser() {
        List<String> setUsers = new ArrayList<String>();
        Collection<String> setUser = userconnections.values();  
        for (String u: setUser) {  
            setUsers.add(u);  
        }  
        return setUsers;  
    }
  
    /** 
     * 向特定的用户发送数据 
     * @param conn 
     * @param message 
     */  
    public static void sendMessageToOnlineUser(WebSocket conn, String message) {
        if (null != conn) {  
            conn.send(message);  
        }  
    }

    /**
     * 向所有在线用户发送消息
     * @param message
     */
    public static void sendMessageToOnlineAllUser(String message) {
        Set<WebSocket> keySet = userconnections.keySet();  
        synchronized (keySet) {
            for (WebSocket conn : keySet) {  
                String user = userconnections.get(conn);  
                if (user != null) { conn.send(message);  
                }  
            }  
        }  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
2.创建房间类

为的是开启房间

ChatServer.java

package com.dist.service;

import com.dist.utils.WebSocketPool;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Set;

/**
 * 与不同的客户端进行通讯的思路为:
 * Step1:在连接成功的时候,向服务器发送自己的用户名,服务器做用户标记;
 * Step2: 发送消息,格式为“XX@XXX”,@前面表示将要发送的对象,“all”表示群发,@后面表示发送的消息。
 */
public class ChatServer extends WebSocketServer {

	private String username;

	public ChatServer(int port) throws UnknownHostException {
		super(new InetSocketAddress(port));
	}

	public ChatServer(InetSocketAddress address) {
		super(address);
		System.out.println("地址:"+address);
	}

	@Override
	public void onOpen(WebSocket conn, ClientHandshake handshake) {

		System.out.println("连接:"+conn);

		sendToAll(conn.getRemoteSocketAddress().getAddress().getHostAddress()
				+ " 进入房间 !");

		System.out.println(conn.getRemoteSocketAddress().getAddress()
				.getHostAddress()
				+ " 进入房间 !");
	}

	@Override
	public void onClose(WebSocket conn, int code, String reason, boolean remote) {

		sendToAll(conn.getRemoteSocketAddress().getAddress().getHostAddress()
				+ " 离开房间 !");

		System.out.println(conn.getRemoteSocketAddress().getAddress()
				.getHostAddress()
				+ " 离开房间 !");

		//触发关闭事件
		userLeave(conn);
	}

	//消息发送
	@Override
	public void onMessage(WebSocket conn, String message) {

		//判断是否是第一次接收的消息
		boolean isfirst = true;

		/*sendToAll("["
				+ conn.getRemoteSocketAddress().getAddress().getHostAddress()
				+ "]" + message);*/

		System.out.println("["
				+ conn.getRemoteSocketAddress().getAddress().getHostAddress()
				+ "]" + message);

		//判断是否已在连接池中
		Set<WebSocket> webSockets=WebSocketPool.getAllWebSocket();
		for (WebSocket webSocket : webSockets){
			if (webSocket.equals(conn)){
				isfirst =false;
			}
		}

		if (isfirst) {
			this.username = message;
			//客户端发送消息到服务器是触发事件
			if (message != null){
				//判断用户是否已经在线
				WebSocket webSocketByUser = WebSocketPool.getWebSocketByUser(message);
				if (null == webSocketByUser){
					//将用户加入连接池-在线
					this.userJoin(username, conn);
					System.out.println("用户" + username + "上线,在线人数:" + WebSocketPool.getUserCount());
				}else {
					WebSocketPool.sendMessageToOnlineUser(conn,"["+username+"] 用户已在线,请您换个用户登录!");
				}
			}
		} else {
			String[] msg = message.split("@", 2);//以@为分隔符把字符串分为xxx和xxxxx两部分,msg[0]表示发送至的用户名,all则表示发给所有人
			if (msg[0].equals("all")) {
				sendToAll(msg[1]);
			} else {
				//指定用户发送消息
				sendMessageToUser(conn,msg[0], msg[1]);
			}
		}
	}

	//异常抛出
	@Override
	public void onError(WebSocket conn, Exception e) {
		e.printStackTrace();
		if (conn != null) {
			conn.close();
		}
	}

	// 发送给所有进入房间的人
	private void sendToAll(String text) {
		Collection<WebSocket> conns = connections();
		synchronized (conns) {
			for (WebSocket client : conns) {
				client.send(text);
			}
		}
	}

	// 测试
	public static void main(String[] args) throws InterruptedException,
			IOException {
		/*int port = 8887;

		ChatServer server = new ChatServer(port);
		server.start();

		System.out.println("房间已开启,等待客户端接入,端口号: " + server.getPort());

		BufferedReader webSocketIn = new BufferedReader(new InputStreamReader(
				System.in));

		while (true) {
			String stringIn = webSocketIn.readLine();
			// 发送给所有的聊天者
			server.sendToAll(stringIn);
		}*/
	}

	/**
	 * 用户下线处理
	 * @param conn
	 */
	public void userLeave(org.java_websocket.WebSocket conn) {
		String user = WebSocketPool.getUserByKey(conn);
		boolean b = WebSocketPool.removeUser(conn); // 在连接池中移除连接
		if (b) {
			WebSocketPool.sendMessageToOnlineAllUser(user); // 把当前用户从所有在线用户列表中删除
			String leaveMsg = "[系统]" + user + "下线了";
			WebSocketPool.sendMessageToOnlineAllUser(leaveMsg); // 向在线用户发送当前用户退出的信息
		}
	}

	/**
	 * 用户上线处理
	 * @param user
	 * @param conn
	 */
	public void userJoin(String user, org.java_websocket.WebSocket conn) {
		WebSocketPool.sendMessageToOnlineAllUser(user); // 把当前用户加入到所有在线用户列表中
		String joinMsg = "[系统]" + user + "上线了!";
		WebSocketPool.sendMessageToOnlineAllUser(joinMsg); // 向所有在线用户推送当前用户上线的消息
		WebSocketPool.addUser(user, conn); // 向连接池添加当前的连接的对象
		WebSocketPool.sendMessageToOnlineUser(conn, WebSocketPool.getOnlineUser().toString());  // 向当前连接发送当前在线用户的列表

	}

	/**
	 * 发送消息给指定用户
	 * @param currentConnection 当前连接
	 * @param user  发送对象
	 * @param message 消息
	 */
	public void sendMessageToUser(WebSocket currentConnection,String user,String message){
		WebSocket conn = WebSocketPool.getWebSocketByUser(user);  //获取发送对象用户的在线连接
		if (null != conn){
			//向特定在线用户发送消息
			WebSocketPool.sendMessageToOnlineUser(conn,message);
			//同时发送消息给当前用户
            WebSocketPool.sendMessageToOnlineUser(currentConnection,message);
		}else {
			WebSocketPool.sendMessageToOnlineUser(currentConnection,"["+user+"] 用户不在线,请您稍后发送!");
			System.out.println("["+user+"] 用户不在线,请您稍后发送!");
			WebSocketPool.sendMessageToOnlineUser(currentConnection,"当前在线人数:"+WebSocketPool.getUserCount()+"  有:"+WebSocketPool.getOnlineUser());
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
3.Http发送消息

在controller层 创建WebSocketController.java

package com.dist.controller;

import com.dist.utils.WebSocketPool;
import org.java_websocket.WebSocket;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author zhengja@dist.com.cn
 * @data 2019/4/17 14:54
 */
@RestController
@RequestMapping("/WebSocket")
public class WebSocketController {

  	 //推送给所有在线用户
    @RequestMapping(value = "v1/sendAllUser", method = RequestMethod.GET)
    public void sendAllUser(@RequestParam String message){
        //推送给所有在线用户
        WebSocketPool.sendMessageToOnlineAllUser(message);
    }
  
    //推送给在线的指定用户
    @RequestMapping(value = "v1/sendUser", method = RequestMethod.GET)
    public void loginWithDevice(@RequestParam String pushObject,
                                @RequestParam String message){
        //推送的设备对象
        List<String> userlist = null;
        if (pushObject == null || "".equals(pushObject)) {
            System.out.println("推送对象不能为nuul");
        } else {
            userlist = new ArrayList<>(Arrays.asList(pushObject.split(",")));
        }
        for (String user : userlist){
            //根据用户查找推送的连接对象是否在线
            WebSocket webSocketByUser = WebSocketPool.getWebSocketByUser(user);
            if (null != webSocketByUser){
                //推送给在线的指定用户
                WebSocketPool.sendMessageToOnlineUser(webSocketByUser,message);
            }else {
                //未推送成功处理模块
                System.out.println("用户 【"+user+"】 不在线,推送失败 ! ");
            }
        }
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
4.创建启动任务

项目起动后自动启动这个任务-开启房间

TestStarts.java

import com.dist.service.ChatServer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class TestStarts implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        int port = 8887;

        ChatServer server = new ChatServer(port);
        server.start();
        System.out.println("项目启动中:房间已开启");
        System.out.println("等待客户端接入的端口号: " + server.getPort());

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

H5前端代码:

H5测试页面:引入jquery.js (放同级目录)
页面目录.png

目前测试页面上的数据信息是写死的,自己可以重后台获取数据,写成动态的

测试页面1

H5-WebSocket.html

注意:var wsUri =“ws://129.204.207.127:8887”; 把地址改成自己的服务器地址,端口不是服务器的,是TestStarts.java启动任务自定义创建的

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>H5-WebSocket Test</title>
    <script src="jquery.js"></script>
</head>
<body>

<br name="#" method="post">
    <!--YOUR DATA AREA-->
    <label id="a">当前用户</label>
    <select id="loginsel">
        <option value="2">李四</option>
        <option value="3">张三</option>
        <option value="4">王二</option>
    </select>
    <input type="button" value="连接" id="btnconnection" onclick="connectionAction()"/>
    <input type="button" value="断开" id="btndisconnect" onclick="disconnectAction()"/></br></br>
    <label id="b">发送对象</label>
    <select id="sel">
        <option value="1" selected>all</option>
        <option value="2">李四</option>
        <option value="3">张三</option>
        <option value="4">王二</option>
    </select>
    <label id="msg">要发送的信息</label><input type="text" id="message">
    <input type="button" id="btnsendMessage" value="发送消息" onclick="sendMessageAction()">
</form>

<script language="javascript"type="text/javascript">
    var wsUri ="ws://129.204.207.127:8887";
    var output;
    var message;
    var userToMessage;
    var websocket;

    function connectionAction() {
        output = document.getElementById("output");
        //websocket的房间
        websocket = new WebSocket(wsUri);
        //打开连接
        websocket.onopen = function(evt) {
            var loginuser = $('#loginsel option:selected').text();
            websocket.send(loginuser);
        };
        websocket.onmessage = function(evt) {
            onMessage(evt)
        };
        websocket.onerror = function(evt) {
            onError(evt)
        };
        $("#loginsel").attr("disabled","disabled");
        $("#btnconnection").attr("disabled","disabled");

        $("#btndisconnect").removeAttr("disabled");
        $("#sel").removeAttr("disabled");
        $("#msg").removeAttr("disabled");
        $("#btnsendMessage").removeAttr("disabled");
    }

    //给指定用户发送消息
    function sendMessageAction() {
        var sendTouser = $('#sel option:selected').text();
        message =document.getElementById("message").value;
        userToMessage = sendTouser +"@"+message;
        websocket.send(userToMessage);
    }

    //断开连接
    function disconnectAction() {
        websocket.close();
        writeToScreen("您已断开连接");

        $("#loginsel").removeAttr("disabled");
        $("#btnconnection").removeAttr("disabled");

        $("#btndisconnect").attr("disabled","disabled");
        $("#sel").attr("disabled","disabled");
        $("#msg").attr("disabled","disabled");
        $("#btnsendMessage").attr("disabled","disabled");
    }

  /*  function init() {
        output = document.getElementById("output");
        testWebSocket();
    }
    function testWebSocket() {
        websocket = new WebSocket(wsUri);
        websocket.onopen = function(evt) {
            onOpen(evt)
        };
        websocket.onmessage = function(evt) {
            onMessage(evt)
        };
        websocket.onerror = function(evt) {
            onError(evt)
        };
        websocket.onclose = function(evt) {
            onClose(evt)
        };
    }*/

    function onOpen(evt) {
        writeToScreen("CONNECTED");
        doSend("Zhansna");
    }

    function onClose(evt) {
        writeToScreen("您已断开连接");
        websocket.close();
    }

    //接收消息
    function onMessage(evt) {
        writeToScreen('<span style="color: blue;">RESPONSE: '+ evt.data+'</span>');
    }

    function onError(evt) {
        writeToScreen('<span style="color: red;">ERROR:</span> '+ evt.data);
    }

    function doSend(message) {
        writeToScreen("SENT: " + message);
        websocket.send(message);
    }

    function writeToScreen(message) {
        var pre = document.createElement("p");
        pre.style.wordWrap = "break-word";
        pre.innerHTML = message;
        output.appendChild(pre);
    }

    window.addEventListener("load", init, false);
</script>
<h2>WebSocket Test</h2>
<div id="output"></div>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
测试页面2

H5-WebSocket2.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>H5-WebSocket Test2</title>
    <script src="jquery.js"></script>
</head>
<body>

<br name="#" method="post">
    <!--YOUR DATA AREA-->
    <label id="a">当前用户</label>
    <select id="loginsel">
        <option value="2">李四</option>
        <option value="3">张三</option>
        <option value="4">王二</option>
    </select>
    <input type="button" value="连接" id="btnconnection" onclick="connectionAction()"/>
    <input type="button" value="断开" id="btndisconnect" onclick="disconnectAction()"/></br></br>
    <label id="b">发送对象</label>
    <select id="sel">
        <option value="1" selected>all</option>
        <option value="2">李四</option>
        <option value="3">张三</option>
        <option value="4">王二</option>
    </select>
    <label id="msg">要发送的信息</label><input type="text" id="message">
    <input type="button" id="btnsendMessage" value="发送消息" onclick="sendMessageAction()">
</form>

<script language="javascript"type="text/javascript">
    var wsUri ="ws://129.204.207.127:8887";
    var output;
    var message;
    var userToMessage;
    var websocket;

    function connectionAction() {
        output = document.getElementById("output");
        //websocket的房间
        websocket = new WebSocket(wsUri);
        //打开连接
        websocket.onopen = function(evt) {
            var loginuser = $('#loginsel option:selected').text();
            websocket.send(loginuser);
        };
        websocket.onmessage = function(evt) {
            onMessage(evt)
        };
        websocket.onerror = function(evt) {
            onError(evt)
        };
        $("#loginsel").attr("disabled","disabled");
        $("#btnconnection").attr("disabled","disabled");

        $("#btndisconnect").removeAttr("disabled");
        $("#sel").removeAttr("disabled");
        $("#msg").removeAttr("disabled");
        $("#btnsendMessage").removeAttr("disabled");
    }

    //给指定用户发送消息
    function sendMessageAction() {
        var sendTouser = $('#sel option:selected').text();
        message =document.getElementById("message").value;
        userToMessage = sendTouser +"@"+message;
        websocket.send(userToMessage);
    }

    //断开连接
    function disconnectAction() {
        websocket.close();
        writeToScreen("您已断开连接");

        $("#loginsel").removeAttr("disabled");
        $("#btnconnection").removeAttr("disabled");

        $("#btndisconnect").attr("disabled","disabled");
        $("#sel").attr("disabled","disabled");
        $("#msg").attr("disabled","disabled");
        $("#btnsendMessage").attr("disabled","disabled");
    }

  /*  function init() {
        output = document.getElementById("output");
        testWebSocket();
    }
    function testWebSocket() {
        websocket = new WebSocket(wsUri);
        websocket.onopen = function(evt) {
            onOpen(evt)
        };
        websocket.onmessage = function(evt) {
            onMessage(evt)
        };
        websocket.onerror = function(evt) {
            onError(evt)
        };
        websocket.onclose = function(evt) {
            onClose(evt)
        };
    }*/

    function onOpen(evt) {
        writeToScreen("CONNECTED");
        doSend("Zhansna");
    }

    function onClose(evt) {
        writeToScreen("您已断开连接");
        websocket.close();
    }

    //接收消息
    function onMessage(evt) {
        writeToScreen('<span style="color: blue;">RESPONSE: '+ evt.data+'</span>');
    }

    function onError(evt) {
        writeToScreen('<span style="color: red;">ERROR:</span> '+ evt.data);
    }

    function doSend(message) {
        writeToScreen("SENT: " + message);
        websocket.send(message);
    }

    function writeToScreen(message) {
        var pre = document.createElement("p");
        pre.style.wordWrap = "break-word";
        pre.innerHTML = message;
        output.appendChild(pre);
    }

    window.addEventListener("load", init, false);
</script>
<h2>WebSocket Test2</h2>
<div id="output"></div>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140

现在就可以实现H5页面之间的通信啦
以上只是H5测试用例,真正用的项目中也是这样,只不过,要根据项目需求该代码逻辑。我的项目就是版本推送和反馈消息的及时推送;

Andorid测试代码:

测试最好创建空白的Andorid app

在.gradle 引入java-websocket依赖

dependencies{
  implementation 'org.java-websocket:Java-WebSocket:1.3.0'
}
  • 1
  • 2
  • 3
页面代码

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    >

    <ScrollView
        android:id="@+id/svChat"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <Spinner
                android:id="@+id/spDraft"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <!-- ws://192.168.1.104:80/JSR356-WebSocket/websocket/ -->
            <!-- ws://192.168.1.104:8887 -->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <EditText
                    android:id="@+id/etAddress"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="4" />

                <Spinner
                    android:id="@+id/spAddress"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="2" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <!--选择登录用户-->
                <EditText
                    android:id="@+id/etloginName"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="4"
                    android:hint="选着登录名" /><!--Jack-->
                <Spinner
                    android:id="@+id/sploginName"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="2" />
            </LinearLayout>

            <Button
                android:id="@+id/btnConnect"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="连接" />

            <Button
                android:id="@+id/btnClose"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="断开" />

            <EditText
                android:id="@+id/etDetails"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@null"
                android:focusable="false"
                android:focusableInTouchMode="false"
                android:paddingTop="5dp"
                android:paddingBottom="5dp"
                android:textSize="13dp" />

            <Button
                android:id="@+id/btnClearDetails"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="清除聊天记录" />
        </LinearLayout>
    </ScrollView>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Spinner
            android:id="@+id/spName"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3"/>

        <!--<EditText
            android:id="@+id/etName"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:hint="发送对象"
            android:text=""
            android:layout_weight="1"/>--><!--Jack-->

        <EditText
            android:id="@+id/etMessage"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:hint="发送消息内容"
            android:layout_weight="4"/>

        <Button
            android:id="@+id/btnSend"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="发送"/>
    </LinearLayout>
</LinearLayout>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
逻辑代码

MainActivity.java

package com.dist.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.Spinner;

import org.java_websocket.WebSocketImpl;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_10;
import org.java_websocket.drafts.Draft_17;
import org.java_websocket.drafts.Draft_75;
import org.java_websocket.drafts.Draft_76;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ScrollView svChat;
    private Spinner spDraft;
    private EditText etAddress;
    private Spinner spAddress;

    private Spinner sploginName;
    private EditText etloginName;

    private Button btnConnect;
    private Button btnClose;
    private EditText etDetails;
    private Button btnClearDetails;

    private Spinner spName;
    //private EditText etName;
    private EditText etMessage;
    private Button btnSend;

    private WebSocketClient client;// 连接客户端
    private DraftInfo selectDraft;// 连接协议

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        svChat = (ScrollView) findViewById(R.id.svChat);
        spDraft = (Spinner) findViewById(R.id.spDraft);
        etAddress = (EditText) findViewById(R.id.etAddress);
        spAddress = (Spinner) findViewById(R.id.spAddress);

        sploginName = (Spinner) findViewById(R.id.sploginName);
        etloginName = (EditText) findViewById(R.id.etloginName);

        btnConnect = (Button) findViewById(R.id.btnConnect);
        btnClose = (Button) findViewById(R.id.btnClose);
        etDetails = (EditText) findViewById(R.id.etDetails);
        btnClearDetails = (Button) findViewById(R.id.btnClearDetails);

        spName = (Spinner) findViewById(R.id.spName);
        //etName = (EditText) findViewById(R.id.etName);
        etMessage = (EditText) findViewById(R.id.etMessage);
        btnSend = (Button) findViewById(R.id.btnSend);

        DraftInfo[] draftInfos = {new DraftInfo("WebSocket协议Draft_17", new Draft_17()), new DraftInfo
                ("WebSocket协议Draft_10", new Draft_10()), new DraftInfo("WebSocket协议Draft_76", new Draft_76()), new
                DraftInfo("WebSocket协议Draft_75", new Draft_75())};// 所有连接协议
        selectDraft = draftInfos[0];// 默认选择第一个连接协议

        ArrayAdapter<DraftInfo> draftAdapter = new ArrayAdapter<DraftInfo>(this, android.R.layout
                .simple_spinner_item, draftInfos);
        spDraft.setAdapter(draftAdapter);
        spDraft.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                selectDraft = (DraftInfo) spDraft.getItemAtPosition(position);// 选择连接协议

                etDetails.append("当前连接协议:" + selectDraft.draftName + "\n");

                Log.e("wlf", "选择连接协议:" + selectDraft.draftName);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                selectDraft = null;// 清空

                Log.e("wlf", "未选择任何连接协议");
            }
        });

        ServerInfo[] serverInfos = {new ServerInfo("连接内网web后台", "ws://192.168.2.114:8887"),new ServerInfo("连接外网web后台", "ws://129.204....:8887")};// 所有连接后台//外网的自己放到服务器上
        etAddress.setText(serverInfos[0].serverAddress);// 默认选择第一个连接协议

        ArrayAdapter<ServerInfo> serverAdapter = new ArrayAdapter<ServerInfo>(this, android.R.layout
                .simple_spinner_item, serverInfos);
        spAddress.setAdapter(serverAdapter);
        spAddress.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

                ServerInfo selectServerInfo = (ServerInfo) spAddress.getItemAtPosition(position);// 选择连接后台
                etAddress.setText(selectServerInfo.serverAddress);

                etDetails.append("当前连接后台:" + selectServerInfo.serverName + "\n");

                Log.e("wlf", "当前连接后台:" + selectServerInfo.serverName);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                selectDraft = null;// 清空

                Log.e("wlf", "未选择任何连接后台");
            }
        });

        UserNameInfo[] loginNameInfo = {new UserNameInfo("老邓", "老邓"), new UserNameInfo("老郑", "老郑"),new UserNameInfo("小金鱼", "小金鱼"),
                new UserNameInfo("张三", "张三"),new UserNameInfo("李四", "李四"),new UserNameInfo("王二", "王二")};// 登录对象
        etloginName.setText(loginNameInfo[0].name);// 默认选择第一个用户登录

        ArrayAdapter<UserNameInfo> loginNameAdapter = new ArrayAdapter<UserNameInfo>(this, android.R.layout
                .simple_spinner_item, loginNameInfo);
        sploginName.setAdapter(loginNameAdapter);
        sploginName.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

                UserNameInfo selectloginNameInfo = (UserNameInfo) sploginName.getItemAtPosition(position);// 选择连接后台
                etloginName.setText(selectloginNameInfo.name);

                etDetails.append("当前登录用户名:" + selectloginNameInfo.loginName + "\n");

                Log.e("wlf", "当前登录用户名:" + selectloginNameInfo.loginName);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                etloginName = null;// 清空

                Log.e("wlf", "未选任何登录对象");
            }
        });

        UserNameInfo[] userNameInfo = {new UserNameInfo("all", "all"),new UserNameInfo("老邓", "老邓"), new UserNameInfo("老郑", "老郑"),new UserNameInfo("小金鱼", "小金鱼"),
                new UserNameInfo("李四", "李四"), new UserNameInfo("张三", "张三"), new UserNameInfo("王二", "王二")};// 要发送的对象

        ArrayAdapter<UserNameInfo> userNameAdapter = new ArrayAdapter<UserNameInfo>(this, android.R.layout
                .simple_spinner_item, userNameInfo);
        spName.setAdapter(userNameAdapter);
        spName.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

                UserNameInfo selectuserNameInfo = (UserNameInfo) spName.getItemAtPosition(position);// 选择连接后台
               // etName.setText(selectuserNameInfo.name);

                etDetails.append("发送对象:" + selectuserNameInfo.loginName + "\n");

                Log.e("wlf", "发送对象:" + selectuserNameInfo.loginName);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
               // etName = null;// 清空

                Log.e("wlf", "未选任何发送对象");
            }
        });

        btnConnect.setOnClickListener(this);
        btnClearDetails.setOnClickListener(this);
        btnClose.setOnClickListener(this);
        btnSend.setOnClickListener(this);

        WebSocketImpl.DEBUG = true;
        System.setProperty("java.net.preferIPv6Addresses", "false");
        System.setProperty("java.net.preferIPv4Stack", "true");
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnConnect:
                try {
                    if (selectDraft == null) {
                        return;
                    }
                    if(etloginName == null){
                        return;
                    }
                    String address = etAddress.getText().toString().trim();
                    if (address.contains("JSR356-WebSocket")) {
                        //address += etName.getText().toString().trim();
                    }
                    Log.e("wlf", "连接地址:" + address);
                    client = new WebSocketClient(new URI(address), selectDraft.draft) {
                        @Override
                        public void onOpen(final ServerHandshake serverHandshakeData) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    etDetails.append("已经连接到服务器【" + getURI() + "】\n");

                                    Log.e("wlf", "已经连接到服务器【" + getURI() + "】");

                                    spDraft.setEnabled(false);
                                    etAddress.setEnabled(false);
                                    spAddress.setEnabled(false);
                                    etloginName.setEnabled(false);
                                    sploginName.setEnabled(false);

                                    btnConnect.setEnabled(false);
                                    //etName.setEnabled(false);

                                    spName.setEnabled(true);
                                    btnClearDetails.setEnabled(true);
                                    btnClose.setEnabled(true);
                                    btnSend.setEnabled(true);
                                }
                            });
                        }

                        @Override
                        public void onMessage(final String message) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    etDetails.append("获取到服务器信息【" + message + "】\n");

                                    Log.e("wlf", "获取到服务器信息【" + message + "】");
                                }
                            });
                        }

                        @Override
                        public void onClose(final int code, final String reason, final boolean remote) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    etDetails.append("断开服务器连接【" + getURI() + ",状态码: " + code + ",断开原因:" + reason +
                                            "】\n");

                                    Log.e("wlf", "断开服务器连接【" + getURI() + ",状态码: " + code + ",断开原因:" + reason + "】");

                                    spDraft.setEnabled(true);
                                    etAddress.setEnabled(true);
                                    spAddress.setEnabled(true);
                                    etloginName.setEnabled(true);
                                    sploginName.setEnabled(true);

                                    btnConnect.setEnabled(true);
                                    //etName.setEnabled(true);

                                    spName.setEnabled(false);
                                    btnClearDetails.setEnabled(true);
                                    btnClose.setEnabled(false);
                                    btnSend.setEnabled(false);
                                }
                            });
                        }

                        @Override
                        public void onError(final Exception e) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    etDetails.append("连接发生了异常【异常原因:" + e + "】\n");

                                    Log.e("wlf", "连接发生了异常【异常原因:" + e + "】");

                                    spDraft.setEnabled(true);
                                    etAddress.setEnabled(true);
                                    btnConnect.setEnabled(true);
                                    //etName.setEnabled(true);

                                    btnClearDetails.setEnabled(false);
                                    btnClose.setEnabled(false);
                                    btnSend.setEnabled(false);
                                }
                            });
                        }
                    };
                    client.connect();
                    new Thread(){
                        @Override
                        public void run(){
                            super.run();
                            try {
                                Thread.sleep(200);
                                if (client != null) {
                                    client.send(etloginName.getText().toString().trim());
                                    svChat.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            svChat.fullScroll(View.FOCUS_DOWN);
                                            etMessage.setText("");
                                            etMessage.requestFocus();
                                        }
                                    });
                                }
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }.start();

                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            case R.id.btnClearDetails:
                if (etDetails.getText().toString() != null && etDetails.getText().length()>0) {
                    etDetails.setText("");
                }
                break;
            case R.id.btnClose:
                if (client != null) {
                    client.close();
                }
                break;
            case R.id.btnSend:
                try {
                    if (client != null) {
                        //client.send(etName.getText().toString().trim() + "说:" + etMessage.getText().toString().trim());
                        //client.send(etName.getText().toString().trim() +"@"+etMessage.getText().toString().trim());
                        client.send(spName.getSelectedItem().toString().trim() +"@"+etMessage.getText().toString().trim());
                        svChat.post(new Runnable() {
                            @Override
                            public void run() {
                                svChat.fullScroll(View.FOCUS_DOWN);
                                etMessage.setText("");
                                etMessage.requestFocus();
                            }
                        });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (client != null) {
            client.close();
        }
    }

    private class DraftInfo {

        private final String draftName;
        private final Draft draft;

        public DraftInfo(String draftName, Draft draft) {
            this.draftName = draftName;
            this.draft = draft;
        }

        @Override
        public String toString() {
            return draftName;
        }
    }

    private class ServerInfo {

        private final String serverName;
        private final String serverAddress;

        public ServerInfo(String serverName, String serverAddress) {
            this.serverName = serverName;
            this.serverAddress = serverAddress;
        }

        @Override
        public String toString() {
            return serverName;
        }
    }

    private class UserNameInfo {

        private final String loginName;
        private final String name;

        public UserNameInfo(String loginName, String name) {
            this.loginName = loginName;
            this.name = name;
        }

        @Override
        public String toString() {
            return loginName;
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405

现在就可以完成H5和Andorid通信啦

************************本片文章阅读结束************************

作者:宇宙小神特别萌
个人博客:www.zhengjiaao.cn
Gitee 仓库:https://gitee.com/zhengjiaao
Github 仓库:https://github.com/zhengjiaao?tab=repositories
描述:喜欢文章的收藏一下,避免以后找不到哦,大家遇到问题下方可评论

************************本片文章阅读结束************************
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/601187
推荐阅读
相关标签
  

闽ICP备14008679号