热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

搭建Android上的服务器实现隔空取物

概述今天逛简书的时候,发现了一个库:https:www.jianshu.compe0c172c4e3bfhttps:github.comMZCretin

概述

今天逛简书的时候,发现了一个库:

  • https://www.jianshu.com/p/e0c172c4e3bf
  • https://github.com/MZCretin/WifiTransfer-master

主要功能是这样的,先口述一下,当打开app,可以通过浏览器访问一个地址,然后通过浏览器可以给手机上上传apk(也支持已有apk删除),然后手机端可以安装、卸载该apk。

三张图就明白了:

应用启动后:

gekong02.png

然后PC端访问:

gekong01.gif

拖拽apk上传,即可上传到手机端。

gekong03.png

ok,大致介绍清楚了。

注意一定要在同一个网段。

先不谈其用处到底有多大,很多时候我看到一个项目的时候,很少考虑其能干嘛,考虑最多的是它是如何实现的,我会么,不会那就学,至于能干嘛,那要等我学会之后?

那么思考下他的实现,这种上传文件的方式,在PC端更加常见,上传文件到服务器。

说到这,就可以想到,可能这个app在手机端搭建了一个服务器。

恩,没错就是这样的,在手机端搭建了一个服务器,这样就可以通过html,将PC端的文件传给手机端,然后手机端收到后再同步界面。

同时,也可以将手机上Sdcard上的文件,完全在PC上呈现。

手机端的Server利用的是该库:

  • https://github.com/koush/AndroidAsync

解析源码的事情就不做了,有兴趣可以自己学习下,接下来开始正片。

一个群友的问题

之所以会关注到这个库,是因为在wanandroid群,有个哥们连续问了好久的一个问题,问题是:

  • 如何通过浏览器输入一个地址播放手机上的视频

当时也很多人回答,回答的核心都是正确的。

当然我恰好看到这个库,之前也没推送过相关内容,所以我决定写个简易的Demo.

当然是Demo就没有什么美观可言了,仅为快速实现效果。

效果图是这样的:

gekong04.gif

页面上显示手机上的视频列表,然后点击某个视频,即开始播放该视频。

有了上例参考,非常简单。

注:部分代码直接从上例copy。 该案例需要网络和Sdcard权限!


先把服务器搭起来


依赖库

首先,依赖下我们搭建Server需要用到的库:

compile 'com.koushikdutta.async:androidasync:2.+'

编写简易html

然后我们在assets下编写一个html文件用于浏览器访问,index.html

最简单的即可:


<html>
<head><meta charset&#61;"UTF-8">
head><body>嘿嘿嘿&#xff0c;连通了...body>html>

启动服务&#xff0c;监听端口

public class MainActivity extends AppCompatActivity {private AsyncHttpServer server &#61; new AsyncHttpServer();private AsyncServer mAsyncServer &#61; new AsyncServer();&#64;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);server.get("/", new HttpServerRequestCallback() {&#64;Overridepublic void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {try {response.send(getIndexContent());} catch (IOException e) {e.printStackTrace();response.code(500).end();}}});server.listen(mAsyncServer, 54321);}&#64;Overrideprotected void onDestroy() {super.onDestroy();if (server !&#61; null) {server.stop();}if (mAsyncServer !&#61; null) {mAsyncServer.stop();}}private String getIndexContent() throws IOException {BufferedInputStream bInputStream &#61; null;try {bInputStream &#61; new BufferedInputStream(getAssets().open("index.html"));ByteArrayOutputStream baos &#61; new ByteArrayOutputStream();int len &#61; 0;byte[] tmp &#61; new byte[10240];while ((len &#61; bInputStream.read(tmp)) > 0) {baos.write(tmp, 0, len);}return new String(baos.toByteArray(), "utf-8");} catch (IOException e) {e.printStackTrace();throw e;} finally {if (bInputStream !&#61; null) {try {bInputStream.close();} catch (IOException e) {e.printStackTrace();}}}}
}

可以看到很简单&#xff0c;创建AsyncHttpServer对象&#xff0c;我们在onCreate中调用get&#xff0c;对外设置一个get型的url监听&#xff0c;监听的url是/即根目录。

然后调用listen&#xff0c;传入端口号54321&#xff0c;开启对该端口的监听。

onDestroy的时候停止服务器。

当捕获到对"/"的访问时&#xff0c;读取assets下的index.html返回给浏览器。

记得添加网络权限。

好了&#xff0c;运行demo&#xff0c;测试一下。

输入地址&#xff0c;你的手机的IP:端口号。

注意电脑和手机在同一个网段&#xff01;

然后你应该看到如下效果图&#xff1a;

gekong05.png

如果没看到&#xff0c;那不用往下了&#xff0c;先找问题吧~

完善Demo

接下来&#xff0c;我们将手机上的mp4返回让其在浏览器上显示。

很简单&#xff0c;既然我们可以监听/&#xff0c;返回一个index.html&#xff0c;我们就能监听另一个url&#xff0c;返回文件目录。

