头部右侧文字
头部左侧文字
当前位置:网站首页 > 科技 > 正文

autojs文件互传(模拟器和手机)(一)

cndao cndao ⋅ 2022-09-23 19:30:59

牙叔教程 简单易懂

发送文件效果演示

手机发送文件给模拟器

autojs文件互传(模拟器和手机)(一)


模拟器发送文件给手机

autojs文件互传(模拟器和手机)(一)

思路

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


经测试,

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

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


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


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


手机端开启socket服务,

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


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

npm i --no-bin-links koa

会报错: initialize houdini failed

autojs文件互传(模拟器和手机)(一)

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

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


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


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文件互传(模拟器和手机)(一)


基本的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文件互传(模拟器和手机)(一)


把圆慢慢变成透明

autojs文件互传(模拟器和手机)(一)


让圆环动起来

autojs文件互传(模拟器和手机)(一)


再绘制一个客户端头像

autojs文件互传(模拟器和手机)(一)


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的cmdlog(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个端口就遍历完了


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


环境


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


名人名言


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


声明


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

cndao

cndao

TA太懒了...暂时没有任何简介

精彩新闻