精华内容
下载资源
问答
  • android同屏

    2017-11-13 18:05:20
    android同屏,在13年基础上修改。利用5.0自带屏幕截图,发送到PC端。低延迟
  • android同屏到pcMicrosoft微软If you have an Android smartphone and a Windows 10 PC, you can now sync your Android phone’s notifications to your PC and see them on your desktop. This feature was ...
    android同屏到pc

    android同屏到pc

    Person using Android notification sync on a Windows 10 laptop
    Microsoft
    微软

    If you have an Android smartphone and a Windows 10 PC, you can now sync your Android phone’s notifications to your PC and see them on your desktop. This feature was previously in testing, but is now available to everyone.

    如果您拥有Android智能手机和Windows 10 PC,则现在可以将Android手机的通知同步到PC并在桌面上查看它们。 此功能以前曾在测试中,但现在每个人都可以使用。

    To use this feature, you’ll just need to set it up in the Your Phone app. The Your Phone app also lets you sync photos to your PC and text from your PC. A future version—already in testing—will let you mirror your Android phone’s entire screen to your desktop and interact with it from your PC. If you use Android, we highly recommend setting this app up—especially now that notification-mirroring is finally available.

    要使用此功能,只需在“电话”应用中进行设置。 您的手机应用程序还允许您将照片同步到PC上,并从PC上同步文本。 将来的版本(已经在测试中)将使您可以将Android手机的整个屏幕镜像到桌面,并可以通过PC与之交互。 如果您使用的是Android,我们强烈建议您设置此应用,尤其是现在终于可以使用通知镜像了。

    Notifications have arrived! With the Your Phone app, you can now receive and manage your Android phone’s notifications on your PC. Get Your Phone app from the Microsoft Store here: https://t.co/E56Z8eVdIR pic.twitter.com/ovlKi1QOJy

    通知已到! 借助您的手机应用程序,您现在可以在PC上接收和管理Android手机的通知。 从此处的Microsoft Store获取您的Phone应用: https: //t.co/E56Z8eVdIR pic.twitter.com/ovlKi1QOJy

    — Windows Insider (@windowsinsider) July 2, 2019

    — Windows Insider(@windowsinsider) ,2019年7月2日

    Don’t worry, it’s not all-or-nothing—you can choose exactly which app notifications you want to sync to your Windows 10 PC. Dismissing a notification on your PC will also dismiss it on your phone, so you won’t have to dismiss the same notification twice.

    不用担心,这不是全部或全部—您可以精确选择要同步到Windows 10 PC的应用程序通知。 在PC上取消通知也将在手机上将其关闭,因此您不必两次取消相同的通知。

    The Your Phone app is compatible with Windows 10’s April 2018 Update (version 1803), October 2018 Update (version 1809), and May 2019 Update (version 1903). If you install the app and don’t see the feature yet, wait a day or two—these things roll out gradually and not everyone will get the new features all at once.

    Your Phone应用程序与Windows 10的2018年4月更新(版本1803),2018年10月更新(版本1809)和2019年5月更新(版本1903)兼容。 如果您安装了该应用程序,但仍未看到该功能,则请等待一两天,这些事情会逐步推出,并且并不是每个人都会一次获得所有新功能。

    翻译自: https://www.howtogeek.com/427431/windows-10-can-now-sync-android-notifications-to-your-pc/

    android同屏到pc

    展开全文
  • 3、EasyIPCamera Android同屏主播端,版本更新地址:https://github.com/EasyDarwin/EasyIPCamera/releases(扫描下载地址:https://fir.im/EasyIPCamera) 4、EasyPlayer Android同屏播放端,版本更新地址:...
  • 近期用了一个完全免费的安卓手机投屏软件,感觉一下子想上天,因此,在这儿给大家介绍一下下。 最开始是由于教朋友们玩手机游戏,全挤在一个小小手机显示眼前确实是干扰操作方法,因此就想把手机的显示投影到...

    近期用了一个完全免费的安卓手机投屏软件,感觉一下子想上天,因此,在这儿给大家介绍一下下。
    最开始是由于教朋友们玩手机游戏,全挤在一个小小手机显示屏眼前确实是干扰操作方法,因此就想把手机的显示屏投影到电脑上,那样看的人清楚,我这个教的人也非常容易解说。
    因此刚开始百度搜索、Google、知乎问答这些,杂七杂八搜寻一通,相比之下。
    是因为,是完全免费哒~~~~~哈哈哈哈哈哈哈哈哈哈~~~~
    返回正题,这一个手机软件是如何使用的呢?
    下边我就用我的小米手机为大家讲解一遍~
    最先第1步便是在手机和pc端上面安装好手机软件,都能够在官网上免费下载,手机的App还可以在小米助手里面免费下载。


    都安装好手机软件后,打开,在手机的App上有个“投影至电脑上”的功能,立即点一下“投影”,就会出現电脑上的无线名称(谨记:这一个的操作方法的先决条件是要确保手机和电脑上是在相同互联网的环境下,否则就出現不了电脑上的无线名称了!)。


    连上电脑上的无线名称后,你的手机显示屏就出現在电脑上啦~


    无论是玩手机游戏,還是播放视频,都能够大屏幕的投影到电脑上。


    当手机游戏正在精彩处,还可以一键截图,一下子微信发朋友圈,装B道路上不需要等候!
    你也能够试一试哦~

    推荐阅读:

    展开全文
  • vysor原理以及Android同屏方案

    千次阅读 2016-12-29 15:34:04
    因为Android是基于linux内核,所以我们也能在android中找到framebuffer这个设备,我们可以通过读取/dev/graphics/fb0这个帧缓存文件中的数据来获取屏幕上的内容,但是这个文件是system权限的,所以只有通过root才能...

    vysor是一个免root实现电脑控制手机的chrome插件,目前也有几款类似的通过电脑控制手机的软件,不过都需要root权限,并且流畅度并不高。vysor没有多余的功能,流畅度也很高,刚接触到这款插件时我惊讶于它的流畅度以及免root,就一直对它的实现原理很感兴趣。这款插件我用了大半年,最近在升级后我发现它居然开始收费了,终生版需要39.99美元,不过经过简单的分析后我很轻松的破解了它的pro版,在分析的过程中发现它的原理并不复杂,所以就打算自己也实现一个类似的软件。

    截屏常见的方案

    在介绍vysor的原理前我先简单介绍一下目前公开的截屏方案。

    • View.getDrawingCache()

    这是最常见的应用内截屏方法,这个函数的原理就是通过view的Cache来获取一个bitmap对象,然后保存成图片文件,这种截屏方式非常的简单,但是局限行也很明显,首先它只能截取应用内部的界面,甚至连状态栏都不能截取到。其次是对某些view的兼容性也不好,比如webview内的内容也无法截取。

    • 读取/dev/graphics/fb0

    因为Android是基于linux内核,所以我们也能在android中找到framebuffer这个设备,我们可以通过读取/dev/graphics/fb0这个帧缓存文件中的数据来获取屏幕上的内容,但是这个文件是system权限的,所以只有通过root才能读取到其中的内容,并且直接通过framebuffer读取出来的画面还需要转换成rgb才能正常显示。下面是通过adb读取这个文件内容的效果。

    • 反射调用SurfaceControl.screenshot()/Surface.screenshot()

    SurfaceControl.screenshot()(低版本是Surface.screenshot())是系统内部提供的截屏函数,但是这个函数是@hide的,所以无法直接调用,需要反射调用。我尝试反射调用这个函数,但是函数返回的是null,后面发现SurfaceControl这个类也是隐藏的,所以从用户代码中无法获取这个类。也有一些方法能够调用到这个函数,比如重新编译一套sdk,或者在源码环境下编译apk,但是这种方案兼容性太差,只能在特定ROM下成功运行。

    • screencap -p xxx.png/screenshot xxx.png

    这两个是在shell下调用的命令,通过adb shell可以直接截图,但是在代码里调用则需要系统权限,所以无法调用。可以看到要实现类似vysor的同步操作,可以使用这两个命令来截取屏幕然后传到电脑显示,但是我自己实现后发现这种方式非常的卡,因为这两个命令不能压缩图片,所以导致获取和生成图片的时间非常长。

    • MediaProjection,VirtualDisplay (>=5.0)

    在5.0以后,google开放了截屏的接口,可以通过”虚拟屏幕”来录制和截取屏幕,不过因为这种方式会弹出确认对话框,并且只在5.0上有效,所以我没有对这种方案做深入的研究。

    可以看到,上述方案中并没有解决方案能够做到兼容性和效率都非常完美,但是我在接触到vysor后发现它不但画面清晰,流畅,而且不需要root。那么它是用了什么黑科技呢?下面我们反编译它的代码来研究一下它的实现机制。

    vysor原理

    反编译vysor的apk后可以发现它的代码并不多,通过分析后我发现它的核心代码在Main这个类中。

    首先来看Main函数的main方法,这个方法比较长,这里直接贴出源码。

    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
    
    public static void main(String[] args) throws Exception {
            if (args.length > 0) {
                commandLinePassword = args[0];
                Log.i(LOGTAG, "Received command line password: " + commandLinePassword);
            }
            Looper.prepare();
            looper = Looper.myLooper();
            AsyncServer server = new AsyncServer();
            AsyncHttpServer httpServer = new AsyncHttpServer() {
                protected boolean onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
                    Log.i(Main.LOGTAG, request.getHeaders().toString());
                    return super.onRequest(request, response);
                }
            };
            String str = "getInstance";
            Object[] objArr = new Object[0];
            InputManager im = (InputManager) InputManager.class.getDeclaredMethod(r20, new Class[0]).invoke(null, objArr);
            str = "obtain";
            MotionEvent.class.getDeclaredMethod(r20, new Class[0]).setAccessible(true);
            str = "injectInputEvent";
            Method injectInputEventMethod = InputManager.class.getMethod(r20, new Class[]{InputEvent.class, Integer.TYPE});
            KeyCharacterMap kcm = KeyCharacterMap.load(-1);
            Class cls = Class.forName("android.os.ServiceManager");
            Method getServiceMethod = cls.getDeclaredMethod("getService", new Class[]{String.class});
            IClipboard clipboard = IClipboard.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"clipboard"}));
            clipboard.addPrimaryClipChangedListener(new AnonymousClass3(clipboard), null);
            IPowerManager pm = IPowerManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"power"}));
            IWindowManager wm = IWindowManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"window"}));
            IRotationWatcher watcher = new Stub() {
                public void onRotationChanged(int rotation) throws RemoteException {
                    if (Main.webSocket != null) {
                        Point displaySize = SurfaceControlVirtualDisplayFactory.getCurrentDisplaySize();
                        JSONObject json = new JSONObject();
                        try {
                            json.put("type", "displaySize");
                            json.put("screenWidth", displaySize.x);
                            json.put("screenHeight", displaySize.y);
                            json.put("nav", Main.hasNavBar());
                            Main.webSocket.send(json.toString());
                        } catch (JSONException e) {
                        }
                    }
                }
            };
            wm.watchRotation(watcher);
            httpServer.get("/screenshot.jpg", new AnonymousClass5(wm));
            httpServer.websocket("/input", "mirror-protocol", new AnonymousClass6(watcher, im, injectInputEventMethod, pm, wm, kcm));
            httpServer.get("/h264", new AnonymousClass7(im, injectInputEventMethod, pm, wm));
            Log.i(LOGTAG, "Server starting");
            AsyncServerSocket rawSocket = server.listen(null, 53517, new AnonymousClass8(wm));
            if (httpServer.listen(server, 53516) == null || rawSocket == null) {
                System.out.println("No server socket?");
                Log.e(LOGTAG, "No server socket?");
                throw new AssertionError("No server socket?");
            }
            System.out.println("Started");
            Log.i(LOGTAG, "Waiting for exit");
            Looper.loop();
            Log.i(LOGTAG, "Looper done");
            server.stop();
            if (current != null) {
                current.stop();
                current = null;
            }
            Log.i(LOGTAG, "Done!");
            System.exit(0);
        }
    

     

    这个软件koushikdutta是由开发的,这个团队以前发布过一个非常流行的开源网络库:async。在这个项目中也用到了这个开源库。main函数主要是新建了一个httpserver然后开放了几个接口,通过screenshot.jpg获取截图,通过socket input接口来发送点击信息,通过h264这个接口来获取实时的屏幕视频流。每一个接口都有对应的响应函数,这里我们主要研究截图,所以就看screenshot这个接口。h264这个接口传输的是实时的视频流,所以就流畅性来说应该会更好,它也是通过virtualdisplay来实现的有兴趣的读者可以自行研究。

    接下来我们来看screenshot对应的响应函数AnonymousClass5的实现代码。

    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
    
    * renamed from: com.koushikdutta.vysor.Main.5 */
        static class AnonymousClass5 implements HttpServerRequestCallback {
            final /* synthetic */ IWindowManager val$wm;
    
            AnonymousClass5(IWindowManager iWindowManager) {
                this.val$wm = iWindowManager;
            }
    
            public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
                if (Main.checkPassword(request.getQuery().getString("password"))) {
                    Log.i(Main.LOGTAG, "screenshot authentication success");
                    try {
                        Bitmap bitmap = EncoderFeeder.screenshot(this.val$wm);
                        ByteArrayOutputStream bout = new ByteArrayOutputStream();
                        bitmap.compress(CompressFormat.JPEG, 100, bout);
                        bout.flush();
                        response.send("image/jpeg", bout.toByteArray());
                        return;
                    } catch (Exception e) {
                        response.code(500);
                        response.send(e.toString());
                        return;
                    }
                }
                Log.i(Main.LOGTAG, "screenshot authentication failed");
                response.code(401);
                response.send("Not Authorized.");
            }
        }
    

     

    这个类传入了一个wm类,这个类是用来监听屏幕旋转的,这里不用管它。另外在vysor开始运行时,会随机生成一个验证码,只有验证通过才能进行连接,所以这里有一个验证的过程,这里也不过管。可以看到这个类定义的响应函数的代码非常简单,就是通过EncoderFeeder.screenshot()函数来过去截图的bitmap,然后返回给请求端。那么EncoderFeeder.screenshot这个函数是怎样实现截图的呢?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    public static Bitmap screenshot(IWindowManager wm) throws Exception {
            String surfaceClassName;
            Point size = SurfaceControlVirtualDisplayFactory.getCurrentDisplaySize(false);
            if (VERSION.SDK_INT <= 17) {
                surfaceClassName = "android.view.Surface";
            } else {
                surfaceClassName = "android.view.SurfaceControl";
            }
            Bitmap b = (Bitmap) Class.forName(surfaceClassName).getDeclaredMethod("screenshot", new Class[]{Integer.TYPE, Integer.TYPE}).invoke(null, new Object[]{Integer.valueOf(size.x), Integer.valueOf(size.y)});
            int rotation = wm.getRotation();
            if (rotation == 0) {
                return b;
            }
            Matrix m = new Matrix();
            if (rotation == 1) {
                m.postRotate(-90.0f);
            } else if (rotation == 2) {
                m.postRotate(-180.0f);
            } else if (rotation == 3) {
                m.postRotate(-270.0f);
            }
            return Bitmap.createBitmap(b, 0, 0, size.x, size.y, m, false);
        }
    

    这里的截图的核心代码也是反射调用Surface/SurfaceControl的screenshot方法。但是我们前面已经了解到,这个类只有在系统权限下才能获取到,那么vysor又是怎么调用到这个函数的呢?我们可以确认的是vysor不是通过重编译sdk和使用系统签名来完成的,因为那样只能对特定的rom适用。

    当时看到这里的代码后我也非常困惑,vysor是怎么调用到这个类的。我注意到了vysor的核心代码不是在某个Activity或者Service中而是在一个Main类中,按照一般的逻辑来说,这种实时传屏应该是放在Service中不断截屏然后发给服务端,所以我决定再看下它的服务端的代码。

    vysor的服务端是一个chrome插件,用javascript写成的,所以找到源码比java更加简单。虽然js经过混淆,但是很容易的可以通过一些工具来解密。然后就是分析它的代码了,终于被我找到了关键的代码。

    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
    
    function y(e, t, n) {
            m(e, "Connecting...");
    
            function o(o) {
                var i = Math.round(Math.random() * (1 << 30)).toString(16);
                var r = "echo -n " + i + " > /data/local/tmp/vysor.pwd ; chmod 600 /data/local/tmp/vysor.pwd";
                Adb.shell({
                    command: "ls -l /system/bin/app_process*",
                    serialno: e
                }, function(s) {
                    var c = "/system/bin/app_process";
                    if (s && s.indexOf("app_process32") != -1) {
                        c += "32"
                    }
                    Adb.sendClientCommand({
                        command: 'shell:sh -c "CLASSPATH=' + o + " " + c + " /system/bin com.koushikdutta.vysor.Main " + i + '"',
                        serialno: e
                    }, function(o) {
                        Adb.shell({
                            serialno: e,
                            command: 'sh -c "' + r + '"'
                        }, function(e) {
                            Socket.eat(o);
                            n(t, i)
                        })
                    })
                })
            }
    

    可以看到上面的代码是调用了adb shell命令来启动com.koushikdutta.vysor.Main类,并且上面获取了app_process这个程序。相信对android熟悉读者已经明白它的原理了。我简单解释一下。我们已经知道Surface/SurfaceControl这两个类是需要具有相应权限的程序才能调用到,用户进程无法获取到。adb shell可以调用screencap或者screenshot来截取屏幕,那就说明adb shell具有截屏的权限。Surface/SurfaceControl和screenshot/screencap它们内部的实现机制应该是相同的,所以也就是说adb shell是具有截屏权限的也就是能够调用到Surface/SurfaceControl。那么我们怎么通过adb shell来调用到这两个类呢,答案就是app_process。app_process可以直接运行一个普通的java类,详细的资料大家可以在网上找到。也就是说我们通过adb shell运行app_process,然后通过app_process来运行一个java类,在java类中就可以访问到Surface/SurfaceControl这两个类,是不是很巧妙?

    理论有了,下面我们来通过代码验证。这里我们可以直接使用vysor的代码。因为是测试用所以我没有添加其他功能。

    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
    
    public class Main {
    
    
        static Looper looper;
    
        public static void main(String[] args) {
    
            AsyncHttpServer httpServer = new AsyncHttpServer() {
                protected boolean onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
                    return super.onRequest(request, response);
                }
            };
    
            Looper.prepare();
            looper = Looper.myLooper();
            System.out.println("Andcast Main Entry!");
            AsyncServer server = new AsyncServer();
            httpServer.get("/screenshot.jpg", new AnonymousClass5());
            httpServer.listen(server, 53516);
    
            Looper.loop();
    
        }
    
        /* renamed from: com.koushikdutta.vysor.Main.5 */
        static class AnonymousClass5 implements HttpServerRequestCallback {
    
            public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
                    try {
                        Bitmap bitmap = ScreenShotFb.screenshot();
                        ByteArrayOutputStream bout = new ByteArrayOutputStream();
                        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bout);
                        bout.flush();
                        response.send("image/jpeg", bout.toByteArray());
                        return;
                    } catch (Exception e) {
                        response.code(500);
                        response.send(e.toString());
                        return;
                    }
            }
        }
    }
    

     

    编译成apk然后安装后,我们使用adb shell来运行这个类,主要方法如下,首先导出classpath,否则会提示找不到类。

    1
    
    export CLASSPATH=/data/app/com.zke1e.andcast-1/base.apk
    

     

    然后调用app_process来启动这个类。

    1
    
    exec app_process /system/bin com.zke1e.andcast.Main '$@'
    

     

    可以看到类已经成功运行了,正在监听请求。

    然后使用adb forward转发端口。

    1
    
    adb forward tcp:53516 tcp:53516
    

    最后在浏览器里访问,就可以获取截图了。

    当然只有简单的截图功能是不够,我们需要能够流畅实时的传输android的屏幕,并且能够在电脑上控制,经过两天的编写,我使用java实现了类似vysor的功能。从流畅度和清晰度上都和vysor差不多,后续还会考虑加入文件传输和声音传输等功能。最近计划编写一个java版的android反编译集成环境,类似android killer。因为android killer只能在windows上使用,而linux下没有类似的方面的软件。到时这个同步软件可以作为插件和反编译套件集成。最后放一张截图。

    更新

    经过一段时间的研究,最后实现了将传输的截图改成了h264码流,提高的流畅度和稳定性,然后将接受端放在了浏览器中,实现了可以在浏览器中对android手机进行控制,下面是截图。

     

    原文地址:http://zke1ev3n.me/2016/07/02/vysor原理以及Android同屏方案/

    展开全文
  • android端通过usb将pc端的屏幕实时的显示在android端。
  • 安卓屏幕同步

    2018-03-09 10:25:51
    用于安卓屏幕同步,asm.jar Android Screen 执行下面命令: > java -jar asm.jar
  • 双端同屏

    web 端 与 android h5 端 界面同屏(同步效果)设计方案

    看到这个标题是不是 很新鲜呀?好牛!哈哈 其实说说它的原理大家就觉得没啥稀奇的了!这个案例是本人设计的,现在分享给大家。如果有什么更好的方案,或者什么 想法可以一起讨论!好的废话补多少上才艺。
    1. 首先大家需要具备的东西,js ,css ,jquery, webSocket 网络协议,java 这些是案例所具备的必备技能。至少这是此案例所涉及的东西。
    2. 了解android h5 是咋个回事!这个案例使用了apiCloud ,这个东西放你封装webScoket 方便了很多
    3. 自己需要搭建webSocket ,很废话的样子!自己搭建websocket 方便自己定义 发送msg 的数据逻辑,如果逻辑不可控,就谈不上开发功能。
    4. 上逻辑
      websocket 是基于http/tcp 请求的场链接协议,如果提及websocket 好多人都知道这是用在聊天室功能!与http/tcp 区别在于不用每次建立连接,建立一次只要不销毁界面对象,它一直都会连接,而且可以主动向客户端发送内容,但前提是要触发一下。这个东西我不在这个地方做阐述。请参考 链接: https://zhuanlan.zhihu.com/p/160910342
      上场景
      a 端触发操作 希望看到 b 端 界面也同样触发了相同操作 如图

    在这里插入图片描述
    如果android h5 触发1号按钮 ,在 web端 也应该 看到 1号按钮自己开了,同样 web 端触发 1号按钮那么 android 端也应还 自动开启 1号按钮 。当然其他操作雷同效果!

    问题1 webSocket 如何知道哪两个页面互通消息 ?
    解答 看设计方案: web端 webSocket连接地址后缀 是 系统window+随机数+关键字sf+设施id
    android 端websocket 连接地址后缀是 系统android+随机数+关键字sf+设施id
    websocket 连接后缀 有关键字要保持一致 设施id 保持一致。大家都知道websocket 是以广播形式发送消息个各个客户端的。怎么可以可以知道这两个是一个设备界面呢!连接时 后缀关键字和id 一致的他们属于一个设备界面,需要同步屏幕效果!每个连接进入websocket 时 用后缀存储为key 此链接为 值创建 map 的session 连接池。 发送消息时 可以发送json 字符串

    先看java websocket 代码

    
    import javax.websocket.*;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * websocktService 核心类
     */
    
    @ServerEndpoint("/webSocket/{sid}")
    @Component
    public class WebSocketService {
        //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
        private static AtomicInteger onlineNum = new AtomicInteger();
    
        //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
        private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();
    
        public static Map<String, Object> viewData;
    
        //发送消息
        public void sendMessage(Session session, String message) throws IOException {
            if (session != null) {
                synchronized (session) {
                    System.out.println("发送数据:" + message);
                    session.getBasicRemote().sendText(message);
                }
            }
        }
    
        //给指定用户发送信息
        public void sendInfo(String userName, String message) {
            Session session = sessionPools.get(userName);
            try {
                sendMessage(session, message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //建立连接成功调用
        @OnOpen
        public void onOpen(Session session, @PathParam(value = "sid") String userName) {
            sessionPools.put(userName, session);
            addOnlineCount();
            System.out.println(userName + "加入webSocket!当前人数为" + onlineNum);
            try {
                sendMessage(session, "欢迎" + userName + "加入连接!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //关闭连接时调用
        @OnClose
        public void onClose(@PathParam(value = "sid") String userName) {
            sessionPools.remove(userName);
            subOnlineCount();
            System.out.println(userName + "断开webSocket连接!当前人数为" + onlineNum);
        }
    
        //收到客户端信息
        @OnMessage
        public void onMessage(String message) throws IOException {
            String text = "客户端:" + message + ",已收到";
            Map<String, String> map = null;
            if (message.contains("viewFlag")) {
                map = StaticToolUtils.gson.fromJson(message, Map.class);
            }
            System.out.println(text);
            for(String userName:sessionPools.keySet()){
                try {
                    if(map!=null) {
                        if (userName.contains(map.get("obj")) && userName.contains(map.get("objId"))) {
                            if (StringUtils.equals(userName, map.get("sid"))) {
                                continue;
                            }
                            sendMessage(sessionPools.get(userName), message);
                        }
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }
    
        public static void   SendMsg(SendMsg msg){
            for(String userName:sessionPools.keySet()){
                if(msg!=null) {
                    if(StringUtils.isNotEmpty(msg.getObj())&&msg.getObjId()>0) {
                        try {
                            if (userName.contains(msg.getObj()) && userName.contains(msg.getObjId().toString())) {
                                sendMessage1(sessionPools.get(userName), StaticToolUtils.gson.toJson(msg));
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            continue;
                        }
                    }
                }
            }
        }
    
        //发送消息
        public static void sendMessage1(Session session, String message) throws IOException {
            if (session != null) {
                synchronized (session) {
                    System.out.println("发送数据:" + message);
                    session.getBasicRemote().sendText(message);
                }
            }
        } 
        
        
        //错误时调用
        @OnError
        public void onError(Session session, Throwable throwable) {
            System.out.println("发生错误");
            throwable.printStackTrace();
        }
    
        public static void addOnlineCount() {    // 上线的人数加一
            onlineNum.incrementAndGet();
        }
    
        public static void subOnlineCount() { // 上线的人数减一
            onlineNum.decrementAndGet();
        }
    
    
    
    @ServerEndpoint("/webSocket/{sid}")
    @Component
    

    这就是websocket 需要加后缀的原因 希望大家不要跳着看我的代码

    1.看看连接的代码片段

      //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
        private static AtomicInteger onlineNum = new AtomicInteger();
    
        //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
        private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();
    
        public static Map<String, Object> viewData;
    
     //建立连接成功调用
        @OnOpen
        public void onOpen(Session session, @PathParam(value = "sid") String userName) {
            sessionPools.put(userName, session);
            addOnlineCount();
            System.out.println(userName + "加入webSocket!当前人数为" + onlineNum);
            try {
                sendMessage(session, "欢迎" + userName + "加入连接!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    

    存储各个websocket 的连接 用key /val 的 map形式存储
    window_739_fk_1000008230655
    android_789_fk_1000008230655 这两个后缀的连接 需要同屏 你明白了吗?

    2.一旦触发一个按钮 我们就向 webSocket 发送 json {viewFlag:””,obj:”fk”,objid:”1000008230655”,data:{}} 内容包含 关键字fk ,设施id 1000008230655 . fk 只是做对象扩展。关键字没有实质的意义。只是为了扩展业务使用。
    再看看 这边接收到消息的代码处理

      //收到客户端信息
        @OnMessage
        public void onMessage(String message) throws IOException {
            String text = "客户端:" + message + ",已收到";
            Map<String, String> map = null;
            if (message.contains("viewFlag")) {
                map = StaticToolUtils.gson.fromJson(message, Map.class);
            }
            System.out.println(text);
            for(String userName:sessionPools.keySet()){
                try {
                    if(map!=null) {
                        if (userName.contains(map.get("obj")) && userName.contains(map.get("objId"))) {
                            if (StringUtils.equals(userName, map.get("sid"))) {
                                continue;
                            }
                            sendMessage(sessionPools.get(userName), message);
                        }
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }
    

    这边就简单解释一下,消息发过来 一看到时自己的连接, 跳过消息不处理。不如 window_739_fk_1000008230655 连接 发的消息 自己是不处理的 ,但是 android_789_fk_1000008230655 连接的客户端 接收到消息 就进行处理一下。发送消息需要含有这些连接关键信息。关键行的的业务逻辑已经讲完了。

    3.在讲些辅助的东西
    在这里插入图片描述
    代码不能贴给你们 因为这个不是场景的代码长 全贴给你们会干扰你们。
    在 接收到信息后,解析信息内容,信息自定义 ,彩笔划掉的地方是js 执行体,也就是说 当window_739_fk_1000008230655 点击按钮 发json 数据, android_789_fk_1000008230655 接收数据
    并解析json 数据 通过viewFlag 内容判断 window_739 执行什么操作, 在 通过data 数据 的内容补充,执行相应操作的js 操作即可。好好消化一下 我所说的,如果问我要 全部的代码 !我会鄙视你的!哈哈哈!如果看懂了可以给个好评!如果看不懂 请拨打我的电话 13072192261 dafl , 技术讨论 可以有的!好的我要下线了!!!!!。

    展开全文
  • Vysor是一款将Android画面投影到桌面的Chrome插件,最大的优点是快、轻,支持Mac、Windows、Linux平台。 安装也很简单: 1、打开Chrome 网上应用商店,搜索Vysor,点击[添加至Chrome]; 2、安装成功后重启Chrome;...
  • 本文研究的是基于Linux系统的同屏器是如何通过USB数据线获取Android系统的视频流,从而实现同步播放的功能,并对其中涉及到的screenrecord截屏技术、ADB技术、libusb技术、alsa声卡技术、AOA技术进行探究。
  • 主要是用来实现android 平板 手机的同屏互动,传送手机屏幕到平板!以下是我发布的优酷视频:http://v.youku.com/v_show/id_XNzM2NzI0NzQ0.html 目前实现的是sink端,source还在实现中!
  • android 接收屏幕广播例子
  • 最近在EasyDarwin开源群里,有不少用户私信需求,要做一种能够多端同屏的系统,细分下来有屏幕采集端和同屏端,屏幕采集端细想也就是一个低延时的流媒体音视频服务器,同屏端也就是一个低延时的播放器,负责播放屏幕...
  • 精品文档 安卓手机无线同屏具体操作步骤如下 注无线同屏的实现慧投 H 系列产品和手机必须在同一 WiFi 下才能实现同屏 步骤 1 打开慧投 H系列产品选择开始设置 步骤 2 进入系统设置 1欢迎下载 精品文档 步骤 3 选择...
  • Android电脑源码通过adb实现实时屏幕演示源码,是一个很不错的Android代码,有兴趣的伙伴们抽时间可以看一下把。
  • 共享你的屏幕和音频到另一台手机 具体分辨率,帧率,声道,和采样率因机型而定 手动狗头.
  • 2.安卓android设备同屏 2.1同屏模式(miracast) 2.2推送模式(DLNA) 3.电脑windows同屏(适合会议、教学培训等) 3.1同屏不联网 3.2同屏联网 4 投屏加密 4.1 安卓投屏加密 4.2 苹果设备投屏加密 4.3 电脑Windows...
  • 环境:为官方下载的2017-11-29-raspbian-stretch硬件:树莓派3B使用adb连接与安卓手机同屏,手机需要打开usb调试(开发者选项里)1、先添加一个源来下载android-tools-adb 打开/etc/apt/sources.list这个软件源列表...
  • android 双屏多显, 副实现播放功能android 双屏多显, 副实现播放功能android 双屏多显, 副实现播放功能android 双屏多显, 副实现播放功能
  • 雷锋:可以去官网下载最新版本。https://er.run/ 苹果电脑和苹果手机 苹果电脑和安卓手机 windows和苹果手机 windows和安卓手机
  • 使用Android Screen Monitor将安卓手机屏幕同步到电脑(windows和linux都可以)上,asm.jar相当于一个工具可以直接运行,然后就可以同步手机屏幕了
  • 那么就需要在靠近客户的地方展示二维码,这里我们有一台安卓平板,平时轮播广告,而当客户确认信息时,在屏幕右下方弹出二维码方便顾客扫码。(PC和Android优先采用USB线连接)   解决方案 (1)在PC机上使用此...
  • Miracast、DLNA与AirPlay均可支持,该app可以远程管理同屏设备,方便连接。
  • 主要实现了android 5.0以上设备屏幕分享到局域网内其他设备,从而达到屏幕共享。(采用udp通信传输图片,有2秒延迟)
  • Android Screen Monitor同步手机屏幕到PC
  • 两个android设备连接同一wifi,分别安装两个apk,实现将一个设备的屏幕投射给另一个android设备,视频码率清晰度可配置。 资源链接:https://download.csdn.net/download/weixin_41532138/11419469 ...
  • Android实现基于webSocket的事件回传达到同屏操控效果 在某些需求开发中,我们也许会遇到这样的需求:实现一个App内部的同屏控制,一台设备控制多台设备进行同步点击。达到同屏的效果。同屏的实现有很多种方法,可以...
  • 基于Android画板的同屏传输.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 95,046
精华内容 38,018
关键字:

安卓同屏