server.get("/files", new HttpServerRequestCallback() {&#64;Overridepublic void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {JSONArray array &#61; new JSONArray();File dir &#61; new File(Environment.getExternalStorageDirectory().getPath());String[] fileNames &#61; dir.list();if (fileNames !&#61; null) {for (String fileName : fileNames) {File file &#61; new File(dir, fileName);if (file.exists() && file.isFile() && file.getName().endsWith(".mp4")) {try {JSONObject jsonObject &#61; new JSONObject();jsonObject.put("name", fileName);jsonObject.put("path", file.getAbsolutePath());array.put(jsonObject);} catch (JSONException e) {e.printStackTrace();}}}}response.send(array.toString());}
});

我们监听/files这个Url&#xff0c;然后返回Sdcard根目录的视频文件&#xff0c;拼接成JSON返回。

这里如果你重新启动&#xff0c;在浏览器上输入&#xff1a;

http://192.168.1.100:54321/files

会看到一堆JSON数据&#xff1a;

gekong06.png

但是我们需要在刚才的html上显示&#xff0c;所以这个请求应该是刚才的Html页面发起&#xff1a;


<html>
<head><meta charset&#61;"UTF-8"><script src&#61;"jquery-1.7.2.min.js" type&#61;"text/Javascript">script><title>文档的标题title><script type&#61;"text/Javascript">$(function() {var now &#61; new Date();var url &#61; &#39;files&#39; &#43; &#39;?&#39; &#43; now.getTime();// 请求JSON数据$.getJSON(url, function(data) {// 编辑JSON数组for (var i &#61; 0; i // 为每个对象生成一个li标签&#xff0c;添加到页面的ul中var $li &#61; $(&#39;

  • &#39; &#43; data[i].name &#43; &#39;
  • &#39;);$li.attr("path", data[i].path);$("#filelist").append($li);}});});script>
    head><body><ul id&#61;"filelist" style&#61;"float:left;">ul>body>html>

    可能很多朋友没了解过js&#xff0c;不过应该能看明白&#xff0c;$.getJSON获取返回的JSON数组&#xff0c;然后遍历为每个Json对象生成一个li标签&#xff0c;添加到页面上。

    这里用了jquery,对于js的也需要也请求处理&#xff0c;这里省略了&#xff0c;很简单&#xff0c;看源码即可。

    此时访问&#xff0c;已经可以显示出视频目录了&#xff1a;

    gekong07.png

    接下来就是点击播放了&#xff0c;在html里面有个标签叫video用于播放视频的&#xff0c;他有个src属性用于设置播放的视频路径。

    所以我们要做的仅为&#xff1a;

    • 点击名字&#xff0c;拿到该视频对应的url&#xff0c;然后设置给video的src属性即可。

    那么视频的url是什么&#xff1f;

    刚才我们返回了视频的路径&#xff0c;所以我们只要再监听一个url&#xff0c;将根据传入的视频路径&#xff0c;将视频文件流返回即可。

    server.get("/files/.*", new HttpServerRequestCallback() {&#64;Overridepublic void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {String path &#61; request.getPath().replace("/files/", "");try {path &#61; URLDecoder.decode(path, "utf-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}File file &#61; new File(path);if (file.exists() && file.isFile()) {try {FileInputStream fis &#61; new FileInputStream(file);response.sendStream(fis, fis.available());} catch (Exception e) {e.printStackTrace();} return;}response.code(404).send("Not found!");}
    });

    我们又监听了一个url为files/xxx.*&#xff0c;捕获到之后&#xff0c;拿到文件名&#xff0c;去SDCard找到该文件&#xff0c;返回文件流即可。

    html端的代码为&#xff1a;


    当然页面上body标签内部也多了一个video标签。


    到这里&#xff0c;所以的代码就介绍完了~~

    小结

    回头看&#xff0c;其实就是app中启动服务器&#xff0c;监听一些url&#xff0c;然后针对性的返回文本、json、文件流等。

    当然了&#xff0c;可以做的时候也挺多的&#xff0c;甚至可以做个PC版本的文件浏览器。

    可能有很多人对html,js不太熟悉&#xff0c;不过还是建议简单了解下&#xff0c;或者敲一下本例&#xff0c;因为本例代码很少&#xff0c;值得作为上手教程。

    源码地址&#xff1a;

    https://github.com/hongyangAndroid/demo_ShowPhoneMp4


    推荐阅读
    • android listview OnItemClickListener失效原因
      最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
    • 带添加按钮的GridView,item的删除事件
      先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
    • Nginx使用AWStats日志分析的步骤及注意事项
      本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
    • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
      VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
    • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
    • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
    • 后台获取视图对应的字符串
      1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
    • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
    • 本文介绍了一款名为TimeSelector的Android日期时间选择器,采用了Material Design风格,可以在Android Studio中通过gradle添加依赖来使用,也可以在Eclipse中下载源码使用。文章详细介绍了TimeSelector的构造方法和参数说明,以及如何使用回调函数来处理选取时间后的操作。同时还提供了示例代码和可选的起始时间和结束时间设置。 ... [详细]
    • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
    • 基于layUI的图片上传前预览功能的2种实现方式
      本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
    • 向QTextEdit拖放文件的方法及实现步骤
      本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
    • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
    • Android开发实现的计时器功能示例
      本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
    • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
      本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
    author-avatar
    mobiledu2502940265
    这个家伙很懒,什么也没留下!
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有