牙叔教程 简单易懂

发送文件效果演示

手机发送文件给模拟器

autojs导入源码教程(autojs文件互传模拟器和手机)(1)

模拟器发送文件给手机

autojs导入源码教程(autojs文件互传模拟器和手机)(2)

思路

要实现互传, 那么两端必须通信, 通信采用什么方式呢?

经测试,

用autojs的nodejs在真机上开起服务, 模拟器是可以访问到的;

用autojs的nodejs在模拟器上开起服务, 真机访问不到;

因此, 我们就不能在模拟器用nodejs开启服务了, 因为真机访问不到;

所以, 我们只在手机开启服务, 模拟器只发送请求;

手机端开启socket服务,

模拟器也用socket与手机通信;

有一个问题要注意, 模拟器上, autojs不能运行命令

npm i --no-bin-links koa

会报错: initialize houdini failed

autojs导入源码教程(autojs文件互传模拟器和手机)(3)

因此, 我们写完代码后, 要打包以后使用;

打包以后安装到模拟上, 可以正常运行

以上是文件互传的通信设计思路, 下面来看看代码怎么写:

nodejs的socket例子

服务端

const net = require("net"); const port = 8000; const hostname = "127.0.0.1"; // const hostname = null; // 定义两个变量, 一个用来计数,一个用来保存客户端 let clients = {}; let clientName = 0; // 创建服务器 const server = new net.createServer(); server.on("connection", (client) => { client.name = clientName; // 给每一个client起个名 clients[client.name] = client; // 将client保存在clients client.on("data", function (msg) { //接收client发来的信息 console.log(`客户端${client.name}发来一个信息:${msg}`); }); client.on("error", function (e) { //监听客户端异常 console.log("client error" e); client.end(); }); client.on("close", function () { delete clients[client.name]; console.log(`客户端${client.name}下线了`); }); }); server.listen(port, hostname, function () { console.log(`服务器运行在:http://${hostname}:${port}`); });

客户端

const net = require("net"); const socket = new net.Socket(); const port = 8000; const hostname = "127.0.0.1"; socket.setEncoding = "UTF-8"; socket.connect(port, hostname, function () { socket.write("hello 大家好~~"); }); socket.on("data", function (msg) { console.log(msg); }); socket.on("error", function (error) { console.log("error" error); }); socket.on("close", function () { console.log("服务器端下线了"); });

然后在终端运行

node socket-server.js

再开一个终端, 运行

node socket-client.js

控制台显示内容

autojs导入源码教程(autojs文件互传模拟器和手机)(4)

基本的socket建立起来了, 下面要考虑实际情况

连接的实际情况

假如有一个手机, 电脑上再开一个模拟器, 两者使用同一个无线网络;

现在要实现文件互传, 用户先打开哪个? 后打开哪个?

我们是不知道的, 并且, 还要判断是不是模拟器,

怎么判断是不是模拟器

