**
Android实现基于webSocket的事件回传达到同屏操控效果
在某些需求开发中,我们也许会遇到这样的需求:实现一个App内部的同屏控制,一台设备控制多台设备进行同步点击。达到同屏的效果。同屏的实现有很多种方法,可以采用rtmp手机录屏推流进行实时直播、也可采用截屏的方式对手机屏幕进行实时socket等,但是这些都是基于屏幕分享的形式。
这里我们不采用屏分享,博主的解决方案是对app内部的点击事件进行实时消息推送(适用于小型软件),我点那里,其他设备跟着一起点哪里。要实现这样的效果传统的http协议当然是不行的,因此我们采用可以长连接的webSocket,采用webSocket建立一个长连接平台。具体实现步骤如下:
(以下为Android端的实现步骤,服务器端的实现请看这里[https://blog.csdn.net/qq_40520781/article/details/113371099])
一、 gradle引入netty依赖
//netty
implementation group: 'io.netty', name: 'netty-all', version: '4.1.50.Final'
二、 新建一个ChartClient类用于连接服务器
发起连接的方法
public void connect(){
group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.group(group);
bootstrap.channel(NioSocketChannel.class);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder",new StringDecoder());
pipeline.addLast("encoder",new StringEncoder());
pipeline.addLast(new ChartClientHandler());
}
});
ChannelFuture cf = bootstrap.connect(host, port).sync();
mChannel = cf.channel();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
发送消息的方法(当发送消息的时候,我们使用Handler发送消息到主线程去控制提示信息的显示,告诉用户现在的连接状态)
public void sendData(String msg){
if (mChannel == null){
Message message = new Message();
message.what = 400;
App.getMsgHandler().sendMessage(message);
return;
}
if (mChannel.isOpen()){
try{
mChannel.writeAndFlush(msg+"\n");
}catch (Exception e){
e.printStackTrace();
Message message = new Message();
message.what = 446;
App.getMsgHandler().sendMessage(message);
}
}else {
Message message = new Message();
message.what = 400;
App.getMsgHandler().sendMessage(message);
}
}
断开连接的方法
public void disConnect(){
if (mChannel == null){
Message message = new Message();
message.what = 400;
App.getMsgHandler().sendMessage(message);
return;
}
if (mChannel.isOpen()){
mChannel.close();
}else {
Message message = new Message();
message.what = 600;
App.getMsgHandler().sendMessage(message);
}
if (!group.isShutdown()){
group.shutdownGracefully();
}
}
与服务器端一样,我们通过Handler进行消息处理,所以我们需要创建一个Handler继承一下SimpleChannelInboundHandler
重写channelRead0方法用于读取从服务器发过来的消息
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Message message = new Message();
message.what=0x01;
Bundle mBUndle = new Bundle();
mBUndle.putString("msg",msg);
message.setData(mBUndle);
App.getMsgHandler().sendMessage(message);
}
这里我们拿到消息以后,使用Handler将消息发送到主线程进行处理。
因为我们要控制的是事件的同步点击,因此我们要在主程序的Application里面接收消息。
这里最好新建一个App类继承自我们的Application,在app里面写一个Handler用于处理我们的消息回传
到这里我们已经实现了服务器的连接和消息的接收,接下来,我们要处理消息的发送和事件的自动触发
实现消息的发送首先我们要先连接服务器,我们在程序启动的时候,就向服务器发起连接
在mainActivity中的onCreate方法中创建一个连接对象、再创建一个子线程去发起连接,并捕获连接异常。
Screen是我封装的一个对象,用于存放事件类型和主机地址、连接状态、是否主控、是否被控、端口号等等的,大家可以根据自己的需要也去封装一个。
设备接入以后我们需要检查一下是否处于连接状态,如果有主控设备正在控制中,设备将自动同步到主控屏幕的屏幕状态(这里是采用字符串的形式进行传参,后端根据需要截取字符串,并判断事件类型,再对事件进行分发处理)
所以我们发送事件是通过调用chartClient的sendData()方法直接将事件参数拼接成字符串发送到服务器端,服务器端再通过对消息的处理,回传回来对应的时间信息,如果用户的设备是非主控设备,那么设备就会自动执行事件。
客服端收到消息后,在App中的handler里面进行处理,我的处理方式是根据事件类型去判断触发了申明事件,从而让我们的app自动去点击
消息都是发到对应的主线程去执行。
最终实现效果如下:
注:演示应用是适配平板的,所以ui看起来有些奇怪
**
我总觉得我没有讲清楚这个实现过程,如果有需要却看不懂的小伙伴,可以私信我1436562842@qq.com