importClass(android.net.Uri); importClass(android.os.BUIld); function isSimulator() { let url = "tel:" "123456"; let Intent = new Intent(); intent.setData(Uri.parse(url)); intent.setAction(Intent.ACTION_DIAL); // 是否可以处理跳转到拨号的 Intent let canCallPhone = intent.resolveActivity(context.getPackageManager()) != null; return ( Build.FINGERPRINT.startsWith("generic") || java.lang.String(Build.FINGERPRINT.toLowerCase()).contains("vbox") || java.lang.String(Build.FINGERPRINT.toLowerCase()).contains("test-keys") || java.lang.String(Build.MODEL).contains("google_sdk") || java.lang.String(Build.MODEL).contains("Emulator") || java.lang.String(Build.MODEL).contains("MuMu") || java.lang.String(Build.MODEL).contains("virtual") || java.lang.String(Build.SERIAL).equalsIgnoreCase("android") || java.lang.String(Build.MANUFACTURER).contains("Genymotion") || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT) || context.getSystemService(context.TELEPHONY_SERVICE).getNetworkOperatorName().toLowerCase().equals("android") || !canCallPhone ); } let simulator = isSimulator(); if (simulator) isSimulator = "当前是模拟器环境"; else isSimulator = "当前是真机环境"; log(isSimulator);

UI显示连接的客户端

假设先点开手机

正常启动socket服务端, UI上应该显示一个等待别人连接的画面, 谁连接了就显示出来

我们先画一个头像

autojs导入源码教程(autojs文件互传模拟器和手机)(5)

然后画圆圈, 从小到大

autojs导入源码教程(autojs文件互传模拟器和手机)(6)

把圆慢慢变成透明

autojs导入源码教程(autojs文件互传模拟器和手机)(7)

让圆环动起来

autojs导入源码教程(autojs文件互传模拟器和手机)(8)

再绘制一个客户端头像

autojs导入源码教程(autojs文件互传模拟器和手机)(9)

UI基本就这样, 后面有需要再添加其他的按钮或者列表之类的

模拟器怎么发现手机端

模拟器一定是看客户端, 因为我用的雷电模拟器局域网IP是 172 开头,

手机是192开头, 不在同一个网段;

模拟器不知道手机的前三位, 因此, 我们前三位就固定下来是 192.168.5.

或者用一个输入框, 让用户可编辑, 作为教程来说, 简单一些, 就固定即即可;

那么模拟器怎么才能知道手机最后一位呢?

我们可以遍历最后一位 2~254

子网掩码默认为255.255.255.0掩码,意思就是前面三个位置已经固定,IP地址最多有255个。如果子网掩码是255.255.0.0 那IP地址就是255X255=65025.一般255个已经足够了。

C类地址

C类地址的表示范围为:192.0.0.0~223.255.255.255,默认网络掩码为:255.255.255.0;C类地址分配给小型网络,如一般的局域网和校园网,它可连接的主机数量是最少的,采用把所属的用户分为若干的网段进行管理。C类网络用前三组数字表示网络的地址,最后一组数字作为网络上的主机地址。

一般同一个局域网,前三位都是一样的, 我这里前三位是 192.168.5

那么我们要发现同一局域网可用的ip时, 我们可以发送请求遍历2~254,

可以用ping, 也可以用http, 我测试ping的时候, ping不通

用java代码或者autojs自带的命令行都ping不通 , 网上说可能是台式机禁用了ICMP回显功能之类的吧

pingCmd = "ping -c 1 -w 0.5 "; //其中 -c 1为发送的次数,-w 表示发送后等待响应的时间 locAddress = "192.168.5."; // current_ip = locAddress "21"; current_ip = "192.168.5.20"; p = pingCmd current_ip; run = java.lang.Runtime.getRuntime(); //获取当前运行环境,来执行ping,相当于windows的cmd log(p); proc = run.exec(p); result = proc.waitFor(); if (result == 0) { log("连接成功" current_ip); } else { log("连接失败" current_ip); }

那么我就不用ping了, 用http, 也不用auotjs的http, 用nodejs会快一点, 毕竟是异步的;

ping不需要端口, http需要端口, 端口我们也用固定的, 随便选个 5001-65535

就选 53182 , 随便打了几个数字

手机服务端监听

我发现写教程, 不能考虑那么多场景, 不然要花好多时间才能写完

用的还是上面那个服务端代码

大家要注意, 我用的雷电模拟器和手机不在同一个网段,

手机ping不了模拟器, 所以只能手机当服务端, 模拟器只能当客户端

const server = new net.createServer(); server.on("connection", (client) => { ... }); server.listen(port, hostname, function () { console.log(`服务器运行在:http://${hostname}:${port}`); });

模拟器遍历端口

"nodejs"; var net = require("net"); var Socket = net.Socket; var ip = "192.168.5"; var port = 53182; var scan = function (host, cb) { var socket = new Socket(); var status = null; socket.setTimeout(1500); socket.on("connect", function () { socket.end(); cb && cb(null, host); }); socket.on("timeout", function () { socket.destroy(); cb && cb(new Error("timeout"), host); }); socket.on("error", function (err) { cb && cb(err, host); }); socket.on("close", function (err) {}); socket.connect(port, host); }; for (var i = 2; i < 254; i ) { scan(ip "." i, function (err, host) { if (err) { console.log("Not found", host); return; } console.log("Found: ", host); }); }

遍历的日志

09-18 12:40:39.890 Thread-34/D: Found: 192.168.5.30 09-18 12:40:41.246 Thread-34/D: Not found 192.168.5.19 09-18 12:40:41.249 Thread-34/D: Not found 192.168.5.20 09-18 12:40:41.251 Thread-34/D: Not found 192.168.5.21 ... 09-18 12:40:41.269 Thread-34/D: Not found 192.168.5.28 09-18 12:40:41.270 Thread-34/D: Not found 192.168.5.29 09-18 12:40:41.278 Thread-34/D: process exit: 0 09-18 12:40:41.279 Script-7 Main [/storage/emulated/0/脚本/findipclient.js]/V:

我的手机ip是192.168.5.30, 模拟器是可以发现我的手机ip的, 同时nodejs是异步的, 速度很快, 最多2秒, 255个端口就遍历完了

篇幅太长, 下一节再说传输文件

环境

设备: 小米11proAndroid版本: 12雷电模拟器:9.0.17Android版本: 9Autojs版本: 9.2.13

名人名言

思路是最重要的, 其他的百度, bing, stackoverflow, github, 安卓文档, autojs文档, 最后才是群里问问 --- 牙叔教程

声明

部分内容来自网络 本教程仅用于学习, 禁止用于其他用途

,