
auto.js 笔记
02_auto.js基础操作1/4
文章目录
- 02_auto.js基础操作1/4
- 安卓手势
- 点击左上角
- 拉出通知栏
- 三指捏合
- 三指下滑
- 双指捏合
- 心形手势
- 解压缩
- 示例一
- 示例二
- 本地存储
- 保存数组和复杂对象
- 保存整数登简单数据
- 随手记
- 传感器
- 打印常用传感器信息
- 显示常用传感器信息
- 调用JavaAPI
- 定时器
- 定时执行
- 循环执行
- 对话框
- 菜单
- 单选框
- 多选框
- 简单计算器
- 模拟更新下载对话框
- 确认框
- 输入框
- UI模式下使用对话框
- 多媒体
- 免root屏幕录制
- 音乐播放器
- 多线程
- 变量可见性实验
- 多线程按键监听
- 多线程简单示例
- 线程启动与关闭
- 原子变量
安卓手势
点击左上角
"auto";
setScreenMetrics(1080, 1920); // 屏幕分辨率1080*1920
click(100, 150);
拉出通知栏
"auto";
//表示从位置(500, 10)滑动到位置(500, 1000), 持续两秒
swipe(500, 10, 500, 1000, 2000);
三指捏合
"auto";
setScreenMetrics(1080, 1920);
//如果你使用的是MIUI,此脚本运行后会出现桌面多屏幕编辑
home();
sleep(1500);
gestures([350, [800, 300], [500, 1000]],
[350, [300, 1500], [500, 1000]],
[350, [300, 300], [500, 1000]]);
三指下滑
"auto";
/**
* 同时模拟三个手势:
* 从(300, 400)到(300, 1400)
* 从(600, 400)到(600, 1400)
* 从(900, 400)到(900, 1400)
* 每一个的时长都为350毫秒
*/
gestures([350, [300, 400], [300, 1400]],
[350, [600, 400], [600, 1400]],
[350, [900, 400], [900, 1400]]
);
双指捏合
"auto";
setScreenMetrics(1080, 1920);
//如果你使用的是MIUI,此脚本运行后会出现桌面编辑
home();
sleep(1500);
gestures([500, [800, 300], [500, 1000]],
[500, [300, 1500], [500, 1000]]);
心形手势
"auto";
toast("开启开发者选项-指针位置或者在画画软件才能查看效果");
setScreenMetrics(1080, 1920);
var points = [10000];
var interval = 0.1;
var x0 = 600;
var y0 = 1000;
var a = 120;
for(var t = 0; t < 2 * Math.PI; t += interval){
var x = x0 + a * (2 * Math.cos(t) - Math.cos(2 * t));
var y = y0 + a * (2 * Math.sin(t) - Math.sin(2 * t));
points.push([parseInt(x), parseInt(y)]);
}
gesture.apply(null, points);
解压缩
示例一
//压缩文件路径(必须是完整路径)
var filePath = "/sdcard/脚本.7z";
//目录路径(必须是完整路径)
var dirPath = "/sdcard/脚本";
//压缩类型
//支持的压缩类型包括:zip 7z bz2 bzip2 tbz2 tbz gz gzip tgz tar wim swm xz txz。
var type = "7z";
//压缩密码
var password = "password"
//7z加密压缩(若文件已存在则跳过)
//zips.A(type, filePath, dirPath, password)
//压缩
switch (zips.A(type, filePath, dirPath)) {
case 0:
toastLog("压缩成功!文件已保存为: " + filePath)
break;
case 1:
toastLog("压缩结束,存在非致命错误(例如某些文件正在被使用,没有被压缩)")
break;
case 2:
toastLog("致命错误")
break;
case 7:
toastLog("命令行错误")
break;
case 8:
toastLog("没有足够内存")
break;
case 255:
toastLog("用户中止操作")
break;
default: toastLog("未知错误")
}
示例二
// 准备工作,创建文件夹与文件,以便后续用于压缩
// 创建两个文件夹与三个文件
$files.create("/sdcard/脚本/zip_test/");
$files.create("/sdcard/脚本/zip_out/");
$files.write("/sdcard/脚本/zip_test/1.txt", "Hello, World");
$files.write("/sdcard/脚本/zip_test/2.txt", "GoodBye, World");
$files.write("/sdcard/脚本/zip_test/3.txt", "Autox.js");
// 1. 压缩文件夹
// 要压缩的文件夹路径
let dir = '/sdcard/脚本/zip_test/';
// 压缩后的文件路径
let zipFile = '/sdcard/脚本/zip_out/未加密.zip';
$files.remove(zipFile);
$zip.zipDir(dir, zipFile);
// 2.加密压缩文件夹
let encryptedZipFile = '/sdcard/脚本/zip_out/加密.zip';
$files.remove(encryptedZipFile);
$zip.zipDir(dir, encryptedZipFile, {
password: 'Autox.js'
});
// 3. 压缩单个文件
let zipSingleFie = '/sdcard/脚本/zip_out/单文件.zip'
$files.remove(zipSingleFie);
$zip.zipFile('/sdcard/脚本/zip_test/1.txt', zipSingleFie);
// 4. 压缩多个文件
let zipMultiFile = '/sdcard/脚本/zip_out/多文件.zip';
$files.remove(zipMultiFile);
let fileList = ['/sdcard/脚本/zip_test/1.txt', '/sdcard/脚本/zip_test/2.txt']
$zip.zipFiles(fileList, zipMultiFile);
// 5. 解压文件
$zip.unzip('/sdcard/脚本/zip_out/未加密.zip', '/sdcard/脚本/zip_out/未加密/');
// 6. 解压加密的zip
$zip.unzip('/sdcard/脚本/zip_out/加密.zip', '/sdcard/脚本/zip_out/加密/', {
password: 'Autox.js'
});
// 7. 从压缩包删除文件
let z = $zip.open('/sdcard/脚本/zip_out/多文件.zip');
z.removeFile('1.txt');
// 8. 为压缩包增加文件
z.addFile('/sdcard/脚本/zip_test/3.txt');
本地存储
保存数组和复杂对象
var storage = storages.create("Auto.js例子:复杂数据");
var arr = [1, 4, 2, 5];
var obj = {
name: "Auto.js",
url: "www.autojs.org"
};
//保存
storage.put("arr", arr);
storage.put("obj", obj);
console.show();
//取出
log("arr = ", storage.get("arr"));
log("obj = ", storage.get("obj"));
保存整数登简单数据
var storage = storages.create("Auto.js例子:简单数据");
var a = 1234;
var b = true;
var str = "hello";
//保存
storage.put("a", a);
storage.put("b", b);
storage.put("str", str);
console.show();
//取出
log("a = " + storage.get("a"));
log("b = " + storage.get("b"));
log("str = " + storage.get("str"));
随手记
"ui";
ui.layout(
<vertical padding="16">
<horizontal>
<text textColor="black" textSize="18sp" layout_weight="1">随手记</text>
<button id="save" text="保存" w="auto" style="Widget.AppCompat.Button.Borderless.Colored"/>
</horizontal>
<input id="content" h="*" gravity="top"/>
</vertical>
);
var storage = storages.create("Auto.js例子:随手记");
var content = storage.get("content");
if(content != null){
ui.content.setText(content);
}
ui.save.click(()=>{
storage.put("content", ui.content.text());
});
传感器
打印常用传感器信息
//忽略不支持的传感器,即使有传感器不支持也不抛出异常
sensors.ignoresUnsupportedSensor = true;
sensors.on("unsupported_sensor", function(sensorName, sensorType){
log("不支持的传感器: %s 类型: %d", sensorName, sensorType);
});
//加速度传感器
sensors.register("accelerometer").on("change", (event, ax, ay, az)=>{
log("x方向加速度: %d
y方向加速度: %d
z方向加速度: %d", ax, ay, az);
});
//方向传感器
sensors.register("orientation").on("change", (event, dx, dy, dz)=>{
log("绕x轴转过角度: %d
绕y轴转过角度: %d
绕z轴转过角度: %d", dx, dy, dz);
});
//陀螺仪传感器
sensors.register("gyroscope").on("change", (event, wx, wy, wz)=>{
log("绕x轴角速度: %d
绕y轴角速度: %d
绕z轴角速度: %d", wx, wy, wz);
});
//磁场传感器
sensors.register("magnetic_field").on("change", (event, bx, by, bz)=>{
log("x方向磁场强度: %d
y方向磁场强度: %d
z方向磁场强度: %d", bx, by, bz);
});
//重力传感器
sensors.register("magnetic_field").on("change", (event, gx, gy, gz)=>{
log("x方向重力: %d
y方向重力: %d
z方向重力: %d", gx, gy, gz);
});
//线性加速度传感器
sensors.register("linear_acceleration").on("change", (event, ax, ay, az)=>{
log("x方向线性加速度: %d
y方向线性加速度: %d
z方向线性加速度: %d", ax, ay, az);
});
//温度传感器
sensors.register("ambient_temperature").on("change", (event, t)=>{
log("当前温度: %d", t);
});
//光线传感器
sensors.register("light").on("change", (event, l)=>{
log("当前光的强度: %d", l);
});
//压力传感器
sensors.register("pressure").on("change", (event, p)=>{
log("当前压力: %d", p);
});
//距离传感器
sensors.register("proximity").on("change", (event, d)=>{
log("当前距离: %d", d);
});
//湿度传感器
sensors.register("relative_humidity").on("change", (event, rh)=>{
log("当前相对湿度: %d", rh);
});
//30秒后退出程序
setTimeout(exit, 30 * 1000);
显示常用传感器信息
"ui";
ui.layout(
<scroll>
<vertical>
<text id="accelerometer" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="orientation" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="gyroscope" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="magnetic_field" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="gravity" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="linear_acceleration" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="ambient_temperature" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="light" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="pressure" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="proximity" margin="12dp" textSize="16sp" textColor="#000000"/>
<text id="relative_humidity" margin="12dp" textSize="16sp" textColor="#000000"/>
</vertical>
</scroll>
);
//忽略不支持的传感器,即使有传感器不支持也不抛出异常
sensors.ignoresUnsupportedSensor = true;
sensors.on("unsupported_sensor", function(sensorName, sensorType){
log(util.format("不支持的传感器: %s 类型: %d", sensorName, sensorType));
});
//加速度传感器
sensors.register("accelerometer", sensors.delay.ui).on("change", (event, ax, ay, az)=>{
ui.accelerometer.setText(util.format("x方向加速度: %d
y方向加速度: %d
z方向加速度: %d", ax, ay, az));
});
//方向传感器
sensors.register("orientation", sensors.delay.ui).on("change", (event, dx, dy, dz)=>{
ui.orientation.setText(util.format("绕x轴转过角度: %d
绕y轴转过角度: %d
绕z轴转过角度: %d", dx, dy, dz));
});
//陀螺仪传感器
sensors.register("gyroscope", sensors.delay.ui).on("change", (event, wx, wy, wz)=>{
ui.gyroscope.setText(util.format("绕x轴角速度: %d
绕y轴角速度: %d
绕z轴角速度: %d", wx, wy, wz));
});
//磁场传感器
sensors.register("magnetic_field", sensors.delay.ui).on("change", (event, bx, by, bz)=>{
ui.magnetic_field.setText(util.format("x方向磁场强度: %d
y方向磁场强度: %d
z方向磁场强度: %d", bx, by, bz));
});
//重力传感器
sensors.register("gravity", sensors.delay.ui).on("change", (event, gx, gy, gz)=>{
ui.gravity.setText(util.format("x方向重力: %d
y方向重力: %d
z方向重力: %d", gx, gy, gz));
});
//线性加速度传感器
sensors.register("linear_acceleration", sensors.delay.ui).on("change", (event, ax, ay, az)=>{
ui.linear_acceleration.setText(util.format("x方向线性加速度: %d
y方向线性加速度: %d
z方向线性加速度: %d", ax, ay, az));
});
//温度传感器
sensors.register("ambient_temperature", sensors.delay.ui).on("change", (event, t)=>{
ui.ambient_temperature.setText(util.format("当前温度: %d", t));
});
//光线传感器
sensors.register("light", sensors.delay.ui).on("change", (event, l)=>{
ui.light.setText(util.format("当前光的强度: %d", l));
});
//压力传感器
sensors.register("pressure", sensors.delay.ui).on("change", (event, p)=>{
ui.pressure.setText(util.format("当前压力: %d", p));
});
//距离传感器
sensors.register("proximity", sensors.delay.ui).on("change", (event, d)=>{
ui.proximity.setText(util.format("当前距离: %d", d));
});
//湿度传感器
sensors.register("relative_humidity", sensors.delay.ui).on("change", (event, rh)=>{
ui.relative_humidity.setText(util.format("当前相对湿度: %d", rh));
});
//30秒后退出程序
setTimeout(exit, 30 * 1000);
调用JavaAPI
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* liveConnect.js: a simple demonstration of javascript-to-Java connectivity
*/
// Create a new StringBuffer. Note that the class name must be fully qualified
// by its package. Packages other than "java" must start with "Packages", i.e.,
// "Packages.javax.servlet...".
var sb = new java.lang.StringBuffer();
// Now add some stuff to the buffer.
sb.append("hi, mom");
sb.append(3); // this will add "3.0" to the buffer since all JS numbers
// are doubles by default
sb.append(true);
// Now print it out. (The toString() method of sb is automatically called
// to convert the buffer to a string.)
// Should print "hi, mom3.0true".
print(sb);
openConsole();
定时器
定时执行
toast("静等20秒,你会看到想看的...");
var i = 0;
setTimeout(function(){
app.openUrl("http://music.163.com/#/song?id=109628&autoplay=true&market=baiduhd");
exit();
}, 20 * 1000);
setInterval(function(){
i++;
toast(i * 5 + "秒");
}, 5000);
循环执行
var i = 0;
setInterval(function(){
i++;
toast(i * 4 + "秒");
if(i == 5){
exit();
}
}, 4000);
对话框
菜单
while(true){
var i = dialogs.select("哲学的基本问题是", "社会和自然的关系问题", "思维与存在的关系问题", "政治和经济的关系问题", "实践和理论的关系问题");
if(i == -1){
toast("猜一下呗");
continue;
}
if(i == 1){
toast("答对辣");
break;
}else{
toast("答错辣")
}
}
单选框
var sex = dialogs.singleChoice("请选择性别", ["男", "女", "基佬", "女装", "其他"], 2);
toast("选择了第" + (sex + 1) + "个选项");
多选框
var i = dialogs.multiChoice("下列作品出自李贽的是", ["《焚书》", "《西湖寻梦》", "《高太史全集》", "《续焚烧书》", "《藏书》"]);
toast("选择了: " + i);
if(i.length == 2 && i.toString() == [0, 4].toString()){
toast("答对辣");
}else{
toast("答错辣");
}
简单计算器
var num1 = dialogs.input("请输入第一个数字");
var op = dialogs.singleChoice("请选择运算", ["加", "减", "乘", "除", "幂"]);
var num2 = dialogs.input("请输入第二个数字");
var result = 0;
switch(op){
case 0:
result = num1 + num2;
break;
case 1:
result = num1 - num2;
break;
case 2:
result = num1 * num2;
break;
case 3:
result = num1 / num2;
break;
case 4:
result = Math.pow(num1, num2);
break;
}
alert("运算结果", result);
模拟更新下载对话框
var releaseNotes = "版本 v7.7.7
"
+ "更新日志:
"
+ "* 新增 若干Bug
";
dialogs.build({
title: "发现新版本",
content: releaseNotes,
positive: "立即下载",
negative: "取消",
neutral: "到浏览器下载"
})
.on("positive", download)
.on("neutral", () => {
app.openUrl("https://www.autojs.org");
})
.show();
var downloadDialog = null;
var downloadId = -1;
function download(){
downloadDialog = dialogs.build({
title: "下载中...",
positive: "暂停",
negative: "取消",
progress: {
max: 100,
showMinMax: true
},
autoDismiss: false
})
.on("positive", ()=>{
if(downloadDialog.getActionButton("positive") == "暂停"){
stopDownload();
downloadDialog.setActionButton("positive", "继续");
}else{
startDownload();
downloadDialog.setActionButton("positive", "暂停");
}
})
.on("negative", ()=>{
stopDownload();
downloadDialog.dismiss();
downloadDialog = null;
})
.show();
startDownload();
}
function startDownload(){
downloadId = setInterval(()=>{
var p = downloadDialog.getProgress();
if(p >= 100){
stopDownload();
downloadDialog.dismiss();
downloadDialog = null;
toast("下载完成");
}else{
downloadDialog.setProgress(p + 1);
}
}, 100);
}
function stopDownload(){
clearInterval(downloadId);
}
确认框
var handsome = confirm("你帅吗?");
if(handsome){
toast("真不要脸!");
toast("真不要脸!");
toast("真不要脸!");
alert("真不要脸!");
}else{
toast("嗯");
}
输入框
var name = rawInput("请输入名字");
alert("(•́へ•́╬)", "你好~ " + name);
var expr = dialogs.input("请输入简单的算式", "1+1");
alert("计算结果为 " + expr);
UI模式下使用对话框
"ui";
ui.layout(
<vertical>
<button id="callback" align="center">回调形式</button>
<button id="promise" align="center">Promise形式</button>
<button id="calc" align="center">简单计算器</button>
</vertical>
);
ui.callback.click(()=>{
dialogs.confirm("要弹出输入框吗?", "", function(b){
if(b){
dialogs.rawInput("输入", "", function(str){
alert("您输入的是:" + str);
});
}else{
ui.finish();
}
});
});
ui.promise.click(()=>{
dialogs.confirm("要弹出输入框吗")
.then(function(b){
if(b){
return dialogs.rawInput("输入");
}else{
ui.finish();
}
}).then(function(str){
alert("您输入的是:" + str);
});
});
ui.calc.click(()=>{
let num1, num2, op;
dialogs.input("请输入第一个数字")
.then(n => {
num1 = n;
return dialogs.singleChoice("请选择运算", ["加", "减", "乘", "除", "幂"]);
})
.then(o => {
op = o;
return dialogs.input("请输入第二个数字");
})
.then(n => {
num2 = n;
var result;
switch(op){
case 0:
result = num1 + num2;
break;
case 1:
result = num1 - num2;
break;
case 2:
result = num1 * num2;
break;
case 3:
result = num1 / num2;
break;
case 4:
result = Math.pow(num1, num2);
break;
}
alert("运算结果", result);
});
});
多媒体
免root屏幕录制
"ui";
importClass(android.content.Context);
importClass(android.hardware.display.DisplayManager);
importClass(android.media.MediaRecorder);
importClass(java.io.File);
runtime.requestPermissions(["WRITE_EXTERNAL_STORAGE", "READ_EXTERNAL_STORAGE", "RECORD_AUDIO"]);
mMediaProjectionManager = context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
mMediaRecorder = new MediaRecorder();
mVirtualDisplay = null;
saveDir = "/sdcard";
saveWidth = device.width;
saveHeight = device.height;
saveTime = 10 * 1000; // 单位:毫秒
isRunning = false;
ui.layout(
<vertical>
<appbar>
<toolbar title="免root屏幕录制" />
</appbar>
<Switch id="permissions" text="音频录制及存储权限" checked="true" gravity="center"/>
<frame gravity="center">
<text text="AutoX" gravity="center" />
</frame>
<button text="免root屏幕录制" style="Widget.AppCompat.Button.Colored" id="button" />
</vertical>
);
ui.button.click(function () {
if (isRunning) {
stopRecord();
ui.button.setText("免root屏幕录制");
} else {
activity.startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(), 666);
}
});
// 申请权限
ui.permissions.on("check", function (checked) {
if (checked) {
runtime.requestPermissions(["WRITE_EXTERNAL_STORAGE", "READ_EXTERNAL_STORAGE", "RECORD_AUDIO"]);
} else {
toastLog("权限不足!");
}
});
ui.emitter.on("resume", function () {
ui.permissions.checked = true;
});
// 获取屏幕录制授权
ui.emitter.on("activity_result", (requestCode, resultCode, data) => {
mMediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, data);
if (mMediaProjection) {
startRecord();
ui.button.setText("视频录制中(点击停止)……");
setTimeout(function () {
stopRecord();
ui.button.setText("免root屏幕录制");
}, saveTime)
}
});
events.on("exit", function () {
stopRecord();
});
function startRecord() {
if (mMediaProjection == null || isRunning) {
return false;
}
file = new File(saveDir, "screen_record.mp4");
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mMediaRecorder.setOutputFile(file.getAbsolutePath());
mMediaRecorder.setVideoSize(saveWidth, saveHeight);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
mMediaRecorder.setVideoFrameRate(30);
try {
mMediaRecorder.prepare();
} catch (e) {
toastLog(e);
}
mVirtualDisplay = mMediaProjection.createVirtualDisplay("免root屏幕录制", saveWidth, saveHeight, 1, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null);
mMediaRecorder.start();
isRunning = true;
return true;
}
function stopRecord() {
if (!isRunning) {
return false;
}
mMediaRecorder.stop();
mMediaRecorder.reset();
mVirtualDisplay.release();
mMediaProjection.stop();
isRunning = false;
toastLog("录制结束!");
return true;
}
音乐播放器
"ui";
ui.layout(
<vertical>
<text id="name" text="音乐播放器" textSize="22sp" textColor="#fbfbfe" bg="#00afff" w="*" gravity="center"></text>
<button id="play">播放音乐</button>
<button id="next">下一曲</button>
<button id="pause">暂停</button>
</vertical>
);
var musicDir = '/sdcard/Music';
if (!files.isDir(musicDir)) {
toastLog(musicDir + "目录不存在!")
}
var musicFiles = files.listDir(musicDir, function (name) {
return name.endsWith(".mp3") || name.endsWith(".wma") || name.endsWith(".wav")
});
var i = 0;
var musicPath = "";
if (musicFiles.length > 0) {
musicPath = files.join(musicDir, musicFiles[i]);
ui.name.setText(files.getNameWithoutExtension(musicPath));
} else {
toastLog(musicDir + "目录下没有音频文件!")
}
ui.pause.click(function () {
media.pauseMusic();
});
ui.next.click(function () {
musicPath = files.join(musicDir, musicFiles[(i + 1) % musicFiles.length]);
if (files.isFile(musicPath)) {
ui.name.setText(files.getNameWithoutExtension(musicPath));
media.playMusic(musicPath, 0.8);
} else {
toastLog(musicPath + "音频文件不存在!")
}
}
);
ui.play.click(function () {
if (media.isMusicPlaying()) {
return true;
} else {
if (files.isFile(musicPath)) {
ui.name.setText(files.getNameWithoutExtension(musicPath));
media.playMusic(musicPath, 0.8);
} else {
toastLog(musicPath + "音频文件不存在!")
}
}
});
ui.emitter.on("pause", () => {
if (media.isMusicPlaying()) {
media.pauseMusic();
}
});
ui.emitter.on("resume", () => {
ui.post(function () {
media.resumeMusic();
}, 200);
});
events.on("exit", function () {
media.stopMusic();
});
多线程
变量可见性实验
var running = true;
threads.start(function(){
while(running){
log("running = true");
}
});
sleep(2000);
running = false;
console.info("running = false");
多线程按键监听
auto();
threads.start(function(){
//在子线程中调用observeKey()从而使按键事件处理在子线程执行
events.observeKey();
events.on("key_down", function(keyCode, events){
//音量键关闭脚本
if(keyCode == keys.volume_up){
exit();
}
});
});
toast("音量上键关闭脚本");
events.on("exit", function(){
toast("脚本已结束");
});
while(true){
log("脚本运行中...");
sleep(2000);
}
多线程简单示例
//启动一个线程
threads.start(function(){
//在线程中每隔1秒打印"线程1"
while(true){
log("线程1");
sleep(1000);
}
});
//启动另一个线程
threads.start(function(){
//在线程中每隔2秒打印"线程1"
while(true){
log("线程2");
sleep(2000);
}
});
//在主线程中每隔3秒打印"主线程"
for(var i = 0; i < 10; i++){
log("主线程");
sleep(3000);
}
//打印100次后退出所有线程
threads.shutDownAll();
线程启动与关闭
//启动一个无限循环的线程
var thread = threads.start(function(){
while(true){
log("子线程运行中...");
sleep(1000);
}
});
//5秒后关闭线程
sleep(5000);
thread.interrupt();
原子变量
var i = threads.atomic();
本文转自 https://blog.csdn.net/qq_37952052/article/details/131625821?spm=1001.2014.3001.5502,如有侵权,请联系删除。
02_auto.js基础操作2/4
文章目录
- 02_auto.js基础操作2/4
- 复杂界面
- 待办事项
- 登录界面
- 界面模板
- 用户调查
- 一个小测试
- 画布
- 函数图像简单版
- 函数图像高级版
- 脚本引擎
- 停止所有正在运行的脚本
- 运行脚本文件
- 运行录制文件
- 运行新的脚本任务
- 界面控件
- 按钮控件
- 表格控件-内置图标查看器
- 复选框单选框控件
- 进度条控件
- 卡片布局
- 列表控件
- 时间日期选择控件
- 输入框控件
- 图片控件
- 文本控件
- 下拉菜单
- 自定义控件-布局模板
- 自定义控件-带颜色按钮
- 自定义控件-模块-配置勾选框
- 自定义控件-使用配置勾选框
复杂界面
待办事项
"ui";
importClass(android.graphics.Paint);
ui.layout(
<frame>
<vertical>
<appbar>
<toolbar id="toolbar" title="Todo" />
</appbar>
<list id="todoList">
<card w="*" h="70" margin="10 5" cardCornerRadius="2dp"
cardElevation="1dp" foreground="?selectableItemBackground">
<horizontal gravity="center_vertical">
<View bg="{{this.color}}" h="*" w="10" />
<vertical padding="10 8" h="auto" w="0" layout_weight="1">
<text id="title" text="{{this.title}}" textColor="#222222" textSize="16sp" maxLines="1" />
<text text="{{this.summary}}" textColor="#999999" textSize="14sp" maxLines="1" />
</vertical>
<checkbox id="done" marginLeft="4" marginRight="6" checked="{{this.done}}" />
</horizontal>
</card>
</list>
</vertical>
<fab id="add" w="auto" h="auto" src="@drawable/ic_add_black_48dp"
margin="16" layout_gravity="bottom|right" tint="#ffffff" />
</frame>
);
var materialColors = ["#e91e63", "#ab47bc", "#5c6bc0", "#7e57c2", "##2196f3", "#00bcd4",
"#26a69a", "#4caf50", "#8bc34a", "#ffeb3b", "#ffa726", "#78909c", "#8d6e63"];
var storage = storages.create("todoList");
//从storage获取todo列表
var todoList = storage.get("items", [
{
title: "写操作系统作业",
summary: "明天第1~2节",
color: "#f44336",
done: false
},
{
title: "给ui模式增加若干Bug",
summary: "无限期",
color: "#ff5722",
done: false
},
{
title: "发布Auto.js 5.0.0正式版",
summary: "2019年1月",
color: "#4caf50",
done: false
},
{
title: "完成毕业设计和论文",
summary: "2019年4月",
color: "#2196f3",
done: false
}
]);;
ui.todoList.setDataSource(todoList);
ui.todoList.on("item_bind", function (itemView, itemHolder) {
//绑定勾选框事件
itemView.done.on("check", function (checked) {
let item = itemHolder.item;
item.done = checked;
let paint = itemView.title.paint;
//设置或取消中划线效果
if (checked) {
paint.flags |= Paint.STRIKE_THRU_TEXT_FLAG;
} else {
paint.flags &= ~Paint.STRIKE_THRU_TEXT_FLAG;
}
itemView.title.invalidate();
});
});
ui.todoList.on("item_click", function (item, i, itemView, listView) {
itemView.done.checked = !itemView.done.checked;
});
ui.todoList.on("item_long_click", function (e, item, i, itemView, listView) {
confirm("确定要删除" + item.title + "吗?")
.then(ok => {
if (ok) {
todoList.splice(i, 1);
}
});
e.consumed = true;
});
//当离开本界面时保存todoList
ui.emitter.on("pause", () => {
storage.put("items", todoList);
});
ui.add.on("click", () => {
dialogs.rawInput("请输入标题")
.then(title => {
if (!title) {
return;
}
dialogs.rawInput("请输入期限", "明天")
.then(summary => {
todoList.push({
title: title,
summary: summary,
color: materialColors[random(0, materialColors.length - 1)]
});
});
})
});
登录界面
"ui";
showLoginUI();
ui.statusBarColor("#000000")
//显示登录界面
function showLoginUI(){
ui.layout(
<frame>
<vertical h="auto" align="center" margin="0 50">
<linear>
<text w="56" gravity="center" color="#111111" size="16">用户名</text>
<input id="name" w="*" h="40"/>
</linear>
<linear>
<text w="56" gravity="center" color="#111111" size="16">密码</text>
<input id="password" w="*" h="40" password="true"/>
</linear>
<linear gravity="center">
<button id="login" text="登录"/>
<button id="register" text="注册"/>
</linear>
</vertical>
</frame>
);
ui.login.on("click", () => {
toast("您输入的用户名为" + ui.name.text() + " 密码为" + ui.password.text());
});
ui.register.on("click", () => showRegisterUI());
}
//显示注册界面
function showRegisterUI(){
ui.layout(
<frame>
<vertical h="auto" align="center" margin="0 50">
<linear>
<text w="56" gravity="center" color="#111111" size="16">用户名</text>
<input w="*" h="40"/>
</linear>
<linear>
<text w="56" gravity="center" color="#111111" size="16">密码</text>
<input w="*" h="40" password="true"/>
</linear>
<linear>
<text w="56" gravity="center" color="#111111" size="16">邮箱</text>
<input w="*" h="40" inputType="textEmailAddress"/>
</linear>
<linear gravity="center">
<button>确定</button>
<button id="cancel">取消</button>
</linear>
</vertical>
</frame>
);
ui.cancel.on("click", () => showLoginUI());
}
界面模板
"ui";
var color = "#009688";
ui.layout(
<drawer id="drawer">
<vertical>
<appbar>
<toolbar id="toolbar" title="示例"/>
<tabs id="tabs"/>
</appbar>
<viewpager id="viewpager">
<frame>
<text text="第一页内容" textColor="black" textSize="16sp"/>
</frame>
<frame>
<text text="第二页内容" textColor="red" textSize="16sp"/>
</frame>
<frame>
<text text="第三页内容" textColor="green" textSize="16sp"/>
</frame>
</viewpager>
</vertical>
<vertical layout_gravity="left" bg="#ffffff" w="280">
<img w="280" h="200" scaleType="fitXY" src="http://images.shejidaren.com/wp-content/uploads/2014/10/023746fki.jpg"/>
<list id="menu">
<horizontal bg="?selectableItemBackground" w="*">
<img w="50" h="50" padding="16" src="{{this.icon}}" tint="{{color}}"/>
<text textColor="black" textSize="15sp" text="{{this.title}}" layout_gravity="center"/>
</horizontal>
</list>
</vertical>
</drawer>
);
//创建选项菜单(右上角)
ui.emitter.on("create_options_menu", menu=>{
menu.add("设置");
menu.add("关于");
});
//监听选项菜单点击
ui.emitter.on("options_item_selected", (e, item)=>{
switch(item.getTitle()){
case "设置":
toast("还没有设置");
break;
case "关于":
alert("关于", "Auto.js界面模板 v1.0.0");
break;
}
e.consumed = true;
});
activity.setSupportActionBar(ui.toolbar);
//设置滑动页面的标题
ui.viewpager.setTitles(["标签一", "标签二", "标签三"]);
//让滑动页面和标签栏联动
ui.tabs.setupWithViewPager(ui.viewpager);
//让工具栏左上角可以打开侧拉菜单
ui.toolbar.setupWithDrawer(ui.drawer);
ui.menu.setDataSource([
{
title: "选项一",
icon: "@drawable/ic_android_black_48dp"
},
{
title: "选项二",
icon: "@drawable/ic_settings_black_48dp"
},
{
title: "选项三",
icon: "@drawable/ic_favorite_black_48dp"
},
{
title: "退出",
icon: "@drawable/ic_exit_to_app_black_48dp"
}
]);
ui.menu.on("item_click", item => {
switch(item.title){
case "退出":
ui.finish();
break;
}
})
用户调查
"ui";
ui.layout(
<vertical>
<text textSize="18sp" textColor="#000000" margin="20" textStyle="bold">
关于Auto.js的用户调查
</text>
<ScrollView>
<vertical>
<text textSize="16sp" margin="8">1. 您的年龄是?</text>
<input text="18" inputType="number" margin="0 16"/>
<text textSize="16sp" margin="8">2. 您用过其他类似软件(脚本精灵,按键精灵等)吗?</text>
<radiogroup margin="0 16">
<radio text="没有用过"/>
<radio text="用过"/>
<radio text="用过,感觉不好用"/>
<radio text="没有Root权限无法使用"/>
</radiogroup>
<text textSize="16sp" margin="8">3. 您使用Auto.js通常用于做什么?(多选)</text>
<checkbox text="游戏辅助" marginLeft="16"/>
<checkbox text="点赞" marginLeft="16"/>
<checkbox text="日常生活工作辅助" marginLeft="16"/>
<checkbox text="练习编程" marginLeft="16"/>
<checkbox text="自动化测试" marginLeft="16"/>
<linear>
<checkbox text="其他" marginLeft="16"/>
<input w="*" margin="0 16"/>
</linear>
<text textSize="16sp" margin="8">4. 您更喜欢以下哪个图标?</text>
<radiogroup margin="0 16">
<radio/>
<img w="100" h="100" margin="0 16" src="http://www.autojs.org/assets/uploads/profile/3-profileavatar.png"/>
<radio/>
<img w="100" h="100" margin="0 16" src="http://www.autojs.org/assets/uploads/files/1511945512596-autojs_logo.png"/>
</radiogroup>
<text textSize="16sp" margin="8">5. 您是什么时候开始使用Auto.js的呢?</text>
<datepicker margin="4 16" datePickerMode="spinner"/>
<text textSize="16sp" margin="8">6. 您用过下面这个Auto.js的论坛吗?</text>
<webview id="webview" h="300" margin="0 16"/>
<radiogroup marginLeft="16" marginTop="16">
<radio text="没有用过"/>
<radio text="用过"/>
<radio text="用过,感觉不好用"/>
</radiogroup>
<linear gravity="center">
<button margin="16">提交</button>
<button margin="16">放弃</button>
</linear>
</vertical>
</ScrollView>
</vertical>
)
ui.webview.loadUrl("http://www.autojs.org");
一个小测试
"ui";
/**
* By Da Zhang
* 本脚本仅为娱乐,没有任何破坏性质
*/
ui.statusBarColor("#AA0000");
var Quin = 32552732;
ui.layout(
<frame background="#AA0000">
<vertical align="top" paddingTop="5" margin="10">
<text id="oops" color="#FFFFFF" gravity="center" size="20">Oops, your files have been encrypted!</text>
<text id="text" bg="#FFFFFF" gravity="left" color="#000000" size="15" marginTop="15" h="425"></text>
<button id="payment" text="Payment" margin="20 0 0 0"/>
<button id="decrypt" text="Decrypt"/>
</vertical>
</frame>
);
ui.text.text("我的手机出了什么问题?
您的一些重要文件被我加密保存了。
" +
"照片、图片、文档、压缩包、音频、视频文件、apk文件等,几乎所有类型的文件都被加密了,因此不能正常打开。
" +
"这和一般文件损坏有本质上的区别。您大可在网上找找恢复文件的方法,我敢保证,没有我们的解密服务,就算老天爷来了也不能恢复这些文档。
" +
"有没有恢复这些文档的方法?
当然有可恢复的方法。只能通过我们的解密服务才能恢复。我以人格担保,能够提供安全有效的恢复服务。
" +
"但这是收费的,也不能无限期的推迟。
请点击 <Decrypt> 按钮,就可以免费恢复一些文档。请您放心,我是绝不会骗你的。
" +
"但想要恢复全部文档,需要付款点费用。
是否随时都可以固定金额付款,就会恢复的吗,当然不是,推迟付款时间越长,对你不利。
" +
"最好3天之内付款费用,过了三天费用就会翻倍。
还有,一个礼拜之内未付款,将会永远恢复不了。
" +
"对了,忘了告诉你,对半年以上没钱付款的穷人,会有活动免费恢复,能否轮到你,就要看您的运气怎么样了。");
ui.oops.click(() => toast("Fuck you!"));
ui.oops.longClick(() => {
var thisjoke="This is a joke : )";
if(ui.oops.text() != thisjoke){
ui.oops.text(thisjoke);
}else{
ui.oops.text("Oops, your files have been encrypted!");
}
return true;
});
ui.text.click(() => ui.text.append("。"));
ui.text.longClick(() => {
ui.text.setText("
"+ui.text.getText())
return true;
});
ui.payment.click(() => {
try{
app.startActivity({
action:"android.intent.action.VIEW",
data:"mqqapi://card/show_pslcard?&uin=" + Quin
});
toast("Please payment by QQ");
}catch(e){
toast("Payment Error");
}
});
ui.payment.longClick(() => {
toast("You are silly b!");
return true;
});
ui.decrypt.click(() => {
toast("Decrypt Error");
activity.finish();
});
ui.decrypt.longClick(() => {
toast("You can't decrypt!");
return true;
});
画布
函数图像简单版
"ui";
//ui布局为一块画布
ui.layout(
<frame>
<canvas id="board" w="*" h="*"/>
</frame>
);
//要绘制的函数,这里是一个一元二次函数
var f = function(x){
return x * x + 3 * x - 4;
}
//绘制区间
var minX = -5;
var maxX = 5;
var minY = -10;
//画笔
var paint = new Paint();
ui.board.on("draw", function(canvas){
var w = canvas.getWidth();
var h = canvas.getHeight();
//计算y轴区间上限
var maxY = minY + (maxX - minX) * h / w;
//设置画笔颜色为黑色
paint.setColor(colors.parseColor("#000000"));
//绘制两个坐标轴
canvas.drawLine(w / 2, 0, w / 2, h, paint);
canvas.drawLine(0, h / 2, w, h / 2, paint);
//设置画笔颜色为红色
paint.setColor(colors.parseColor("#ff0000"));
//绘制图像
for(var i = 0; i < w; i++){
var x = minX + i / w * (maxX - minX);
var y = f(x);
var j = h - (y - minY) / (maxY - minY) * h;
canvas.drawPoint(i, j, paint);
}
});
函数图像高级版
"ui";
//ui布局为一块画布和一些函数调整控件
ui.layout(
<vertical>
<linear>
<input id="fx" textSize="16sp" text="x*x+3*x-4" layout_weight="1"/>
<button id="ok" w="50dp"/>
</linear>
<linear>
<button id="left" text="←" layout_weight="1"/>
<button id="right" text="→" layout_weight="1"/>
<button id="up" text="↓" layout_weight="1"/>
<button id="down" text="↑" layout_weight="1"/>
<button id="zoom_in" text="+" layout_weight="1"/>
<button id="zoom_out" text="-" layout_weight="1"/>
</linear>
<canvas id="board" w="*" h="*"/>
</vertical>
);
//函数表达式
var f = "x*x+3*x-4";
//绘制区间
var minX = -5;
var maxX = 5;
var minY;
var h = 1;
var w = 1;
//画笔
var paint = new Paint();
paint.setStrokeWidth(2);
ui.board.on("draw", function(canvas){
w = canvas.getWidth();
h = canvas.getHeight();
if(minY == undefined){
minY = -(maxX - minX) * h / w / 2;
}
//计算y轴区间上限
var maxY = minY + (maxX - minX) * h / w;
//设置画笔颜色为黑色
paint.setColor(colors.parseColor("#000000"));
//绘制两个坐标轴
var x0 = parseInt(- minX / (maxX - minX) * w);
canvas.drawLine(x0, 0, x0, h, paint);
var y0 = parseInt(h + minY / (maxY - minY) * h);
canvas.drawLine(0, y0, w, y0, paint);
//设置画笔颜色为红色
paint.setColor(colors.parseColor("#ff0000"));
//绘制图像
for(var i = 0; i < w; i++){
var x = minX + i / w * (maxX - minX);
var y = eval(f);
var j = h - (y - minY) / (maxY - minY) * h;
canvas.drawPoint(i, j, paint);
}
});
ui.ok.click(()=>{
f = String(ui.fx.text());
});
ui.left.click(()=>{
var d = maxX - minX;
maxX -= d / 10;
minX -= d / 10;
});
ui.right.click(()=>{
var d = maxX - minX;
maxX += d / 10;
minX += d / 10;
});
ui.up.click(()=>{
var d = maxX - minX;
minY += d / 8;
});
ui.down.click(()=>{
var d = maxX - minX;
minY -= d / 8;
});
ui.zoom_in.click(()=>{
var d = maxX - minX;
var a = (maxX + minX) / 2;
maxX = a + d;
minX = a - d;
minY *= (maxX - minY) / d * h / w;
});
ui.zoom_out.click(()=>{
var d = maxX - minX;
maxX -= d / 2;
minX += d / 2;
});
脚本引擎
停止所有正在运行的脚本
engines.stopAllAndToast();
运行脚本文件
var scriptsPath = "/sdcard/脚本/";
if(!files.exists(scriptsPath)){
scriptsPath = "/sdcard/Scripts/";
}
var scriptFiles = files.listDir(scriptsPath, function(name){
return name.endsWith(".js");
});
var i = dialogs.singleChoice("请选择要运行的脚本", scriptFiles);
if(i < 0){
exit();
}
var path = files.join(scriptsPath, scriptFiles[i]);
engines.execScriptFile(path);
运行录制文件
var scriptsPath = "/sdcard/脚本/";
if(!files.exists(scriptsPath)){
scriptsPath = "/sdcard/Scripts/";
}
var scriptFiles = files.listDir(scriptsPath, function(name){
return name.endsWith(".auto");
});
var i = dialogs.singleChoice("请选择要运行的脚本", scriptFiles);
if(i < 0){
exit();
}
var path = files.join(scriptsPath, scriptFiles[i]);
engines.execAutoFile(path);
运行新的脚本任务
var script = "toast('Hello, Auto.js');" +
"sleep(3000);" +
"toast('略略略');";
var execution = engines.execScript("Hello", script);
sleep(1000);
execution.getEngine().forceStop();
界面控件
按钮控件
"ui";
ui.layout(
<vertical padding="16">
<button text="普通按钮" w="auto"/>
<button text="带颜色按钮" style="Widget.AppCompat.Button.Colored" w="auto"/>
<button text="无边框按钮" style="Widget.AppCompat.Button.Borderless" w="auto"/>
<button text="无边框有颜色按钮" style="Widget.AppCompat.Button.Borderless.Colored" w="auto"/>
<button text="长长的按钮" w="*"/>
<button id="click_me" text="点我" w="auto"/>
</vertical>
);
ui.click_me.on("click", ()=>{
toast("我被点啦");
});
ui.click_me.on("long_click", ()=>{
toast("我被长按啦");
});
表格控件-内置图标查看器
"ui";
ui.layout(
<vertical>
<linear>
<input id="input" layout_weight="1" textColor="black" textSize="16sp" marginLeft="16"/>
<button id="search" text="搜索" style="Widget.AppCompat.Button.Borderless.Colored"/>
<button id="reset" text="重置" style="Widget.AppCompat.Button.Borderless.Colored"/>
</linear>
<grid id="icons" spanCount="4" h="*">
<img src="@drawable/{{this}}" h="80" margin="12" bg="?selectableItemBackgroundBorderless"/>
</grid>
</vertical>
);
//所有内置图标名称
var icons = ['ic_3d_rotation_black_48dp', 'ic_accessibility_black_48dp', 'ic_accessible_black_48dp', 'ic_account_balance_black_48dp', 'ic_account_balance_wallet_black_48dp', 'ic_account_box_black_48dp', 'ic_account_circle_black_48dp', 'ic_add_shopping_cart_black_48dp', 'ic_alarm_add_black_48dp', 'ic_alarm_black_48dp', 'ic_alarm_off_black_48dp', 'ic_alarm_on_black_48dp', 'ic_all_out_black_48dp', 'ic_android_black_48dp', 'ic_announcement_black_48dp', 'ic_aspect_ratio_black_48dp', 'ic_assessment_black_48dp', 'ic_assignment_black_48dp', 'ic_assignment_ind_black_48dp', 'ic_assignment_late_black_48dp', 'ic_assignment_returned_black_48dp', 'ic_assignment_return_black_48dp', 'ic_assignment_turned_in_black_48dp', 'ic_autorenew_black_48dp', 'ic_backup_black_48dp', 'ic_bookmark_black_48dp', 'ic_bookmark_border_black_48dp', 'ic_book_black_48dp', 'ic_bug_report_black_48dp', 'ic_build_black_48dp', 'ic_cached_black_48dp', 'ic_camera_enhance_black_48dp', 'ic_card_giftcard_black_48dp', 'ic_card_membership_black_48dp', 'ic_card_travel_black_48dp', 'ic_change_history_black_48dp', 'ic_check_circle_black_48dp', 'ic_chrome_reader_mode_black_48dp', 'ic_class_black_48dp', 'ic_code_black_48dp', 'ic_compare_arrows_black_48dp', 'ic_copyright_black_48dp', 'ic_credit_card_black_48dp', 'ic_dashboard_black_48dp', 'ic_date_range_black_48dp', 'ic_delete_black_48dp', 'ic_delete_forever_black_48dp', 'ic_description_black_48dp', 'ic_dns_black_48dp', 'ic_done_all_black_48dp', 'ic_done_black_48dp', 'ic_donut_large_black_48dp', 'ic_donut_small_black_48dp', 'ic_eject_black_48dp', 'ic_euro_symbol_black_48dp', 'ic_event_black_48dp', 'ic_event_seat_black_48dp', 'ic_exit_to_app_black_48dp', 'ic_explore_black_48dp', 'ic_extension_black_48dp', 'ic_face_black_48dp', 'ic_favorite_black_48dp', 'ic_favorite_border_black_48dp', 'ic_feedback_black_48dp', 'ic_find_in_page_black_48dp', 'ic_find_replace_black_48dp', 'ic_fingerprint_black_48dp', 'ic_flight_land_black_48dp', 'ic_flight_takeoff_black_48dp', 'ic_flip_to_back_black_48dp', 'ic_flip_to_front_black_48dp', 'ic_gavel_black_48dp', 'ic_get_app_black_48dp', 'ic_gif_black_48dp', 'ic_grade_black_48dp', 'ic_group_work_black_48dp', 'ic_g_translate_black_48dp', 'ic_help_black_48dp', 'ic_help_outline_black_48dp', 'ic_highlight_off_black_48dp', 'ic_history_black_48dp', 'ic_home_black_48dp', 'ic_hourglass_empty_black_48dp', 'ic_hourglass_full_black_48dp', 'ic_https_black_48dp', 'ic_http_black_48dp', 'ic_important_devices_black_48dp', 'ic_info_black_48dp', 'ic_info_outline_black_48dp', 'ic_input_black_48dp', 'ic_invert_colors_black_48dp', 'ic_label_black_48dp', 'ic_label_outline_black_48dp', 'ic_language_black_48dp', 'ic_launch_black_48dp', 'ic_lightbulb_outline_black_48dp', 'ic_line_style_black_48dp', 'ic_line_weight_black_48dp', 'ic_list_black_48dp', 'ic_lock_black_48dp', 'ic_lock_open_black_48dp', 'ic_lock_outline_black_48dp', 'ic_loyalty_black_48dp', 'ic_markunread_mailbox_black_48dp', 'ic_motorcycle_black_48dp', 'ic_note_add_black_48dp', 'ic_offline_pin_black_48dp', 'ic_opacity_black_48dp', 'ic_open_in_browser_black_48dp', 'ic_open_in_new_black_48dp', 'ic_open_with_black_48dp', 'ic_pageview_black_48dp', 'ic_pan_tool_black_48dp', 'ic_payment_black_48dp', 'ic_perm_camera_mic_black_48dp', 'ic_perm_contact_calendar_black_48dp', 'ic_perm_data_setting_black_48dp', 'ic_perm_device_information_black_48dp', 'ic_perm_identity_black_48dp', 'ic_perm_media_black_48dp', 'ic_perm_phone_msg_black_48dp', 'ic_perm_scan_wifi_black_48dp', 'ic_pets_black_48dp', 'ic_picture_in_picture_alt_black_48dp', 'ic_picture_in_picture_black_48dp', 'ic_play_for_work_black_48dp', 'ic_polymer_black_48dp', 'ic_power_settings_new_black_48dp', 'ic_pregnant_woman_black_48dp', 'ic_print_black_48dp', 'ic_query_builder_black_48dp', 'ic_question_answer_black_48dp', 'ic_receipt_black_48dp', 'ic_record_voice_over_black_48dp', 'ic_redeem_black_48dp', 'ic_remove_shopping_cart_black_48dp', 'ic_reorder_black_48dp', 'ic_report_problem_black_48dp', 'ic_restore_black_48dp', 'ic_restore_page_black_48dp', 'ic_room_black_48dp', 'ic_rounded_corner_black_48dp', 'ic_rowing_black_48dp', 'ic_schedule_black_48dp', 'ic_search_black_48dp', 'ic_settings_applications_black_48dp', 'ic_settings_backup_restore_black_48dp', 'ic_settings_black_48dp', 'ic_settings_bluetooth_black_48dp', 'ic_settings_brightness_black_48dp', 'ic_settings_cell_black_48dp', 'ic_settings_ethernet_black_48dp', 'ic_settings_input_antenna_black_48dp', 'ic_settings_input_component_black_48dp', 'ic_settings_input_composite_black_48dp', 'ic_settings_input_hdmi_black_48dp', 'ic_settings_input_svideo_black_48dp', 'ic_settings_overscan_black_48dp', 'ic_settings_phone_black_48dp', 'ic_settings_power_black_48dp', 'ic_settings_remote_black_48dp', 'ic_settings_voice_black_48dp', 'ic_shopping_basket_black_48dp', 'ic_shopping_cart_black_48dp', 'ic_shop_black_48dp', 'ic_shop_two_black_48dp', 'ic_speaker_notes_black_48dp', 'ic_speaker_notes_off_black_48dp', 'ic_spellcheck_black_48dp', 'ic_stars_black_48dp', 'ic_store_black_48dp', 'ic_subject_black_48dp', 'ic_supervisor_account_black_48dp', 'ic_swap_horiz_black_48dp', 'ic_swap_vertical_circle_black_48dp', 'ic_swap_vert_black_48dp', 'ic_system_update_alt_black_48dp', 'ic_tab_black_48dp', 'ic_tab_unselected_black_48dp', 'ic_theaters_black_48dp', 'ic_thumbs_up_down_black_48dp', 'ic_thumb_down_black_48dp', 'ic_thumb_up_black_48dp', 'ic_timeline_black_48dp', 'ic_toc_black_48dp', 'ic_today_black_48dp', 'ic_toll_black_48dp', 'ic_touch_app_black_48dp', 'ic_track_changes_black_48dp', 'ic_translate_black_48dp', 'ic_trending_down_black_48dp', 'ic_trending_flat_black_48dp', 'ic_trending_up_black_48dp', 'ic_turned_in_black_48dp', 'ic_turned_in_not_black_48dp', 'ic_update_black_48dp', 'ic_verified_user_black_48dp', 'ic_view_agenda_black_48dp', 'ic_view_array_black_48dp', 'ic_view_carousel_black_48dp', 'ic_view_column_black_48dp', 'ic_view_day_black_48dp', 'ic_view_headline_black_48dp', 'ic_view_list_black_48dp', 'ic_view_module_black_48dp', 'ic_view_quilt_black_48dp', 'ic_view_stream_black_48dp', 'ic_view_week_black_48dp', 'ic_visibility_black_48dp', 'ic_visibility_off_black_48dp', 'ic_watch_later_black_48dp', 'ic_work_black_48dp', 'ic_youtube_searched_for_black_48dp', 'ic_zoom_in_black_48dp', 'ic_zoom_out_black_48dp', 'ic_add_alert_black_48dp', 'ic_error_black_48dp', 'ic_error_outline_black_48dp', 'ic_warning_black_48dp', 'ic_add_to_queue_black_48dp', 'ic_airplay_black_48dp', 'ic_album_black_48dp', 'ic_art_track_black_48dp', 'ic_av_timer_black_48dp', 'ic_branding_watermark_black_48dp', 'ic_call_to_action_black_48dp', 'ic_closed_caption_black_48dp', 'ic_equalizer_black_48dp', 'ic_explicit_black_48dp', 'ic_fast_forward_black_48dp', 'ic_fast_rewind_black_48dp', 'ic_featured_play_list_black_48dp', 'ic_featured_video_black_48dp', 'ic_fiber_dvr_black_48dp', 'ic_fiber_manual_record_black_48dp', 'ic_fiber_new_black_48dp', 'ic_fiber_pin_black_48dp', 'ic_fiber_smart_record_black_48dp', 'ic_forward_10_black_48dp', 'ic_forward_30_black_48dp', 'ic_forward_5_black_48dp', 'ic_games_black_48dp', 'ic_hd_black_48dp', 'ic_hearing_black_48dp', 'ic_high_quality_black_48dp', 'ic_library_add_black_48dp', 'ic_library_books_black_48dp', 'ic_library_music_black_48dp', 'ic_loop_black_48dp', 'ic_mic_black_48dp', 'ic_mic_none_black_48dp', 'ic_mic_off_black_48dp', 'ic_movie_black_48dp', 'ic_music_video_black_48dp', 'ic_new_releases_black_48dp', 'ic_note_black_48dp', 'ic_not_interested_black_48dp', 'ic_pause_black_48dp', 'ic_pause_circle_filled_black_48dp', 'ic_pause_circle_outline_black_48dp', 'ic_playlist_add_black_48dp', 'ic_playlist_add_check_black_48dp', 'ic_playlist_play_black_48dp', 'ic_play_arrow_black_48dp', 'ic_play_circle_filled_black_48dp', 'ic_play_circle_filled_white_black_48dp', 'ic_play_circle_outline_black_48dp', 'ic_queue_black_48dp', 'ic_queue_music_black_48dp', 'ic_queue_play_next_black_48dp', 'ic_radio_black_48dp', 'ic_recent_actors_black_48dp', 'ic_remove_from_queue_black_48dp', 'ic_repeat_black_48dp', 'ic_repeat_one_black_48dp', 'ic_replay_10_black_48dp', 'ic_replay_30_black_48dp', 'ic_replay_5_black_48dp', 'ic_replay_black_48dp', 'ic_shuffle_black_48dp', 'ic_skip_next_black_48dp', 'ic_skip_previous_black_48dp', 'ic_slow_motion_video_black_48dp', 'ic_snooze_black_48dp', 'ic_sort_by_alpha_black_48dp', 'ic_stop_black_48dp', 'ic_subscriptions_black_48dp', 'ic_subtitles_black_48dp', 'ic_surround_sound_black_48dp', 'ic_videocam_black_48dp', 'ic_videocam_off_black_48dp', 'ic_video_call_black_48dp', 'ic_video_label_black_48dp', 'ic_video_library_black_48dp', 'ic_volume_down_black_48dp', 'ic_volume_mute_black_48dp', 'ic_volume_off_black_48dp', 'ic_volume_up_black_48dp', 'ic_web_asset_black_48dp', 'ic_web_black_48dp', 'ic_business_black_48dp', 'ic_call_black_48dp', 'ic_call_end_black_48dp', 'ic_call_made_black_48dp', 'ic_call_merge_black_48dp', 'ic_call_missed_black_48dp', 'ic_call_missed_outgoing_black_48dp', 'ic_call_received_black_48dp', 'ic_call_split_black_48dp', 'ic_chat_black_48dp', 'ic_chat_bubble_black_48dp', 'ic_chat_bubble_outline_black_48dp', 'ic_clear_all_black_48dp', 'ic_comment_black_48dp', 'ic_contacts_black_48dp', 'ic_contact_mail_black_48dp', 'ic_contact_phone_black_48dp', 'ic_dialer_sip_black_48dp', 'ic_dialpad_black_48dp', 'ic_email_black_48dp', 'ic_forum_black_48dp', 'ic_import_contacts_black_48dp', 'ic_import_export_black_48dp', 'ic_invert_colors_off_black_48dp', 'ic_live_help_black_48dp', 'ic_location_off_black_48dp', 'ic_location_on_black_48dp', 'ic_mail_outline_black_48dp', 'ic_message_black_48dp', 'ic_no_sim_black_48dp', 'ic_phonelink_erase_black_48dp', 'ic_phonelink_lock_black_48dp', 'ic_phonelink_ring_black_48dp', 'ic_phonelink_setup_black_48dp', 'ic_phone_black_48dp', 'ic_portable_wifi_off_black_48dp', 'ic_present_to_all_black_48dp', 'ic_ring_volume_black_48dp', 'ic_rss_feed_black_48dp', 'ic_screen_share_black_48dp', 'ic_speaker_phone_black_48dp', 'ic_stay_current_landscape_black_48dp', 'ic_stay_current_portrait_black_48dp', 'ic_stay_primary_landscape_black_48dp', 'ic_stay_primary_portrait_black_48dp', 'ic_stop_screen_share_black_48dp', 'ic_swap_calls_black_48dp', 'ic_textsms_black_48dp', 'ic_voicemail_black_48dp', 'ic_vpn_key_black_48dp', 'ic_add_black_48dp', 'ic_add_box_black_48dp', 'ic_add_circle_black_48dp', 'ic_add_circle_outline_black_48dp', 'ic_archive_black_48dp', 'ic_backspace_black_48dp', 'ic_block_black_48dp', 'ic_clear_black_48dp', 'ic_content_copy_black_48dp', 'ic_content_cut_black_48dp', 'ic_content_paste_black_48dp', 'ic_create_black_48dp', 'ic_delete_sweep_black_48dp', 'ic_drafts_black_48dp', 'ic_filter_list_black_48dp', 'ic_flag_black_48dp', 'ic_font_download_black_48dp', 'ic_forward_black_48dp', 'ic_gesture_black_48dp', 'ic_inbox_black_48dp', 'ic_link_black_48dp', 'ic_low_priority_black_48dp', 'ic_mail_black_48dp', 'ic_markunread_black_48dp', 'ic_move_to_inbox_black_48dp', 'ic_next_week_black_48dp', 'ic_redo_black_48dp', 'ic_remove_black_48dp', 'ic_remove_circle_black_48dp', 'ic_remove_circle_outline_black_48dp', 'ic_reply_all_black_48dp', 'ic_reply_black_48dp', 'ic_report_black_48dp', 'ic_save_black_48dp', 'ic_select_all_black_48dp', 'ic_send_black_48dp', 'ic_sort_black_48dp', 'ic_text_format_black_48dp', 'ic_unarchive_black_48dp', 'ic_undo_black_48dp', 'ic_weekend_black_48dp', 'ic_access_alarms_black_48dp', 'ic_access_alarm_black_48dp', 'ic_access_time_black_48dp', 'ic_add_alarm_black_48dp', 'ic_airplanemode_active_black_48dp', 'ic_airplanemode_inactive_black_48dp', 'ic_battery_20_black_48dp', 'ic_battery_30_black_48dp', 'ic_battery_50_black_48dp', 'ic_battery_60_black_48dp', 'ic_battery_80_black_48dp', 'ic_battery_90_black_48dp', 'ic_battery_alert_black_48dp', 'ic_battery_charging_20_black_48dp', 'ic_battery_charging_30_black_48dp', 'ic_battery_charging_50_black_48dp', 'ic_battery_charging_60_black_48dp', 'ic_battery_charging_80_black_48dp', 'ic_battery_charging_90_black_48dp', 'ic_battery_charging_full_black_48dp', 'ic_battery_full_black_48dp', 'ic_battery_std_black_48dp', 'ic_battery_unknown_black_48dp', 'ic_bluetooth_black_48dp', 'ic_bluetooth_connected_black_48dp', 'ic_bluetooth_disabled_black_48dp', 'ic_bluetooth_searching_black_48dp', 'ic_brightness_auto_black_48dp', 'ic_brightness_high_black_48dp', 'ic_brightness_low_black_48dp', 'ic_brightness_medium_black_48dp', 'ic_data_usage_black_48dp', 'ic_developer_mode_black_48dp', 'ic_devices_black_48dp', 'ic_dvr_black_48dp', 'ic_gps_fixed_black_48dp', 'ic_gps_not_fixed_black_48dp', 'ic_gps_off_black_48dp', 'ic_graphic_eq_black_48dp', 'ic_location_disabled_black_48dp', 'ic_location_searching_black_48dp', 'ic_network_cell_black_48dp', 'ic_network_wifi_black_48dp', 'ic_nfc_black_48dp', 'ic_screen_lock_landscape_black_48dp', 'ic_screen_lock_portrait_black_48dp', 'ic_screen_lock_rotation_black_48dp', 'ic_screen_rotation_black_48dp', 'ic_sd_storage_black_48dp', 'ic_settings_system_daydream_black_48dp', 'ic_signal_cellular_0_bar_black_48dp', 'ic_signal_cellular_1_bar_black_48dp', 'ic_signal_cellular_2_bar_black_48dp', 'ic_signal_cellular_3_bar_black_48dp', 'ic_signal_cellular_4_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_0_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_1_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_2_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_3_bar_black_48dp', 'ic_signal_cellular_connected_no_internet_4_bar_black_48dp', 'ic_signal_cellular_no_sim_black_48dp', 'ic_signal_cellular_null_black_48dp', 'ic_signal_cellular_off_black_48dp', 'ic_signal_wifi_0_bar_black_48dp', 'ic_signal_wifi_1_bar_black_48dp', 'ic_signal_wifi_1_bar_lock_black_48dp', 'ic_signal_wifi_2_bar_black_48dp', 'ic_signal_wifi_2_bar_lock_black_48dp', 'ic_signal_wifi_3_bar_black_48dp', 'ic_signal_wifi_3_bar_lock_black_48dp', 'ic_signal_wifi_4_bar_black_48dp', 'ic_signal_wifi_4_bar_lock_black_48dp', 'ic_signal_wifi_off_black_48dp', 'ic_storage_black_48dp', 'ic_usb_black_48dp', 'ic_wallpaper_black_48dp', 'ic_widgets_black_48dp', 'ic_wifi_lock_black_48dp', 'ic_wifi_tethering_black_48dp', 'ic_attach_file_black_48dp', 'ic_attach_money_black_48dp', 'ic_border_all_black_48dp', 'ic_border_bottom_black_48dp', 'ic_border_clear_black_48dp', 'ic_border_color_black_48dp', 'ic_border_horizontal_black_48dp', 'ic_border_inner_black_48dp', 'ic_border_left_black_48dp', 'ic_border_outer_black_48dp', 'ic_border_right_black_48dp', 'ic_border_style_black_48dp', 'ic_border_top_black_48dp', 'ic_border_vertical_black_48dp', 'ic_bubble_chart_black_48dp', 'ic_drag_handle_black_48dp', 'ic_format_align_center_black_48dp', 'ic_format_align_justify_black_48dp', 'ic_format_align_left_black_48dp', 'ic_format_align_right_black_48dp', 'ic_format_bold_black_48dp', 'ic_format_clear_black_48dp', 'ic_format_color_fill_black_48dp', 'ic_format_color_reset_black_48dp', 'ic_format_color_text_black_48dp', 'ic_format_indent_decrease_black_48dp', 'ic_format_indent_increase_black_48dp', 'ic_format_italic_black_48dp', 'ic_format_line_spacing_black_48dp', 'ic_format_list_bulleted_black_48dp', 'ic_format_list_numbered_black_48dp', 'ic_format_paint_black_48dp', 'ic_format_quote_black_48dp', 'ic_format_shapes_black_48dp', 'ic_format_size_black_48dp', 'ic_format_strikethrough_black_48dp', 'ic_format_textdirection_l_to_r_black_48dp', 'ic_format_textdirection_r_to_l_black_48dp', 'ic_format_underlined_black_48dp', 'ic_functions_black_48dp', 'ic_highlight_black_48dp', 'ic_insert_chart_black_48dp', 'ic_insert_comment_black_48dp', 'ic_insert_drive_file_black_48dp', 'ic_insert_emoticon_black_48dp', 'ic_insert_invitation_black_48dp', 'ic_insert_link_black_48dp', 'ic_insert_photo_black_48dp', 'ic_linear_scale_black_48dp', 'ic_merge_type_black_48dp', 'ic_mode_comment_black_48dp', 'ic_mode_edit_black_48dp', 'ic_monetization_on_black_48dp', 'ic_money_off_black_48dp', 'ic_multiline_chart_black_48dp', 'ic_pie_chart_black_48dp', 'ic_pie_chart_outlined_black_48dp', 'ic_publish_black_48dp', 'ic_short_text_black_48dp', 'ic_show_chart_black_48dp', 'ic_space_bar_black_48dp', 'ic_strikethrough_s_black_48dp', 'ic_text_fields_black_48dp', 'ic_title_black_48dp', 'ic_vertical_align_bottom_black_48dp', 'ic_vertical_align_center_black_48dp', 'ic_vertical_align_top_black_48dp', 'ic_wrap_text_black_48dp', 'ic_attachment_black_48dp', 'ic_cloud_black_48dp', 'ic_cloud_circle_black_48dp', 'ic_cloud_done_black_48dp', 'ic_cloud_download_black_48dp', 'ic_cloud_off_black_48dp', 'ic_cloud_queue_black_48dp', 'ic_cloud_upload_black_48dp', 'ic_create_new_folder_black_48dp', 'ic_file_download_black_48dp', 'ic_file_upload_black_48dp', 'ic_folder_black_48dp', 'ic_folder_open_black_48dp', 'ic_folder_shared_black_48dp', 'ic_cast_black_48dp', 'ic_cast_connected_black_48dp', 'ic_computer_black_48dp', 'ic_desktop_mac_black_48dp', 'ic_desktop_windows_black_48dp', 'ic_developer_board_black_48dp', 'ic_devices_other_black_48dp', 'ic_device_hub_black_48dp', 'ic_dock_black_48dp', 'ic_gamepad_black_48dp', 'ic_headset_black_48dp', 'ic_headset_mic_black_48dp', 'ic_keyboard_arrow_down_black_48dp', 'ic_keyboard_arrow_left_black_48dp', 'ic_keyboard_arrow_right_black_48dp', 'ic_keyboard_arrow_up_black_48dp', 'ic_keyboard_backspace_black_48dp', 'ic_keyboard_black_48dp', 'ic_keyboard_capslock_black_48dp', 'ic_keyboard_hide_black_48dp', 'ic_keyboard_return_black_48dp', 'ic_keyboard_tab_black_48dp', 'ic_keyboard_voice_black_48dp', 'ic_laptop_black_48dp', 'ic_laptop_chromebook_black_48dp', 'ic_laptop_mac_black_48dp', 'ic_laptop_windows_black_48dp', 'ic_memory_black_48dp', 'ic_mouse_black_48dp', 'ic_phonelink_black_48dp', 'ic_phonelink_off_black_48dp', 'ic_phone_android_black_48dp', 'ic_phone_iphone_black_48dp', 'ic_power_input_black_48dp', 'ic_router_black_48dp', 'ic_scanner_black_48dp', 'ic_security_black_48dp', 'ic_sim_card_black_48dp', 'ic_smartphone_black_48dp', 'ic_speaker_black_48dp', 'ic_speaker_group_black_48dp', 'ic_tablet_android_black_48dp', 'ic_tablet_black_48dp', 'ic_tablet_mac_black_48dp', 'ic_toys_black_48dp', 'ic_tv_black_48dp', 'ic_videogame_asset_black_48dp', 'ic_watch_black_48dp', 'ic_add_a_photo_black_48dp', 'ic_add_to_photos_black_48dp', 'ic_adjust_black_48dp', 'ic_assistant_black_48dp', 'ic_assistant_photo_black_48dp', 'ic_audiotrack_black_48dp', 'ic_blur_circular_black_48dp', 'ic_blur_linear_black_48dp', 'ic_blur_off_black_48dp', 'ic_blur_on_black_48dp', 'ic_brightness_1_black_48dp', 'ic_brightness_2_black_48dp', 'ic_brightness_3_black_48dp', 'ic_brightness_4_black_48dp', 'ic_brightness_5_black_48dp', 'ic_brightness_6_black_48dp', 'ic_brightness_7_black_48dp', 'ic_broken_image_black_48dp', 'ic_brush_black_48dp', 'ic_burst_mode_black_48dp', 'ic_camera_alt_black_48dp', 'ic_camera_black_48dp', 'ic_camera_front_black_48dp', 'ic_camera_rear_black_48dp', 'ic_camera_roll_black_48dp', 'ic_center_focus_strong_black_48dp', 'ic_center_focus_weak_black_48dp', 'ic_collections_black_48dp', 'ic_collections_bookmark_black_48dp', 'ic_colorize_black_48dp', 'ic_color_lens_black_48dp', 'ic_compare_black_48dp', 'ic_control_point_black_48dp', 'ic_control_point_duplicate_black_48dp', 'ic_crop_16_9_black_48dp', 'ic_crop_3_2_black_48dp', 'ic_crop_5_4_black_48dp', 'ic_crop_7_5_black_48dp', 'ic_crop_black_48dp', 'ic_crop_din_black_48dp', 'ic_crop_free_black_48dp', 'ic_crop_landscape_black_48dp', 'ic_crop_original_black_48dp', 'ic_crop_portrait_black_48dp', 'ic_crop_rotate_black_48dp', 'ic_crop_square_black_48dp', 'ic_dehaze_black_48dp', 'ic_details_black_48dp', 'ic_edit_black_48dp', 'ic_exposure_black_48dp', 'ic_exposure_neg_1_black_48dp', 'ic_exposure_neg_2_black_48dp', 'ic_exposure_plus_1_black_48dp', 'ic_exposure_plus_2_black_48dp', 'ic_exposure_zero_black_48dp', 'ic_filter_1_black_48dp', 'ic_filter_2_black_48dp', 'ic_filter_3_black_48dp', 'ic_filter_4_black_48dp', 'ic_filter_5_black_48dp', 'ic_filter_6_black_48dp', 'ic_filter_7_black_48dp', 'ic_filter_8_black_48dp', 'ic_filter_9_black_48dp', 'ic_filter_9_plus_black_48dp', 'ic_filter_black_48dp', 'ic_filter_b_and_w_black_48dp', 'ic_filter_center_focus_black_48dp', 'ic_filter_drama_black_48dp', 'ic_filter_frames_black_48dp', 'ic_filter_hdr_black_48dp', 'ic_filter_none_black_48dp', 'ic_filter_tilt_shift_black_48dp', 'ic_filter_vintage_black_48dp', 'ic_flare_black_48dp', 'ic_flash_auto_black_48dp', 'ic_flash_off_black_48dp', 'ic_flash_on_black_48dp', 'ic_flip_black_48dp', 'ic_gradient_black_48dp', 'ic_grain_black_48dp', 'ic_grid_off_black_48dp', 'ic_grid_on_black_48dp', 'ic_hdr_off_black_48dp', 'ic_hdr_on_black_48dp', 'ic_hdr_strong_black_48dp', 'ic_hdr_weak_black_48dp', 'ic_healing_black_48dp', 'ic_image_aspect_ratio_black_48dp', 'ic_image_black_48dp', 'ic_iso_black_48dp', 'ic_landscape_black_48dp', 'ic_leak_add_black_48dp', 'ic_leak_remove_black_48dp', 'ic_lens_black_48dp', 'ic_linked_camera_black_48dp', 'ic_looks_3_black_48dp', 'ic_looks_4_black_48dp', 'ic_looks_5_black_48dp', 'ic_looks_6_black_48dp', 'ic_looks_black_48dp', 'ic_looks_one_black_48dp', 'ic_looks_two_black_48dp', 'ic_loupe_black_48dp', 'ic_monochrome_photos_black_48dp', 'ic_movie_creation_black_48dp', 'ic_movie_filter_black_48dp', 'ic_music_note_black_48dp', 'ic_nature_black_48dp', 'ic_nature_people_black_48dp', 'ic_navigate_before_black_48dp', 'ic_navigate_next_black_48dp', 'ic_palette_black_48dp', 'ic_panorama_black_48dp', 'ic_panorama_fish_eye_black_48dp', 'ic_panorama_horizontal_black_48dp', 'ic_panorama_vertical_black_48dp', 'ic_panorama_wide_angle_black_48dp', 'ic_photo_album_black_48dp', 'ic_photo_black_48dp', 'ic_photo_camera_black_48dp', 'ic_photo_filter_black_48dp', 'ic_photo_library_black_48dp', 'ic_photo_size_select_actual_black_48dp', 'ic_photo_size_select_large_black_48dp', 'ic_photo_size_select_small_black_48dp', 'ic_picture_as_pdf_black_48dp', 'ic_portrait_black_48dp', 'ic_remove_red_eye_black_48dp', 'ic_rotate_90_degrees_ccw_black_48dp', 'ic_rotate_left_black_48dp', 'ic_rotate_right_black_48dp', 'ic_slideshow_black_48dp', 'ic_straighten_black_48dp', 'ic_style_black_48dp', 'ic_switch_camera_black_48dp', 'ic_switch_video_black_48dp', 'ic_tag_faces_black_48dp', 'ic_texture_black_48dp', 'ic_timelapse_black_48dp', 'ic_timer_10_black_48dp', 'ic_timer_3_black_48dp', 'ic_timer_black_48dp', 'ic_timer_off_black_48dp', 'ic_tonality_black_48dp', 'ic_transform_black_48dp', 'ic_tune_black_48dp', 'ic_view_comfy_black_48dp', 'ic_view_compact_black_48dp', 'ic_vignette_black_48dp', 'ic_wb_auto_black_48dp', 'ic_wb_cloudy_black_48dp', 'ic_wb_incandescent_black_48dp', 'ic_wb_iridescent_black_48dp', 'ic_wb_sunny_black_48dp', 'ic_add_location_black_48dp', 'ic_beenhere_black_48dp', 'ic_directions_bike_black_48dp', 'ic_directions_black_48dp', 'ic_directions_boat_black_48dp', 'ic_directions_bus_black_48dp', 'ic_directions_car_black_48dp', 'ic_directions_railway_black_48dp', 'ic_directions_run_black_48dp', 'ic_directions_subway_black_48dp', 'ic_directions_transit_black_48dp', 'ic_directions_walk_black_48dp', 'ic_edit_location_black_48dp', 'ic_ev_station_black_48dp', 'ic_flight_black_48dp', 'ic_hotel_black_48dp', 'ic_layers_black_48dp', 'ic_layers_clear_black_48dp', 'ic_local_activity_black_48dp', 'ic_local_airport_black_48dp', 'ic_local_atm_black_48dp', 'ic_local_bar_black_48dp', 'ic_local_cafe_black_48dp', 'ic_local_car_wash_black_48dp', 'ic_local_convenience_store_black_48dp', 'ic_local_dining_black_48dp', 'ic_local_drink_black_48dp', 'ic_local_florist_black_48dp', 'ic_local_gas_station_black_48dp', 'ic_local_grocery_store_black_48dp', 'ic_local_hospital_black_48dp', 'ic_local_hotel_black_48dp', 'ic_local_laundry_service_black_48dp', 'ic_local_library_black_48dp', 'ic_local_mall_black_48dp', 'ic_local_movies_black_48dp', 'ic_local_offer_black_48dp', 'ic_local_parking_black_48dp', 'ic_local_pharmacy_black_48dp', 'ic_local_phone_black_48dp', 'ic_local_pizza_black_48dp', 'ic_local_play_black_48dp', 'ic_local_post_office_black_48dp', 'ic_local_printshop_black_48dp', 'ic_local_see_black_48dp', 'ic_local_shipping_black_48dp', 'ic_local_taxi_black_48dp', 'ic_map_black_48dp', 'ic_my_location_black_48dp', 'ic_navigation_black_48dp', 'ic_near_me_black_48dp', 'ic_person_pin_black_48dp', 'ic_person_pin_circle_black_48dp', 'ic_pin_drop_black_48dp', 'ic_place_black_48dp', 'ic_rate_review_black_48dp', 'ic_restaurant_black_48dp', 'ic_restaurant_menu_black_48dp', 'ic_satellite_black_48dp', 'ic_store_mall_directory_black_48dp', 'ic_streetview_black_48dp', 'ic_subway_black_48dp', 'ic_terrain_black_48dp', 'ic_traffic_black_48dp', 'ic_train_black_48dp', 'ic_tram_black_48dp', 'ic_transfer_within_a_station_black_48dp', 'ic_zoom_out_map_black_48dp', 'ic_apps_black_48dp', 'ic_arrow_back_black_48dp', 'ic_arrow_downward_black_48dp', 'ic_arrow_drop_down_black_48dp', 'ic_arrow_drop_down_circle_black_48dp', 'ic_arrow_drop_up_black_48dp', 'ic_arrow_forward_black_48dp', 'ic_arrow_upward_black_48dp', 'ic_cancel_black_48dp', 'ic_check_black_48dp', 'ic_chevron_left_black_48dp', 'ic_chevron_right_black_48dp', 'ic_close_black_48dp', 'ic_expand_less_black_48dp', 'ic_expand_more_black_48dp', 'ic_first_page_black_48dp', 'ic_fullscreen_black_48dp', 'ic_fullscreen_exit_black_48dp', 'ic_last_page_black_48dp', 'ic_menu_black_48dp', 'ic_more_horiz_black_48dp', 'ic_more_vert_black_48dp', 'ic_refresh_black_48dp', 'ic_subdirectory_arrow_left_black_48dp', 'ic_subdirectory_arrow_right_black_48dp', 'ic_unfold_less_black_48dp', 'ic_unfold_more_black_48dp', 'ic_adb_black_48dp', 'ic_airline_seat_flat_angled_black_48dp', 'ic_airline_seat_flat_black_48dp', 'ic_airline_seat_individual_suite_black_48dp', 'ic_airline_seat_legroom_extra_black_48dp', 'ic_airline_seat_legroom_normal_black_48dp', 'ic_airline_seat_legroom_reduced_black_48dp', 'ic_airline_seat_recline_extra_black_48dp', 'ic_airline_seat_recline_normal_black_48dp', 'ic_bluetooth_audio_black_48dp', 'ic_confirmation_number_black_48dp', 'ic_disc_full_black_48dp', 'ic_do_not_disturb_alt_black_48dp', 'ic_do_not_disturb_black_48dp', 'ic_do_not_disturb_off_black_48dp', 'ic_do_not_disturb_on_black_48dp', 'ic_drive_eta_black_48dp', 'ic_enhanced_encryption_black_48dp', 'ic_event_available_black_48dp', 'ic_event_busy_black_48dp', 'ic_event_note_black_48dp', 'ic_folder_special_black_48dp', 'ic_live_tv_black_48dp', 'ic_mms_black_48dp', 'ic_more_black_48dp', 'ic_network_check_black_48dp', 'ic_network_locked_black_48dp', 'ic_no_encryption_black_48dp', 'ic_ondemand_video_black_48dp', 'ic_personal_video_black_48dp', 'ic_phone_bluetooth_speaker_black_48dp', 'ic_phone_forwarded_black_48dp', 'ic_phone_in_talk_black_48dp', 'ic_phone_locked_black_48dp', 'ic_phone_missed_black_48dp', 'ic_phone_paused_black_48dp', 'ic_power_black_48dp', 'ic_priority_high_black_48dp', 'ic_rv_hookup_black_48dp', 'ic_sd_card_black_48dp', 'ic_sim_card_alert_black_48dp', 'ic_sms_black_48dp', 'ic_sms_failed_black_48dp', 'ic_sync_black_48dp', 'ic_sync_disabled_black_48dp', 'ic_sync_problem_black_48dp', 'ic_system_update_black_48dp', 'ic_tap_and_play_black_48dp', 'ic_time_to_leave_black_48dp', 'ic_vibration_black_48dp', 'ic_voice_chat_black_48dp', 'ic_vpn_lock_black_48dp', 'ic_wc_black_48dp', 'ic_wifi_black_48dp', 'ic_ac_unit_black_48dp', 'ic_airport_shuttle_black_48dp', 'ic_all_inclusive_black_48dp', 'ic_beach_access_black_48dp', 'ic_business_center_black_48dp', 'ic_casino_black_48dp', 'ic_child_care_black_48dp', 'ic_child_friendly_black_48dp', 'ic_fitness_center_black_48dp', 'ic_free_breakfast_black_48dp', 'ic_golf_course_black_48dp', 'ic_hot_tub_black_48dp', 'ic_kitchen_black_48dp', 'ic_pool_black_48dp', 'ic_room_service_black_48dp', 'ic_smoke_free_black_48dp', 'ic_smoking_rooms_black_48dp', 'ic_spa_black_48dp', 'ic_cake_black_48dp', 'ic_domain_black_48dp', 'ic_group_add_black_48dp', 'ic_group_black_48dp', 'ic_location_city_black_48dp', 'ic_mood_bad_black_48dp', 'ic_mood_black_48dp', 'ic_notifications_active_black_48dp', 'ic_notifications_black_48dp', 'ic_notifications_none_black_48dp', 'ic_notifications_off_black_48dp', 'ic_notifications_paused_black_48dp', 'ic_pages_black_48dp', 'ic_party_mode_black_48dp', 'ic_people_black_48dp', 'ic_people_outline_black_48dp', 'ic_person_add_black_48dp', 'ic_person_black_48dp', 'ic_person_outline_black_48dp', 'ic_plus_one_black_48dp', 'ic_poll_black_48dp', 'ic_public_black_48dp', 'ic_school_black_48dp', 'ic_sentiment_dissatisfied_black_48dp', 'ic_sentiment_neutral_black_48dp', 'ic_sentiment_satisfied_black_48dp', 'ic_sentiment_very_dissatisfied_black_48dp', 'ic_sentiment_very_satisfied_black_48dp', 'ic_share_black_48dp', 'ic_whatshot_black_48dp', 'ic_star_black_48dp', 'ic_star_border_black_48dp', 'ic_star_half_black_48dp'];
ui.icons.setDataSource(icons);
ui.icons.on("item_click", function(icon){
var d = "@drawable/" + icon;
setClip(d);
toast(d + "已复制到剪贴板");
});
ui.search.on("click", function(){
var text = ui.input.text();
if(text.length == 0){
return;
}
search(text);
});
ui.reset.on("click", function(){
ui.icons.setDataSource(icons);
});
function search(keywords){
var result = [];
for(var i = 0; i < icons.length; i++){
var icon = icons[i];
if(icon.indexOf(keywords) >= 0){
result.push(icon);
}
}
ui.icons.setDataSource(result);
}
复选框单选框控件
"ui";
ui.layout(
<vertical padding="16">
<checkbox id="cb1" text="复选框"/>
<checkbox id="cb2" checked="true" text="勾选的复选框"/>
<radiogroup>
<radio text="单选框1"/>
<radio text="单选框2"/>
<radio text="单选框3"/>
</radiogroup>
<radiogroup mariginTop="16">
<radio text="单选框1"/>
<radio text="单选框2"/>
<radio text="勾选的单选框3" checked="true"/>
</radiogroup>
</vertical>
);
ui.cb1.on("check", (checked)=>{
if(checked){
toast("第一个框被勾选了");
}else{
toast("第一个框被取消勾选了");
}
});
进度条控件
"ui";
ui.layout(
<vertical padding="16">
<text text="处理中..." textColor="black" textSize="16sp"/>
<progressbar />
<text text="直线无限进度条" textColor="black" textSize="16sp" marginTop="24"/>
<progressbar indeterminate="true" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>
<text text="直线进度条" textColor="black" textSize="16sp" marginTop="24"/>
<progressbar progress="30" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>
<text text="可调节进度条" textColor="black" textSize="16sp" marginTop="24"/>
<seekbar progress="20"/>
<horizontal gravity="center" marginTop="24">
<text id="progress_value" textColor="black" textSize="16sp" margin="8" text="0"/>
<progressbar id="progress" w="*" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>
</horizontal>
<button id="download">开始下载</button>
</vertical>
);
var downloadId = null;
ui.download.click(()=>{
if(downloadId != null){
stopDownload();
}else{
startDownload();
}
});
function stopDownload(){
ui.download.text("开始下载");
clearInterval(downloadId);
downloadId = null;
}
function startDownload(){
if(ui.progress.getProgress() == 100){
ui.progress.setProgress(0);
}
ui.download.text("停止下载");
downloadId = setInterval(()=>{
var p = ui.progress.getProgress();
p++;
if(p > 100){
stopDownload();
return;
}
ui.progress.setProgress(p);
ui.progress_value.setText(p.toString());
}, 200);
}
卡片布局
"ui";
ui.layout(
<vertical>
<appbar>
<toolbar id="toolbar" title="卡片布局"/>
</appbar>
<card w="*" h="70" margin="10 5" cardCornerRadius="2dp"
cardElevation="1dp" gravity="center_vertical">
<vertical padding="18 8" h="auto">
<text text="写操作系统作业" textColor="#222222" textSize="16sp"/>
<text text="明天第1~2节" textColor="#999999" textSize="14sp"/>
</vertical>
<View bg="#f44336" h="*" w="10"/>
</card>
<card w="*" h="70" margin="10 5" cardCornerRadius="2dp"
cardElevation="1dp" gravity="center_vertical">
<vertical padding="18 8" h="auto">
<text text="修复ui模式的Bug" textColor="#222222" textSize="16sp"/>
<text text="无限期" textColor="#999999" textSize="14sp"/>
</vertical>
<View bg="#ff5722" h="*" w="10"/>
</card>
<card w="*" h="70" margin="10 5" cardCornerRadius="2dp"
cardElevation="1dp" gravity="center_vertical">
<vertical padding="18 8" h="auto">
<text text="发布Auto.js 5.0.0正式版" textColor="#222222" textSize="16sp"/>
<text text="2019年1月" textColor="#999999" textSize="14sp"/>
</vertical>
<View bg="#4caf50" h="*" w="10"/>
</card>
<card w="*" h="70" margin="10 5" cardCornerRadius="2dp"
cardElevation="1dp" gravity="center_vertical">
<vertical padding="18 8" h="auto">
<text text="完成毕业设计和论文" textColor="#222222" textSize="16sp"/>
<text text="2019年4月" textColor="#999999" textSize="14sp"/>
</vertical>
<View bg="#2196f3" h="*" w="10"/>
</card>
</vertical>
);
列表控件
"ui";
ui.layout(
<frame>
<list id="list">
<vertical>
<text id="name" textSize="16sp" textColor="#000000" text="姓名: {{name}}"/>
<text id="age" textSize="16sp" textColor="#000000" text="年龄: {{age}}岁"/>
<button id="deleteItem" text="删除"/>
</vertical>
</list>
</frame>
);
var items = [
{name: "小明", age: 18}, {name: "小红", age: 30},
{name: "小东", age: 19}, {name: "小强", age: 31},
{name: "小满", age: 20}, {name: "小一", age: 32},
{name: "小和", age: 21}, {name: "小二", age: 1},
{name: "小贤", age: 22}, {name: "小三", age: 2},
{name: "小伟", age: 23}, {name: "小四", age: 3},
{name: "小黄", age: 24}, {name: "小五", age: 4},
{name: "小健", age: 25}, {name: "小六", age: 5},
{name: "小啦", age: 26}, {name: "小七", age: 6},
{name: "小哈", age: 27}, {name: "小八", age: 7},
{name: "小啊", age: 28}, {name: "小九", age: 8},
{name: "小啪", age: 29}, {name: "小十", age: 9}
];
ui.list.setDataSource(items);
ui.list.on("item_click", function(item, i, itemView, listView){
toast("被点击的人名字为: " + item.name + ",年龄为: " + item.age);
});
ui.list.on("item_bind", function(itemView, itemHolder){
itemView.deleteItem.on("click", function(){
let item = itemHolder.item;
toast("被删除的人名字为: " + item.name + ",年龄为: " + item.age);
items.splice(itemHolder.position, 1);
});
})
时间日期选择控件
"ui";
ui.layout(
<scroll>
<vertical padding="16">
<text text="日历样式日期选择" textColor="black" textSize="16sp" marginTop="16"/>
<datepicker />
<text text="滑动日期选择" textColor="black" textSize="16sp" marginTop="16"/>
<datepicker datePickerMode="spinner"/>
<text text="时钟样式时间选择" textColor="black" textSize="16sp" marginTop="16"/>
<timepicker />
<text text="滑动时间选择" textColor="black" textSize="16sp" marginTop="16"/>
<timepicker timePickerMode="spinner"/>
</vertical>
</scroll>
)
输入框控件
"ui";
ui.layout(
<vertical padding="16">
<text text="输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input />
<!-- hint属性用来设置输入框的提示-->
<text text="带提示的输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input hint="请输入一些内容"/>
<!-- inputType属性用来设置输入类型,包括number, email, phone等-->
<text text="数字输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input inputType="number" text="123"/>
<!-- password属性用来设置输入框是否是密码输入框 -->
<text text="密码输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input password="true"/>
<!-- lines属性用来设置输入框的行数 -->
<text text="多行输入框" textColor="black" textSize="16sp" marginTop="16"/>
<input lines="3"/>
<text text="设置输入框错误信息" textColor="black" textSize="16sp" marginTop="16"/>
<input id="qq" inputType="number" hint="请输入您的QQ号码"/>
<button id="ok" text="确定" w="auto" style="Widget.AppCompat.Button.Colored"/>
</vertical>
);
ui.ok.click(()=>{
var text = ui.qq.text();
if(text.length == 0){
ui.qq.setError("输入不能为空");
return;
}
var qq = parseInt(text);
if(qq < 10000){
ui.qq.setError("QQ号码格式错误");
return;
}
ui.qq.setError(null);
});
图片控件
"ui";
ui.layout(
<scroll>
<vertical bg="#707070" padding="16">
<text text="网络图片" textColor="black" textSize="16sp" marginTop="16"/>
<img src="http://www.autojs.org/assets/uploads/profile/3-profileavatar.png"
w="100" h="100"/>
<text text="带边框的图片" textColor="black" textSize="16sp" marginTop="16"/>
<img src="http://www.autojs.org/assets/uploads/profile/1-profileavatar.jpeg"
w="100" h="100" borderWidth="2dp" borderColor="#202020"/>
<text text="圆形图片" textColor="black" textSize="16sp" marginTop="16"/>
<img src="http://www.autojs.org/assets/uploads/profile/1-profileavatar.jpeg"
w="100" h="100" circle="true"/>
<text text="带边框的圆形图片" textColor="black" textSize="16sp" marginTop="16"/>
<img src="http://www.autojs.org/assets/uploads/profile/1-profileavatar.jpeg"
w="100" h="100" circle="true" borderWidth="2dp" borderColor="#202020"/>
<text text="圆角图片" textColor="black" textSize="16sp" marginTop="16"/>
<img id="rounded_img" src="http://www.autojs.org/assets/uploads/profile/1-profileavatar.jpeg"
w="100" h="100" radius="20dp" scaleType="fitXY"/>
<button id="change_img" text="更改图片"/>
</vertical>
</scroll>
);
ui.change_img.on("click", ()=>{
ui.rounded_img.setSource("http://www.autojs.org/assets/uploads/profile/1-profilecover.jpeg");
});
文本控件
"ui";
ui.layout(
<vertical padding="16">
<text textSize="40sp">大字</text>
<text textSize="12sp">小字</text>
<text textStyle="bold" textColor="black">加粗</text>
<text textStyle="italic">斜体</text>
<text textColor="#00ff00">原谅色</text>
<text margin="8">Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。Android操作系统最初由Andy Rubin开发,主要支持手机。2005年8月由Google收购注资。2007年11月,Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Android系统。</text>
<text maxLines="1" ellipsize="end" margin="8">Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。Android操作系统最初由Andy Rubin开发,主要支持手机。2005年8月由Google收购注资。2007年11月,Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Android系统。</text>
<text maxLines="2" ellipsize="end" margin="8">Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。Android操作系统最初由Andy Rubin开发,主要支持手机。2005年8月由Google收购注资。2007年11月,Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Android系统。</text>
<text w="*" gravity="center" textSize="20sp">居中</text>
<text autoLink="all">自动超链接网址www.baidu.com, 邮箱 123@qq.com等</text>
</vertical>
);
下拉菜单
"ui";
ui.layout(
<vertical padding="16">
<horizontal>
<text textSize="16sp">下拉菜单</text>
<spinner id="sp1" entries="选项1|选项2|选项3"/>
</horizontal>
<horizontal>
<text textSize="16sp">对话框菜单</text>
<spinner id="sp2" entries="选项4|选项5|选项6" spinnerMode="dialog"/>
</horizontal>
<button id="ok">确定</button>
<button id="select3">选择选项3</button>
</vertical>
);
ui.ok.on("click", ()=>{
var i = ui.sp1.getSelectedItemPosition();
var j = ui.sp2.getSelectedItemPosition();
toast("您的选择是选项" + (i + 1) + "和选项" + (j + 4));
});
ui.select3.on("click", ()=>{
ui.sp1.setSelection(2);
});
自定义控件-布局模板
"ui";
var InputLayout = (function() {
//继承至ui.Widget
util.extend(InputLayout, ui.Widget);
function InputLayout() {
ui.Widget.call(this);
this.defineAttr("hint", (view, attr, value, defineSetter)=>{
view._hint.setText(value);
});
this.defineAttr("text", (view, attr, value, defineSetter)=>{
view._input.setText(value);
});
}
InputLayout.prototype.render = function() {
return (
<vertical>
<text id="_hint" textSize="16sp" margin="4" textColor="gray"/>
<input id="_input" margin="0 16"/>
</vertical>
);
}
InputLayout.prototype.getInput = function() {
return this.view._input.getText();
};
ui.registerWidget("input-layout", InputLayout);
return InputLayout;
})();
ui.layout(
<vertical>
<input-layout id="name" hint="请输入名字"/>
<input-layout id="age" hint="请输入年龄" text="18"/>
<button id="ok" text="确认"/>
</vertical>
);
ui.ok.on("click", function(){
toast("名字是:" + ui.name.widget.getInput() + ", 年龄是:" + ui.age.widget.getInput());
});
自定义控件-带颜色按钮
"ui";
var ColoredButton = (function() {
//继承ui.Widget
util.extend(ColoredButton, ui.Widget);
function ColoredButton() {
//调用父类构造函数
ui.Widget.call(this);
//自定义属性color,定义按钮颜色
this.defineAttr("color", (view, name, defaultGetter) => {
return this._color;
}, (view, name, value, defaultSetter) => {
this._color = value;
view.attr("backgroundTint", value);
});
//自定义属性onClick,定义被点击时执行的代码
this.defineAttr("onClick", (view, name, defaultGetter) => {
return this._onClick;
}, (view, name, value, defaultSetter) => {
this._onClick = value;
});
}
ColoredButton.prototype.render = function() {
return (
<button textSize="16sp" style="Widget.AppCompat.Button.Colored" w="auto"/>
);
}
ColoredButton.prototype.onViewCreated = function(view) {
view.on("click", () => {
if (this._onClick) {
eval(this._onClick);
}
});
}
ui.registerWidget("colored-button", ColoredButton);
return ColoredButton;
})();
ui.layout(
<vertical>
<colored-button text="第一个按钮" color="#ff5722"/>
<colored-button text="第二个按钮" onClick="hello()"/>
</vertical>
);
function hello() {
alert("Hello ~");
}
自定义控件-模块-配置勾选框
//这个自定义控件是一个勾选框checkbox,能够保存自己的勾选状态,在脚本重新启动时能恢复状态
var PrefCheckBox = (function() {
//继承至ui.Widget
util.extend(PrefCheckBox, ui.Widget);
function PrefCheckBox() {
//调用父类构造函数
ui.Widget.call(this);
//自定义属性key,定义在配置中保存时的key
this.defineAttr("key");
}
PrefCheckBox.prototype.render = function() {
return (
<checkbox />
);
}
PrefCheckBox.prototype.onFinishInflation = function(view) {
view.setChecked(PrefCheckBox.getPref().get(this.getKey(), false));
view.on("check", (checked) => {
PrefCheckBox.getPref().put(this.getKey(), checked);
});
}
PrefCheckBox.prototype.getKey = function() {
if(this.key){
return this.key;
}
let id = this.view.attr("id");
if(!id){
throw new Error("should set a id or key to the checkbox");
}
return id.replace("@+id/", "");
}
PrefCheckBox.setPref = function(pref) {
PrefCheckBox._pref = pref;
}
PrefCheckBox.getPref = function(){
if(!PrefCheckBox._pref){
PrefCheckBox._pref = storages.create("pref");
}
return PrefCheckBox._pref;
}
ui.registerWidget("pref-checkbox", PrefCheckBox);
return PrefCheckBox;
})();
module.exports = PrefCheckBox;
自定义控件-使用配置勾选框
"ui";
var PrefCheckBox = require('./自定义控件-模块-配置勾选框.js');
ui.layout(
<vertical>
<pref-checkbox id="perf1" text="配置1"/>
<pref-checkbox id="perf2" text="配置2"/>
<button id="btn" text="获取配置"/>
</vertical>
);
ui.btn.on("click", function(){
toast("配置1为" + PrefCheckBox.getPref().get("perf1"));
toast("配置2为" + PrefCheckBox.getPref().get("perf2"));
});
本文转自 https://blog.csdn.net/qq_37952052/article/details/131625690?spm=1001.2014.3001.5502,如有侵权,请联系删除。
02_auto.js基础操作3/4
文章目录
- 02_auto.js基础操作3/4
- 控制台
- 保存日志
- 产生随机数
- 调整控制台大小位置
- 格式化输出
- 控制台示例
- 设置日志显示最大行数
- 修改控制台界面
- 终端模拟器
- 设备与设备信息
- 调整设备亮度
- 调整设备音量
- 获取设备信息
- 时间与按键、触摸监听
- 按键监听
- 触摸监听
- 通知监听
- 音量健控制程序
- 长按返回退出当前程序
- Toast监听
- 图片与图色处理
- 找图
- 找出所有图
- 找图并画出位置
- 获取网络图片并保存
- 截图并保存
- 精确找色
- 模糊找色
- 区域找色1
- 区域找色2
- 实时显示触摸点颜色
- 图片处理
- 颜色获取和检测
- 找到QQ红点位置
- 文件读写
- 读取文本文件
- 读写文本文件
- 删除所有空文件夹
- 文件编码转换
- 文件编码转换(高级)
- 写入文本文件
- 消息处理(加密、摘要、编码)
- 加密解密
- 消息摘要(MD5,SHA)
- base64编码
- 协程
- 协成HelloWorld
- ui中使用协成
- 悬浮窗
- 动态悬浮文字
- 护眼模式
- 悬浮窗输入框
- 悬浮窗运行脚本按钮简单版
- 悬浮文字
- 悬浮运行脚本按钮
控制台
保存日志
console.setGlobalLogConfig({
file: "/sdcard/log.txt"
});
console.log(1);
console.log(2);
console.error(3);
app.viewFile("/sdcard/log.txt");
产生随机数
console.show();
log("将产生5个1到100的随机数");
for(let i = 0; i < 5; i++){
print(random(1, 100));
print(" ");
sleep(400);
}
print("
");
log("将产生10个1到20的不重复随机数");
var exists = {};
for(let i = 0; i < 10; i++){
var r;
do{
r = random(1, 20);
}while(exists[r]);
exists[r] = true;
print(r + " ");
sleep(400);
}
调整控制台大小位置
console.show(true);
console.log("运行结束自动关闭");
console.log("调整大小...");
console.setSize(1000, 1000);
sleep(2000);
console.log("调整位置...");
console.setPosition(0, 500);
sleep(2000);
格式化输出
console.show();
var i = {
name: "小明",
age: 18,
height: 1.72
};
console.log("大家好, 我叫%s, 今年%d岁, 身高%d米", i.name, i.age, i.height);
console.log("实际上我是一个对象啦,长这样子: %j", i);
控制台示例
//显示控制台
console.show();
console.verbose("这是灰色");
console.log("这是黑色");
console.info("这是红色");
console.warn("这是蓝色");
console.error("这是绿色=_=");
hey();
function hey() {
console.trace("打印日志行数");
}
设置日志显示最大行数
console.show(false);
console.setMaxLines(10);
var i=0;
while(true){
console.log(i)
i++;
sleep(500);
}
修改控制台界面
function myrandom(min,max){
return Math.floor(Math.random() * (max - min + 1) ) + min;
}
threads.start(function () {
console.show();
console.setTitle("中文","#ff11ee00",30);
console.setCanInput(false);
var i=0;
do {
console.setLogSize(myrandom(4,20) );
console.setBackgroud("#33ef0000");
console.setCanInput(i%2==0);
i++;
console.log("i----->"+i);
sleep(3000);
} while (true);
});
终端模拟器
var sh = new Shell();
sh.setCallback({
onOutput: function(str){
print(str);
}
})
console.show();
do {
var cmd = console.rawInput();
sh.exec(cmd);
}while(cmd != "exit");
sh.exit();
设备与设备信息
调整设备亮度
"ui";
ui.layout(
<vertical padding="16">
<checkbox id="auto" text="自动亮度"/>
<text textColor="black" textSize="16sp" margin="8">亮度</text>
<seekbar id="brightness" max="100"/>
</vertical>
);
//getBrightnessMode()返回亮度模式,1为自动亮度
ui.auto.setChecked(device.getBrightnessMode() == 1);
ui.auto.setOnCheckedChangeListener(function(v, checked){
device.setBrightnessMode(checked ? 1: 0);
});
ui.brightness.setProgress(device.getBrightness());
ui.brightness.setOnSeekBarChangeListener({
onProgressChanged: function(seekbar, p, fromUser){
if(fromUser){
device.setBrightness(p);
}
}
});
调整设备音量
"ui";
ui.layout(
<vertical padding="16">
<text textColor="black" textSize="16sp">媒体音量</text>
<seekbar id="music"/>
<text textColor="black" textSize="16sp">通知音量</text>
<seekbar id="notification"/>
<text textColor="black" textSize="16sp">闹钟音量</text>
<seekbar id="alarm"/>
</vertical>
);
ui.music.setMax(device.getMusicMaxVolume());
ui.music.setProgress(device.getMusicVolume());
ui.music.setOnSeekBarChangeListener({
onProgressChanged: function(seekbar, p, fromUser){
if(fromUser){
device.setMusicVolume(p);
}
}
});
ui.notification.setMax(device.getNotificationMaxVolume());
ui.notification.setProgress(device.getAlarmVolume());
ui.notification.setOnSeekBarChangeListener({
onProgressChanged: function(seekbar, p, fromUser){
if(fromUser){
device.setNotificationVolume(p);
}
}
});
ui.alarm.setMax(device.getAlarmMaxVolume());
ui.alarm.setProgress(device.getAlarmVolume());
ui.alarm.setOnSeekBarChangeListener({
onProgressChanged: function(seekbar, p, fromUser){
if(fromUser){
device.setAlarmVolume(p);
}
}
});
获取设备信息
console.show();
var str = "";
str += "屏幕宽度:" + device.width;
str += "
屏幕高度:" + device.height;
str += "
buildId:" + device.buildId;
str += "
主板:" + device.board;
str += "
制造商:" + device.brand;
str += "
型号:" + device.model;
str += "
产品名称:" + device.product;
str += "
bootloader版本:" + device.bootloader;
str += "
硬件名称:" + device.hardware;
str += "
唯一标识码:" + device.fingerprint;
str += "
IMEI: " + device.getIMEI();
str += "
AndroidId: " + device.getAndroidId();
str += "
Mac: " + device.getMacAddress();
str += "
API: " + device.sdkInt;
str += "
电量: " + device.getBattery();
str += "
是否有虚拟导航: " + device.checkDeviceHasNavigationBar();
str += "
虚拟导航高度: " + device.getVirtualBarHeigh();
log(str);
时间与按键、触摸监听
按键监听
"auto";
events.observeKey();
var keyNames = {
"KEYCODE_VOLUME_UP": "音量上键",
"KEYCODE_VOLUME_DOWN": "音量下键",
"KEYCODE_HOME": "Home键",
"KEYCODE_BACK": "返回键",
"KEYCODE_MENU": "菜单键",
"KEYCODE_POWER": "电源键",
};
events.on("key", function(code, event){
var keyName = getKeyName(code, event);
if(event.getAction() == event.ACTION_DOWN){
toast(keyName + "被按下");
}else if(event.getAction() == event.ACTION_UP){
toast(keyName + "弹起");
}
});
loop();
function getKeyName(code, event){
var keyCodeStr = event.keyCodeToString(code);
var keyName = keyNames[keyCodeStr];
if(!keyName){
return keyCodeStr;
}
return keyName;
}
触摸监听
events.observeTouch();
events.setTouchEventTimeout(30);
toast("请在日志中查看触摸的点的坐标");
events.on("touch", function(point){
log(point);
});
loop();
通知监听
auto();
events.observeNotification();
events.onNotification(function(notification){
printNotification(notification);
});
toast("监听中,请在日志中查看记录的通知及其内容");
function printNotification(notification){
log("应用包名: " + notification.getPackageName());
log("通知文本: " + notification.getText());
log("通知优先级: " + notification.priority);
log("通知目录: " + notification.category);
log("通知时间: " + new Date(notification.when));
log("通知数: " + notification.number);
log("通知摘要: " + notification.tickerText);
}
音量健控制程序
"auto";
events.observeKey();
var interval = 5000;
var task = task1;
events.onKeyDown("volume_up", function(event){
if(task == task1){
task = task2;
}else{
task = task1;
}
toast("任务已切换");
});
events.onKeyDown("volume_down", function(event){
toast("程序结束");
exit();
});
task();
loop();
function task1(){
toast("任务1运行中,音量下键结束,音量上键切换任务");
setTimeout(task, interval);
}
function task2(){
toast("任务2运行中,音量下键结束,音量上键切换任务");
setTimeout(task, interval);
}
长按返回退出当前程序
"auto";
var 长按间隔 = 1500;
var curPackage = null;
var timeoutId = null;
events.observeKey();
events.onKeyDown("back", function(event){
curPackage = currentPackage();
timeoutId = setTimeout(function(){
backBackBackBack();
}, 长按间隔);
});
events.onKeyUp("back", function(event){
clearTimeout(timeoutId);
});
loop();
function backBackBackBack(){
while(curPackage == currentPackage()){
back();
sleep(200);
}
}
Toast监听
auto();
events.observeToast();
events.onToast(function(toast){
var pkg = toast.getPackageName();
log("Toast内容: " + toast.getText() +
" 来自: " + getAppName(pkg) +
" 包名: " + pkg);
});
toast("监听中,请在日志中查看记录的Toast及其内容");
图片与图色处理
找图
var superMario = images.read("./super_mario.jpg");
var mario = images.read("./mario.png");
var point = findImage(superMario, mario);
toastLog(point);
superMario.recycle();
mario.recycle();
找出所有图
var superMario = images.read("./super_mario.jpg");
var block = images.read("./block.png");
var result = images.matchTemplate(superMario, block, {
threshold: 0.8
}).matches;
toastLog(result);
superMario.recycle();
block.recycle();
找图并画出位置
var superMario = images.read("./super_mario.jpg");
var block = images.read("./block.png");
var points = images.matchTemplate(superMario, block, {
threshold: 0.8
}).points;
toastLog(points);
var canvas = new Canvas(superMario);
var paint = new Paint();
paint.setColor(colors.parseColor("#2196F3"));
points.forEach(point => {
canvas.drawRect(point.x, point.y, point.x + block.width, point.y + block.height, paint);
});
var image = canvas.toImage();
images.save(image, "/sdcard/tmp.png");
app.viewFile("/sdcard/tmp.png");
superMario.recycle();
block.recycle();
image.recycle();
获取网络图片并保存
//这个是Auto.js图标的地址
var url = "https://www.autojs.org/assets/uploads/profile/3-profileavatar.png";
var logo = images.load(url);
//保存到路径/sdcard/auto.js.png
images.save(logo, "/sdcard/auto.js.png");
截图并保存
if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
images.saveImage(img, "/sdcard/1.png");
精确找色
if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
//0x9966ff为编辑器紫色字体的颜色
toastLog("开始找色");
var point = findColor(img, 0x9966ff);
if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}
模糊找色
if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
//0x9966ff为编辑器紫色字体的颜色
toastLog("开始找色");
var point = findColor(img, 0x9966ff);
if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}
区域找色1
if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
toastLog("开始找色");
//指定在位置(100, 220)宽高为400*400的区域找色。
//#75438a是编辑器默认主题的棕红色字体(数字)颜色,位置大约在第5行的"2000",坐标大约为(283, 465)
var point = findColorInRegion(img, "#75438a", 90, 220, 900, 1000);
if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}
区域找色2
if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
//0xffffff为白色
toastLog("开始找色");
//指定在位置(90, 220)宽高为900*1000的区域找色。
//0xff00cc是编辑器的深粉红色字体(字符串)颜色
var point = findColor(img, "#ff00cc", {
region: [90, 220, 900, 1000],
threads: 8
});
if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}
实时显示触摸点颜色
requestScreenCapture();
console.show();
events.observeTouch();
events.setTouchEventTimeout(30);
events.on("touch", function(point){
var c = colors.toString(images.pixel(captureScreen(), point.x, point.y));
log("(" + point.x + ", " + point.y + "): " + c);
});
图片处理
"ui";
var url = "https://www.autojs.org/assets/uploads/files/1540386817060-918021-20160416200702191-185324559.jpg";
var logo = null;
var currentImg = null;
events.on("exit", function(){
if(logo != null){
logo.recycle();
}
if(currentImg != null){
currentImg.recycle();
}
});
ui.layout(
<vertical>
<img id="img" w="250" h="250" url="{{url}}" />
<scroll>
<vertical>
<button id="rotate" text="旋转" />
<button id="concat" text="拼接" />
<button id="grayscale" text="灰度化" />
<button id="binary" text="二值化" />
<button id="adaptiveBinary" text="自适应二值化" />
<button id="hsv" text="RGB转HSV" />
<button id="blur" text="模糊" />
<button id="medianBlur" text="中值滤波" />
<button id="gaussianBlur" text="高斯模糊" />
</vertical>
</scroll>
</vertical>
);
//把一张图片设置到图片控件中
function setImage(img) {
ui.run(() => {
ui.img.setImageBitmap(img.bitmap);
var oldImg = currentImg;
//不能立即回收currentImg,因为此时img控件还在使用它,应该在下次消息循环再回收它
ui.post(()=>{
if(oldImg != null){
oldImg.recycle();
}
});
currentImg = img;
});
}
//启动一个处理图片的线程
var imgProcess = threads.start(function () {
setInterval(() => { }, 1000);
});
//处理图片的函数,把任务交给图片处理线程处理
function processImg(process) {
imgProcess.setTimeout(() => {
if (logo == null) {
logo = images.load(url);
}
//处理图片
var result = process(logo);
//把处理后的图片设置到图片控件中
setImage(result);
}, 0);
}
var degress = 0;
ui.rotate.on("click", () => {
processImg(img => {
degress += 90;
//旋转degress角度
return images.rotate(img, degress);
});
});
ui.concat.on("click", () => {
processImg(img => {
if(currentImg == null){
toast("请先点击其他按钮,再点击本按钮");
return img.clone();
}
//把currentImg拼接在img右边
return images.concat(img, currentImg, "right");
});
});
ui.grayscale.on("click", () => {
processImg(img => {
//灰度化
return images.grayscale(img);
});
});
ui.binary.on("click", () => {
processImg(img => {
var g = images.grayscale(img);
//二值化,取灰度为30到200之间的图片
var result = images.threshold(g, 100, 200);
g.recycle();
return result;
});
});
ui.adaptiveBinary.on("click", () => {
processImg(img => {
var g = images.grayscale(img);
//自适应二值化,最大值为200,块大小为25
var result = images.adaptiveThreshold(g, 200, "MEAN_C", "BINARY", 25, 10);
g.recycle();
return result;
});
});
ui.hsv.on("click", () => {
processImg(img => {
//RGB转HSV
return images.cvtColor(img, "BGR2HSV");
});
});
ui.blur.on("click", () => {
processImg(img => {
//模糊
return images.blur(img, [10, 10]);
});
});
ui.medianBlur.on("click", () => {
processImg(img => {
//中值滤波
return images.medianBlur(img, 5);
});
});
ui.gaussianBlur.on("click", () => {
processImg(img => {
//高斯模糊
return images.gaussianBlur(img, [5, 5]);
});
});
颜色获取和检测
if(!requestScreenCapture()){
toast("请求截图失败");
exit
}
sleep(2000);
var x = 760;
var y = 180;
//获取在点(x, y)处的颜色
var c = images.pixel(captureScreen(), x, y);
//显示该颜色
var msg = "";
msg += "在位置(" + x + ", " + y + ")处的颜色为" + colors.toString(c);
msg += "
R = " + colors.red(c) + ", G = " + colors.green(c) + ", B = " + colors.blue(c);
//检测在点(x, y)处是否有颜色#73bdb6 (模糊比较)
var isDetected = images.detectsColor(captureScreen(), "#73bdb6", x, y);
msg += "
该位置是否匹配到颜色#73bdb6: " + isDetected;
alert(msg);
找到QQ红点位置
if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
launchApp("QQ");
sleep(2000);
var img = captureScreen();
toastLog("开始找色");
var point = findColor(img, "#f64d30");
if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}
文件读写
读取文本文件
//文件路径
var path = "/sdcard/1.txt";
//打开文件
var file = open(path);
//读取文件的所有内容
var text = file.read();
//打印到控制台
print(text);
//关闭文件
file.close();
console.show();
读写文本文件
//以写入模式打开SD卡根目录文件1.txt
var file = open("/sdcard/1.txt", "w")
//写入aaaa
file.write("aaaa");
//写入bbbbb后换行
file.writeline("bbbbb");
//写入ccc与ddd两行
file.writelines(["ccc", "ddd"]);
//关闭文件
file.close();
//以附加模式打开文件
file = open("/sdcard/1.txt", "a");
//附加一行"啦啦啦啦"
file.writeline("啦啦啦啦");
//附加一行"哈哈哈哈"
file.writeline("哈哈哈哈");
//附加两行ccc, ddd
file.writelines(["ccc", "ddd"]);
//输出缓冲区
file.flush();
//关闭文件
file.close();
//以读取模式打开文件
file = open("/sdcard/test.txt", "r")
//读取一行并打印
print(file.readline());
//读取剩余所有行并打印
for each(line in file.readlines()){
print(line)
}
file.close()
//显示控制台
console.show()
删除所有空文件夹
if(confirm("该操作会删除SD卡目录及其子目录下所有空文件夹,是否继续?")){
toast("请点击右上角打开日志");
deleteAllEmptyDirs(files.getSdcardPath());
toast("全部完成!");
}
function deleteAllEmptyDirs(dir){
var list = files.listDir(dir);
var len = list.length;
if(len == 0){
log("删除目录 " + dir + " " + (files.remove(dir) ? "成功" : "失败"));
return;
}
for(let i = 0; i < len; i++){
var child = files.join(dir, list[i]);
if(files.isDir(child)){
deleteAllEmptyDirs(child);
}
}
}
文件编码转换
//以UTF-8编码打开SD卡上的1.txt文件
var f = open("/sdcard/1.txt", "r", "utf-8");
//读取文件所有内容
var text = f.read();
//关闭文件
f.close();
//以gbk编码打开SD卡上的2.txt文件
var out = open("/sdcard/2.txt", "w", "gbk");
//写入内容
out.write(text);
//关闭文件
out.close();
文件编码转换(高级)
convert("/sdcard/1.txt", "utf-8", "/sdcard/2.txt", "gbk");
/**
* fromFile: 源文件路径
* fromEncoding: 源文件编码
* toFile: 输出文件路径
* toEncoding: 输出文件编码
*/
function convert(fromFile, fromEncoding, toFile, toEncoding){
fromFile = open(fromFile, "r", fromEncoding);
toFile = open(toFile, "w", toEncoding);
while(true){
var line = fromFile.readline();
if(!line)
break;
toFile.writeline(line);
}
}
写入文本文件
//文件路径
var path = "/sdcard/1.txt";
//要写入的文件内容
var text = "Hello, AutoJs";
//以写入模式打开文件
var file = open(path, "w");
//写入文件
file.write(text);
//关闭文件
file.close();
消息处理(加密、摘要、编码)
加密解密
let message = "未加密字符串";
log("明文: ", message);
// 密钥,由于AES等算法要求是16位的倍数,我们这里用一个16位的密钥
let key = new $crypto.Key("password12345678");
log("密钥: ", key);
// AES加密
let aes = $crypto.encrypt(message, key, "AES/ECB/PKCS5padding");
log("AES加密后二进制数据: ", aes);
log("AES解密: ", $crypto.decrypt(aes, key, "AES/ECB/PKCS5padding", {output: 'string'}));
// RSA加密
// 生成RSA密钥
let keyPair = $crypto.generateKeyPair("RSA");
log("密钥对: ", keyPair);
// 使用私钥加密
let rsa = $crypto.encrypt(message, keyPair.privateKey, "RSA/ECB/PKCS1padding");
log("RSA私钥加密后二进制数据: ", rsa);
// 使用公钥解密
log("RSA公钥解密: ", $crypto.decrypt(rsa, keyPair.publicKey, "RSA/ECB/PKCS1padding", {output: 'string'}));
消息摘要(MD5,SHA)
// 字符串消息摘要
let message = "Hello, Autox.js";
// 输出各种消息摘要算法结果的hex值
log("字符串: ", message);
log("MD5: ", $crypto.digest(message, "MD5"));
log("SHA1: ", $crypto.digest(message, "SHA-1"));
log("SHA256: ", $crypto.digest(message, "SHA-256"));
// 输出各种消息摘要算法结果的base64值
log("MD5 [base64]: ", $crypto.digest(message, "MD5", {output: 'base64'}));
log("SHA1 [base64]: ", $crypto.digest(message, "SHA-1", {output: 'base64'}));
log("SHA256 [base64]: ", $crypto.digest(message, "SHA-256", {output: 'base64'}));
// 文件消息摘要
let file = "/sdcard/脚本/_test_for_message_digest.js"
// 写入文件内容,提供为后续计算MD5等
$files.write(file, "Test!");
log("文件: ", file);
log("MD5: ", $crypto.digest(file, "MD5", {input: 'file'}));
log("SHA1: ", $crypto.digest(file, "SHA-1", {input: 'file'}));
log("SHA256: ", $crypto.digest(file, "SHA-256", {input: 'file'}));
base64编码
let message = "autox.js";
log("明文: ", message);
let base64encode = $base64.encode(message);
log("Base64编码: ", base64encode);
let message2 = "YXV0b3guanM=";
log("明文2: ", message2);
let base64decode = $base64.decode(message2);
log("Base64解码: ", base64decode);
协程
协成HelloWorld
// 注意,要使用协程这个特性,必须使用项目功能,并且在project.json配置好features属性
// delay不同于sleep,不会阻塞当前线程
function delay(millis) {
var cont = continuation.create();
setTimeout(()=>{
cont.resume();
}, millis);
cont.await();
}
// 异步IO例子,在另一个线程读取文件,读取完成后返回当前线程继续执行
function read(path) {
var cont = continuation.create();
threads.start(function(){
try {
cont.resume(files.read(path));
}catch(err){
cont.resumeError(err);
}
});
return cont.await();
}
// 使用Promise和协程的例子
function add(a, b) {
return new Promise(function(resolve, reject) {
var sum = a + b;
resolve(sum);
});
}
toastLog("Hello, Continuation!");
//3秒后发出提示
setTimeout(()=>{
toastLog("3秒后....");
}, 3000);
// 你可以尝试把delay更换成sleep,看会发生什么!
delay(6000);
toastLog("6秒后...");
try {
toastLog("读取文件hello.txt: " + read("./hello.txt"));
}catch(err){
console.error(err);
}
var sum = add(1, 2).await();
toastLog("1 + 2 = " + sum);
// project.json
{
"name": "协程HelloWorld",
"main": "main.js",
"ignore": [
"build"
],
"packageName": "com.example.cont.helloworld",
"versionName": "1.0.0",
"versionCode": 1,
"useFeatures": ["continuation"]
}
ui中使用协成
"ui";
ui.layout(
<frame bg="#4fc3f7">
<text textColor="white" textSize="18sp" layout_gravity="center">
UI中使用协程
</text>
</frame>
);
continuation.delay(5000);
if (!requestScreenCapture()) {
dialogs.alert("请授予软件截图权限").await();
}
// 退出应用对话框
ui.emitter.on("back_pressed", function (e) {
e.consumed = true;
let exit = dialogs.confirm("确定要退出程序").await();
if (exit) {
ui.finish();
}
});
// project.json
{
"name": "协程UI示例",
"main": "main.js",
"ignore": [
"build"
],
"packageName": "com.example.cont.ui",
"versionName": "1.0.0",
"versionCode": 1,
"useFeatures": ["continuation"]
}
悬浮窗
动态悬浮文字
var window = floaty.window(
<frame gravity="center">
<text id="text" textSize="16sp" textColor="#f44336"/>
</frame>
);
window.exitOnClose();
window.text.click(()=>{
window.setAdjustEnabled(!window.isAdjustEnabled());
});
setInterval(()=>{
//对控件的操作需要在UI线程中执行
ui.run(function(){
window.text.setText(dynamicText());
});
}, 1000);
function dynamicText(){
var date = new Date();
var str = util.format("时间: %d:%d:%d
", date.getHours(), date.getMinutes(), date.getSeconds());
str += util.format("内存使用量: %d%%
", getMemoryUsage());
str += "当前活动: " + currentActivity() + "
";
str += "当前包名: " + currentPackage();
return str;
}
//获取内存使用率
function getMemoryUsage(){
var usage = (100 * device.getAvailMem() / device.getTotalMem());
//保留一位小数
return Math.round(usage * 10) / 10;
}
护眼模式
var w = floaty.rawWindow(
<frame gravity="center" bg="#44ffcc00"/>
);
w.setSize(-1, -1);
w.setTouchable(false);
setTimeout(()=>{
w.close();
}, 60000);
悬浮窗输入框
var window = floaty.window(
<vertical>
<input id="input" text="请输入你的名字" textSize="16sp" focusable="true"/>
<button id="ok" text="确定"/>
</vertical>
);
window.exitOnClose();
toast("长按确定键可调整位置");
window.input.on("key", function(keyCode, event){
if(event.getAction() == event.ACTION_DOWN && keyCode == keys.back){
window.disableFocus();
event.consumed = true;
}
});
window.input.on("touch_down", ()=>{
window.requestFocus();
window.input.requestFocus();
});
window.ok.on("click", ()=>{
toast("傻瓜! " + window.input.text());
window.disableFocus();
});
window.ok.on("long_click", ()=>{
window.setAdjustEnabled(!window.isAdjustEnabled());
});
setInterval(()=>{}, 1000);
悬浮窗运行脚本按钮简单版
var path = "/sdcard/脚本/test.js";
if(!files.exists(path)){
toast("脚本文件不存在: " + path);
exit();
}
var window = floaty.window(
<frame>
<button id="action" text="开始运行" w="90" h="40" bg="#77ffffff"/>
</frame>
);
window.exitOnClose();
var execution = null;
window.action.click(()=>{
if(window.action.getText() == '开始运行'){
execution = engines.execScriptFile(path);
window.action.setText('停止运行');
}else{
if(execution){
execution.getEngine().forceStop();
}
window.action.setText('开始运行');
}
});
window.action.longClick(()=>{
window.setAdjustEnabled(!window.isAdjustEnabled());
return true;
});
setInterval(()=>{}, 1000);
悬浮文字
var window = floaty.window(
<frame gravity="center">
<text id="text" text="点击可调整位置" textSize="16sp"/>
</frame>
);
window.exitOnClose();
window.text.click(()=>{
window.setAdjustEnabled(!window.isAdjustEnabled());
});
setInterval(()=>{}, 1000);
悬浮运行脚本按钮
var path = "/sdcard/脚本/test.js";
if(!files.exists(path)){
toast("脚本文件不存在: " + path);
exit();
}
var window = floaty.window(
<frame>
<button id="action" text="开始运行" w="90" h="40" bg="#77ffffff"/>
</frame>
);
setInterval(()=>{}, 1000);
var execution = null;
//记录按键被按下时的触摸坐标
var x = 0, y = 0;
//记录按键被按下时的悬浮窗位置
var windowX, windowY;
//记录按键被按下的时间以便判断长按等动作
var downTime;
window.action.setOnTouchListener(function(view, event){
switch(event.getAction()){
case event.ACTION_DOWN:
x = event.getRawX();
y = event.getRawY();
windowX = window.getX();
windowY = window.getY();
downTime = new Date().getTime();
return true;
case event.ACTION_MOVE:
//移动手指时调整悬浮窗位置
window.setPosition(windowX + (event.getRawX() - x),
windowY + (event.getRawY() - y));
//如果按下的时间超过1.5秒判断为长按,退出脚本
if(new Date().getTime() - downTime > 1500){
exit();
}
return true;
case event.ACTION_UP:
//手指弹起时如果偏移很小则判断为点击
if(Math.abs(event.getRawY() - y) < 5 && Math.abs(event.getRawX() - x) < 5){
onClick();
}
return true;
}
return true;
});
function onClick(){
if(window.action.getText() == '开始运行'){
execution = engines.execScriptFile(path);
window.action.setText('停止运行');
}else{
if(execution){
execution.getEngine().forceStop();
}
window.action.setText('开始运行');
}
}
本文转自 https://blog.csdn.net/qq_37952052/article/details/131743472?spm=1001.2014.3001.5502,如有侵权,请联系删除。
02_auto.js基础操作4/4
文章目录
- 02_auto.js基础操作4/4
- 应用
- 打开应用
- 发送意图-文本消息分享
- 强制停止应用
- 卸载应用
- 应用工具
- GoogleMLkit
- OCR识别
- OCR截图识别
- OCR识别点击
- HTTP网络请求
- 获取网页
- 文件上传
- 文件下载
- javascript
- 数字
- E4X
- HelloWorld
- PaddleOCR
- PaddleOCR文本识别
- PaddleOCR文本识别-自定义模型路径
- PaddleOCR-截图识别
- Shell命令
- 冻结网易云音乐
- 结束所有后台进程
- 解冻并打开网易云音乐
- 锁屏
- TessractOCR
- Web扩展与游戏编程
- 贪吃蛇
- 贪吃蛇重力版
- AutoX注入webviwe
- WebSocket
- 创建客户端
- WebSocket示例
应用
打开应用
var appName = rawInput("请输入应用名称");
launchApp(appName);
发送意图-文本消息分享
var content = rawInput('请输入要分享的文本');
app.startActivity({
action: "android.intent.action.SEND",
type: "text/*",
extras: {
"android.intent.extra.TEXT": content
},
packageName: "com.tencent.mobileqq",
className: "com.tencent.mobileqq.activity.JumpActivity"
});
强制停止应用
"auto";
var appName = rawInput("请输入应用名称");
openAppSetting(getPackageName(appName));
while(!click("强制停止"));
卸载应用
//输入应用名称
var appName = rawInput('请输入要卸载的应用名称');
//获取应用包名
var packageName = getPackageName(appName);
if(!packageName){
toast("应用不存在!");
}else{
//卸载应用
app.uninstall(packageName);
}
应用工具
var i = dialogs.select("请选择工具", "获取应用包名", "打开应用详情页", "卸载应用");
if(i == -1){
alert("没有选择任何工具!");
}
switch(i){
case 0:
//获取应用包名
appName = rawInput("请输入应用名称", "QQ");
packageName = getPackageName(appName);
toast(packageName);
setClip(packageName);
toast("已复制到剪贴板");
break;
case 1:
//打开应用详情页
appName = rawInput("请输入应用名称", "微信");
openAppSetting(getPackageName(appName));
break;
case 2:
//卸载应用
appName = rawInput("请输入应用名称");
packageName = getPackageName(appName);
if(packageName == ""){
toast("应用不存在");
}else if(confirm("确定卸载应用" + packageName + "吗?")){
app.uninstall(packageName);
}
break;
}
GoogleMLkit
OCR识别
let img = images.read("./1.png")
let start = new Date()
// 识别图片中的文字,返回完整识别信息(兼容百度OCR格式)。
//可选语言:拉丁 "la" , 中文 "zh" ,梵文 "sa" ,日语 "ja" , 韩语 "ko"
let result = gmlkit.ocr(img, "zh")
log('OCR识别耗时:' + (new Date() - start) + 'ms')
//排序 sort()会改变原对象,sorted() 不会改变原对象,而是返回新对象
result.sort()
//或者
//let newResult = result.sorted()
log("识别信息: " + result)
log("-------------------------------------------")
log("文本识别信息: " + result.text)
log("-------------------------------------------")
toastLog("json识别信息: " + JSON.stringify(result))
// 回收图片
img.recycle()
// project.json
{
"abis": [
"arm64-v8a",
"armeabi-v7a",
"x86",
"x86_64"
],
"assets": [
{
"form": "file:///android_asset/mlkit-google-ocr-models",
"to": "/mlkit-google-ocr-models"
}
],
"buildDir": "build",
"build": {
"build_id": null,
"build_number": 0,
"build_time": 0
},
"useFeatures": [],
"icon": null,
"ignoredDirs": [],
"launchConfig": {
"displaySplash": false,
"hideLauncher": false,
"hideLogs": false,
"stableMode": false,
"volumeUpcontrol": false,
"permissions": [],
"serviceDesc": "使脚本自动操作(点击、长按、滑动等)所需,若关闭则只能执行不涉及自动操作的脚本。",
"splashIcon": null,
"splashText": "Powered by Google ML Kit ocr"
},
"libs": [
"libmlkit_google_ocr_pipeline.so",
"libjackpal-androidterm5.so",
"libjackpal-termexec2.so"
],
"main": "main.js",
"name": "Google MlKitOCR",
"outputPath": null,
"packageName": "com.script.gmlkitocr",
"scripts": {},
"signingConfig": {
"alias": null,
"keystore": null
},
"sourcePath": null,
"versionCode": 1,
"versionName": "1.0.0"
}
OCR截图识别
let currentEngine = engines.myEngine()
let runningEngines = engines.all()
let currentSource = currentEngine.getSource() + ''
if (runningEngines.length > 1) {
runningEngines.forEach(compareEngine => {
let compareSource = compareEngine.getSource() + ''
if (currentEngine.id !== compareEngine.id && compareSource === currentSource) {
// 强制关闭同名的脚本
compareEngine.forceStop()
}
})
}
if (!requestScreenCapture()) {
toastLog('请求截图权限失败')
exit()
}
sleep(1000)
// 识别结果和截图信息
let result = []
let img = null
let running = true
let capturing = true
/**
* 截图并识别OCR文本信息
*/
function captureAndOcr() {
capturing = true
img && img.recycle()
img = captureScreen()
if (!img) {
toastLog('截图失败')
}
let start = new Date()
//结果转数组:层级:3
result = gmlkit.ocr(img,"zh").toArray(3);
log(result);
toastLog('耗时' + (new Date() - start) + 'ms')
capturing = false
}
captureAndOcr()
// 获取状态栏高度
let offset = -getStatusBarHeightCompat()
//let offset = 0;
// 绘制识别结果
let window = floaty.rawWindow(
<canvas id="canvas" layout_weight="1" />
);
// 设置悬浮窗位置
ui.post(() => {
window.setPosition(0, offset)
window.setSize(device.width, device.height)
window.setTouchable(false)
})
// 操作按钮
let clickButtonWindow = floaty.rawWindow(
<vertical>
<button id="captureAndOcr" text="截图识别" />
<button id="closeBtn" text="退出" />
</vertical>
);
ui.run(function () {
clickButtonWindow.setPosition(device.width / 2 - ~~(clickButtonWindow.getWidth() / 2), device.height * 0.65)
})
// 点击识别
clickButtonWindow.captureAndOcr.click(function () {
result = []
ui.run(function () {
clickButtonWindow.setPosition(device.width, device.height)
})
setTimeout(() => {
threads.start(()=>{
captureAndOcr()
ui.run(function () {
clickButtonWindow.setPosition(device.width / 2 - ~~(clickButtonWindow.getWidth() / 2), device.height * 0.65)
})
})
}, 500)
})
// 点击关闭
clickButtonWindow.closeBtn.click(function () {
exit()
})
let Typeface = android.graphics.Typeface
let paint = new Paint()
paint.setStrokeWidth(1)
paint.setTypeface(Typeface.DEFAULT_BOLD)
paint.setTextAlign(Paint.Align.LEFT)
paint.setAntiAlias(true)
paint.setStrokeJoin(Paint.Join.ROUND)
paint.setDither(true)
window.canvas.on('draw', function (canvas) {
if (!running || capturing) {
return
}
// 清空内容
canvas.drawColor(0xFFFFFF, android.graphics.PorterDuff.Mode.CLEAR)
if (result && result.length > 0) {
for (let i = 0; i < result.length; i++) {
let ocrResult = result[i]
drawRectAndText(ocrResult.text + ' #信心:' + ocrResult.confidence.toFixed(2), ocrResult.bounds, '#00ff00', canvas, paint);
}
}
})
setInterval(() => { }, 10000)
events.on('exit', () => {
// 标记停止 避免canvas导致闪退
running = false
// 回收图片
img && img.recycle()
// 撤销监听
window.canvas.removeAllListeners()
})
/**
* 绘制文本和方框
*
* @param {*} desc
* @param {*} rect
* @param {*} colorStr
* @param {*} canvas
* @param {*} paint
*/
function drawRectAndText (desc, rect, colorStr, canvas, paint) {
let color = colors.parseColor(colorStr)
paint.setStrokeWidth(1)
paint.setStyle(Paint.Style.STROKE)
// 反色
paint.setARGB(255, 255 - (color >> 16 & 0xff), 255 - (color >> 8 & 0xff), 255 - (color & 0xff))
canvas.drawRect(rect, paint)
paint.setARGB(255, color >> 16 & 0xff, color >> 8 & 0xff, color & 0xff)
paint.setStrokeWidth(1)
paint.setTextSize(20)
paint.setStyle(Paint.Style.FILL)
canvas.drawText(desc, rect.left, rect.top, paint)
paint.setTextSize(10)
paint.setStrokeWidth(1)
paint.setARGB(255, 0, 0, 0)
}
/**
* 获取状态栏高度
*
* @returns
*/
function getStatusBarHeightCompat () {
let result = 0
let resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android")
if (resId > 0) {
result = context.getResources().getDimensionPixelOffset(resId)
}
if (result <= 0) {
result = context.getResources().getDimensionPixelOffset(R.dimen.dimen_25dp)
}
return result
}
OCR识别点击
//requestScreenCapture()
var mainActivity = "org.autojs.autojs.ui.main.MainActivity"
if (currentActivity != mainActivity) {
app.startActivity({
packageName: "org.autojs.autoxjs.v6",
className: mainActivity,
});
waitForActivity(mainActivity)
}
requestScreenCapture()
sleep(1000)
let img = captureScreen()
let start = new Date()
let result = gmlkit.ocr(img, "zh")
toastLog('OCR识别耗时:' + (new Date() - start) + 'ms')
let managerBtn = result.find(3, e => e.text == "管理")
if (managerBtn) click(managerBtn.bounds)
sleep(500)
let homeBtn = result.find(3, e => e.text == "主页")
if (homeBtn) click(homeBtn.bounds)
sleep(500)
let docBtn = result.find(3, e => e.text == "文档")
if (docBtn) press(docBtn.bounds, 500)
// 回收图片
img.recycle()
HTTP网络请求
获取网页
var url = "www.baidu.com";
var res = http.get(url);
if(res.statusCode == 200){
toast("请求成功");
console.show();
log(res.body.string());
}else{
toast("请求失败:" + res.statusMessage);
}
文件上传
//如果遇到SocketTimeout的异常,重新多运行几次脚本即可
console.show();
example1();
example2();
example3();
example4();
example5();
function example1(){
var res = http.postMultipart("http://posttestserver.com/post.php", {
"file": open("/sdcard/1.txt")
});
log("例子1:");
log(res.body.string());
}
function example2(){
var res = http.postMultipart("http://posttestserver.com/post.php", {
"file": ["1.txt", "/sdcard/1.txt"]
});
log("例子2:");
log(res.body.string());
}
function example3(){
var res = http.postMultipart("http://posttestserver.com/post.php", {
"file": ["1.txt", "text/plain", "/sdcard/1.txt"]
});
log("例子3:");
log(res.body.string());
}
function example4(){
var res = http.postMultipart("http://posttestserver.com/post.php", {
"file": open("/sdcard/1.txt"),
"aKey": "aValue"
});
log("例子4:");
log(res.body.string());
}
文件下载
var url = "http://www.autojs.org/assets/uploads/profile/3-profileavatar.png";
var res = http.get(url);
if(res.statusCode != 200){
toast("请求失败");
}
files.writeBytes("/sdcard/1.png", res.body.bytes());
toast("下载成功");
app.viewFile("/sdcard/1.png");
javascript
数字
a = 5;
b = 6;
c = -1;
x = 1.5;
y = a * x * x + b * x * c;
log("y = " + y);
openConsole();
E4X
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
print("----------------------------------------");
// Use the XML constructor to parse an string into an XML object
var John = "<employee><name>John</name><age>25</age></employee>";
var Sue ="<employee><name>Sue</name><age>32</age></employee>";
var tagName = "employees";
var employees = new XML("<" + tagName +">" + John + Sue + "</" + tagName +">");
print("The employees XML object constructed from a string is:
" + employees);
print("----------------------------------------");
// Use an XML literal to create an XML object
var order = <order>
<customer>
<firstname>John</firstname>
<lastname>Doe</lastname>
</customer>
<item>
<description>Big Screen Television</description>
<price>1299.99</price>
<quantity>1</quantity>
</item>
</order>
// Construct the full customer name
var name = order.customer.firstname + " " + order.customer.lastname;
// Calculate the total price
var total = order.item.price * order.item.quantity;
print("The order XML object constructed using a literal is:
" + order);
print("The total price of " + name + "'s order is " + total);
print("----------------------------------------");
// construct a new XML object using expando and super-expando properties
var order = <order/>;
order.customer.name = "Fred Jones";
order.customer.address.street = "123 Long Lang";
order.customer.address.city = "Underwood";
order.customer.address.state = "CA";
order.item[0] = "";
order.item[0].description = "Small Rodents";
order.item[0].quantity = 10;
order.item[0].price = 6.95;
print("The order custructed using expandos and super-expandos is:
" + order);
// append a new item to the order
order.item += <item><description>Catapult</description><price>139.95</price></item>;
print("----------------------------------------");
print("The order after appending a new item is:
" + order);
print("----------------------------------------");
// dynamically construct an XML element using embedded expressions
var tagname = "name";
var attributename = "id";
var attributevalue = 5;
var content = "Fred";
var x = <{tagname} {attributename}={attributevalue}>{content}</{tagname}>;
print("The dynamically computed element value is:
" + x.toXMLString());
print("----------------------------------------");
// Create a SOAP message
var message = <soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<soap:Body>
<m:GetLastTradePrice xmlns:m="http://mycompany.com/stocks">
<symbol>DIS</symbol>
</m:GetLastTradePrice>
</soap:Body>
</soap:Envelope>
// declare the SOAP and stocks namespaces
var soap = new Namespace("http://schemas.xmlsoap.org/soap/envelope/");
var stock = new Namespace ("http://mycompany.com/stocks");
// extract the soap encoding style and body from the soap message
var encodingStyle = message.@soap::encodingStyle;
print("The encoding style of the soap message is specified by:
" + encodingStyle);
// change the stock symbol
message.soap::Body.stock::GetLastTradePrice.symbol = "MYCO";
var body = message.soap::Body;
print("The body of the soap message is:
" + body);
print("----------------------------------------");
// create an manipulate an XML object using the default xml namespace
default xml namespace = "http://default.namespace.com";
var x = <x/>;
x.a = "one";
x.b = "two";
x.c = <c xmlns="http://some.other.namespace.com">three</c>;
print("XML object constructed using the default xml namespace:
" + x);
default xml namespace="";
print("----------------------------------------");
var order = <order id = "123456" timestamp="Mon Mar 10 2003 16:03:25 GMT-0800 (PST)">
<customer>
<firstname>John</firstname>
<lastname>Doe</lastname>
</customer>
<item id="3456">
<description>Big Screen Television</description>
<price>1299.99</price>
<quantity>1</quantity>
</item>
<item id = "56789">
<description>DVD Player</description>
<price>399.99</price>
<quantity>1</quantity>
</item>
</order>;
// get the customer element from the orderprint("The customer is:
" + order.customer);
// get the id attribute from the order
print("The order id is:" + order.@id);
// get all the child elements from the order element
print("The children of the order are:
" + order.*);
// get the list of all item descriptions
print("The order descriptions are:
" + order.item.description);
// get second item by numeric index
print("The second item is:
" + order.item[1]);
// get the list of all child elements in all item elements
print("The children of the items are:
" + order.item.*);
// get the second child element from the order by index
print("The second child of the order is:
" + order.*[1]);
// calculate the total price of the order
var totalprice = 0;
for each (i in order.item) {
totalprice += i.price * i.quantity;
}
print("The total price of the order is: " + totalprice);
print("----------------------------------------");
var e = <employees>
<employee id="1"><name>Joe</name><age>20</age></employee>
<employee id="2"><name>Sue</name><age>30</age></employee>
</employees>;
// get all the names in e
print("All the employee names are:
" + e..name);
// employees with name Joe
print("The employee named Joe is:
" + e.employee.(name == "Joe"));
// employees with id's 1 & 2
print("Employees with ids 1 & 2:
" + e.employee.(@id == 1 || @id == 2));
// name of employee with id 1
print("Name of the the employee with ID=1: " + e.employee.(@id == 1).name);
print("----------------------------------------");
openConsole();
HelloWorld
log("Hello world!!!");
toast("Hello, AutoJs!");
console.show();
PaddleOCR
PaddleOCR文本识别
let img = images.read("./0.jpg")
// PaddleOCR 移动端提供了两种模型:ocr_v2_for_cpu与ocr_v2_for_cpu(slim),此选项用于选择加载的模型,默认true使用v2的slim版(速度更快),false使用v2的普通版(准确率更高)
let useSlim = true
let start = new Date()
// 识别图片中的文字,返回完整识别信息(兼容百度OCR格式)。
let result = paddle.ocr(img, useSlim)
log('OCR识别耗时:' + (new Date() - start) + 'ms')
// 可以使用简化的调用命令,默认参数:cpuThreadNum = 4, useSlim = true
// const result = paddle.ocr(img)
toastLog("完整识别信息: " + JSON.stringify(result))
start = new Date()
// 识别图片中的文字,只返回文本识别信息(字符串列表)。当前版本可能存在文字顺序错乱的问题 建议先使用detect后自行排序
const stringList = paddle.ocrText(img, useSlim)
log('OCR纯文本识别耗时:' + (new Date() - start) + 'ms')
// 可以使用简化的调用命令,默认参数:cpuThreadNum = 4, useSlim = true
// const stringList = paddle.ocrText(img)
toastLog("文本识别信息: " + JSON.stringify(stringList))
// 回收图片
img.recycle()
// 释放native内存,非必要,供万一出现内存泄露时使用
// paddle.release()
// project.json
{
"abis": [
"arm64-v8a",
"armeabi-v7a",
"x86",
"x86_64"
],
"assets": [
{
"form": "file:///android_asset/models",
"to": "/models"
}
],
"buildDir": "build",
"build": {
"build_id": null,
"build_number": 0,
"build_time": 0
},
"useFeatures": [],
"icon": null,
"ignoredDirs": [],
"launchConfig": {
"displaySplash": false,
"hideLauncher": false,
"hideLogs": false,
"stableMode": false,
"volumeUpcontrol": false,
"permissions": [],
"serviceDesc": "使脚本自动操作(点击、长按、滑动等)所需,若关闭则只能执行不涉及自动操作的脚本。",
"splashIcon": null,
"splashText": "Powered by paddle ocr"
},
"libs": [
"libc++_shared.so",
"libpaddle_light_api_shared.so",
"libhiai.so",
"libhiai_ir.so",
"libhiai_ir_build.so",
"libNative.so",
"libjackpal-androidterm5.so",
"libjackpal-termexec2.so"
],
"main": "PaddleOCR.js",
"name": "PaddleOCR",
"outputPath": null,
"packageName": "com.script.paddleocr",
"scripts": {},
"signingConfig": {
"alias": null,
"keystore": null
},
"sourcePath": null,
"versionCode": 1,
"versionName": "1.0.0"
}
PaddleOCR文本识别-自定义模型路径
let img = images.read("./0.jpg")
// 新增:自定义模型路径(必须是绝对路径), files.path() 将相对路径转为绝对路径
let myModelPath = files.path("./models");
let start = new Date()
// 识别图片中的文字,返回完整识别信息(兼容百度OCR格式)。
let result = paddle.ocr(img, myModelPath)
log('OCR识别耗时:' + (new Date() - start) + 'ms')
toastLog("完整识别信息: " + JSON.stringify(result))
start = new Date()
// 识别图片中的文字,只返回文本识别信息(字符串列表)。当前版本可能存在文字顺序错乱的问题 建议先使用detect后自行排序
const stringList = paddle.ocrText(img, myModelPath)
log('OCR纯文本识别耗时:' + (new Date() - start) + 'ms')
toastLog("文本识别信息: " + JSON.stringify(stringList))
// 回收图片
img.recycle()
// 释放native内存,非必要,供万一出现内存泄露时使用
// paddle.release()
// project.json
{
"abis": [
"arm64-v8a",
"armeabi-v7a",
"x86",
"x86_64"
],
"assets": [
{
"form": "models",
"to": "/models"
}
],
"buildDir": "build",
"build": {
"build_id": null,
"build_number": 0,
"build_time": 0
},
"useFeatures": [],
"icon": null,
"ignoredDirs": [],
"launchConfig": {
"displaySplash": false,
"hideLauncher": false,
"hideLogs": false,
"stableMode": false,
"volumeUpcontrol": false,
"permissions": [],
"serviceDesc": "使脚本自动操作(点击、长按、滑动等)所需,若关闭则只能执行不涉及自动操作的脚本。",
"splashIcon": null,
"splashText": "Powered by paddle ocr"
},
"libs": [
"libc++_shared.so",
"libpaddle_light_api_shared.so",
"libhiai.so",
"libhiai_ir.so",
"libhiai_ir_build.so",
"libNative.so",
"libjackpal-androidterm5.so",
"libjackpal-termexec2.so"
],
"main": "PaddleOCR(自定义模型路径).js",
"name": "PaddleOCR(自定义模型路径)",
"outputPath": null,
"packageName": "com.script.paddleocr.custommodel",
"scripts": {},
"signingConfig": {
"alias": null,
"keystore": null
},
"sourcePath": null,
"versionCode": 1,
"versionName": "1.0.0"
}
PaddleOCR-截图识别
let currentEngine = engines.myEngine()
let runningEngines = engines.all()
let currentSource = currentEngine.getSource() + ''
if (runningEngines.length > 1) {
runningEngines.forEach(compareEngine => {
let compareSource = compareEngine.getSource() + ''
if (currentEngine.id !== compareEngine.id && compareSource === currentSource) {
// 强制关闭同名的脚本
compareEngine.forceStop()
}
})
}
if (!requestScreenCapture()) {
toastLog('请求截图权限失败')
exit()
}
sleep(1000)
// 识别结果和截图信息
let result = []
let img = null
let running = true
let capturing = true
/**
* 截图并识别OCR文本信息
*/
function captureAndOcr() {
capturing = true
img && img.recycle()
img = captureScreen()
if (!img) {
toastLog('截图失败')
}
let start = new Date()
result = paddle.ocr(img);
log(result);
toastLog('耗时' + (new Date() - start) + 'ms')
capturing = false
}
captureAndOcr()
// 获取状态栏高度
let offset = -getStatusBarHeightCompat()
//let offset = 0;
// 绘制识别结果
let window = floaty.rawWindow(
<canvas id="canvas" layout_weight="1" />
);
// 设置悬浮窗位置
ui.post(() => {
window.setPosition(0, offset)
window.setSize(device.width, device.height)
window.setTouchable(false)
})
// 操作按钮
let clickButtonWindow = floaty.rawWindow(
<vertical>
<button id="captureAndOcr" text="截图识别" />
<button id="closeBtn" text="退出" />
</vertical>
);
ui.run(function () {
clickButtonWindow.setPosition(device.width / 2 - ~~(clickButtonWindow.getWidth() / 2), device.height * 0.65)
})
// 点击识别
clickButtonWindow.captureAndOcr.click(function () {
result = []
ui.run(function () {
clickButtonWindow.setPosition(device.width, device.height)
})
setTimeout(() => {
threads.start(()=>{
captureAndOcr()
ui.run(function () {
clickButtonWindow.setPosition(device.width / 2 - ~~(clickButtonWindow.getWidth() / 2), device.height * 0.65)
})
})
}, 500)
})
// 点击关闭
clickButtonWindow.closeBtn.click(function () {
exit()
})
let Typeface = android.graphics.Typeface
let paint = new Paint()
paint.setStrokeWidth(1)
paint.setTypeface(Typeface.DEFAULT_BOLD)
paint.setTextAlign(Paint.Align.LEFT)
paint.setAntiAlias(true)
paint.setStrokeJoin(Paint.Join.ROUND)
paint.setDither(true)
window.canvas.on('draw', function (canvas) {
if (!running || capturing) {
return
}
// 清空内容
canvas.drawColor(0xFFFFFF, android.graphics.PorterDuff.Mode.CLEAR)
if (result && result.length > 0) {
for (let i = 0; i < result.length; i++) {
let ocrResult = result[i]
drawRectAndText(ocrResult.words + ' #信心:' + ocrResult.confidence.toFixed(2), ocrResult.bounds, '#00ff00', canvas, paint);
}
}
})
setInterval(() => { }, 10000)
events.on('exit', () => {
// 标记停止 避免canvas导致闪退
running = false
// 回收图片
img && img.recycle()
// 撤销监听
window.canvas.removeAllListeners()
})
/**
* 绘制文本和方框
*
* @param {*} desc
* @param {*} rect
* @param {*} colorStr
* @param {*} canvas
* @param {*} paint
*/
function drawRectAndText (desc, rect, colorStr, canvas, paint) {
let color = colors.parseColor(colorStr)
paint.setStrokeWidth(1)
paint.setStyle(Paint.Style.STROKE)
// 反色
paint.setARGB(255, 255 - (color >> 16 & 0xff), 255 - (color >> 8 & 0xff), 255 - (color & 0xff))
canvas.drawRect(rect, paint)
paint.setARGB(255, color >> 16 & 0xff, color >> 8 & 0xff, color & 0xff)
paint.setStrokeWidth(1)
paint.setTextSize(20)
paint.setStyle(Paint.Style.FILL)
canvas.drawText(desc, rect.left, rect.top, paint)
paint.setTextSize(10)
paint.setStrokeWidth(1)
paint.setARGB(255, 0, 0, 0)
}
/**
* 获取状态栏高度
*
* @returns
*/
function getStatusBarHeightCompat () {
let result = 0
let resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android")
if (resId > 0) {
result = context.getResources().getDimensionPixelOffset(resId)
}
if (result <= 0) {
result = context.getResources().getDimensionPixelOffset(R.dimen.dimen_25dp)
}
return result
}
Shell命令
冻结网易云音乐
shell("pm disable com.netease.cloudmusic", true);
结束所有后台进程
shell("am kill-all", true);
解冻并打开网易云音乐
shell("pm enable com.netease.cloudmusic", true);
launchApp("网易云音乐");
锁屏
KeyCode("KEYCODE_POWER");
//或者 KeyCode(26);
TessractOCR
//此例子仅作为演示,无法运行,因为tessdata目录下没有训练数据,
//如需运行,可前往github下载完整例子:https://github.com/wilinz/autoxjs-tessocr
//导包
importClass(com.googlecode.tesseract.android.TessBaseAPI)
//新建OCR实例
var tessocr = new TessBaseAPI()
//请求截图权限
requestScreenCapture(false);
//3秒后开始
toastLog("3秒后截图")
sleep(3000)
toastLog("开始截图")
//截图
var img = captureScreen();
//tessdata目录所在的文件夹,目录下放置训练数据
//训练数据下载地址:https://github.com/tesseract-ocr/tessdata/tree/4.0.0
var dataPath = files.path("./")
//初始化tessocr
//第二个参数是初始化的语言,是数据文件去掉扩展名后的文件名,多个语言用+连接
//训练数据文件夹必须命名为tessdata
//训练数据下载时是什么名字就是什么名字,不能改
var ok = tessocr.init(dataPath, "eng+chi_sim")
if (ok) {
toastLog("初始化成功: " + tessocr.getInitLanguagesAsString())
} else {
toastLog("初始化失败")
}
//设置图片
tessocr.setImage(img.getBitmap())
//打印文本结果
toastLog(tessocr.getUTF8Text())
//如需获取位置等其他结果请看文档
// project.json
{
"abis": [
"arm64-v8a",
"armeabi-v7a",
"x86",
"x86_64"
],
"assets": [
],
"buildDir": "build",
"build": {
"build_id": null,
"build_number": 0,
"build_time": 0
},
"useFeatures": [],
"icon": null,
"ignoredDirs": [
"build"
],
"launchConfig": {
"displaySplash": false,
"hideLauncher": false,
"hideLogs": false,
"stableMode": false,
"volumeUpcontrol": false,
"permissions": [],
"serviceDesc": "使脚本自动操作(点击、长按、滑动等)所需,若关闭则只能执行不涉及自动操作的脚本。",
"splashIcon": null,
"splashText": "Powered by TessOCR"
},
"libs": [
"libtesseract.so",
"libpng.so",
"libleptonica.so",
"libjpeg.so",
"libjackpal-androidterm5.so",
"libjackpal-termexec2.so"
],
"main": "main.js",
"name": "TessOCR",
"outputPath": null,
"packageName": "com.script.tessocr",
"projectDirectory": null,
"scripts": {},
"signingConfig": {
"alias": null,
"keystore": null
},
"sourcePath": null,
"versionCode": 1,
"versionName": "1.0.0"
}
Web扩展与游戏编程
贪吃蛇
"ui";
ui.layout(
<vertical>
<canvas id="board" layout_weight="1"/>
<relative h="120">
<button id="up" text="↑" w="60" h="60" layout_alignParentTop="true" layout_centerHorizontal="true"/>
<button id="left" text="←" w="60" h="60" layout_alignParentBottom="true" layout_toLeftOf="@id/down"/>
<button id="down" text="↓" w="60" h="60" layout_alignParentBottom="true" layout_centerHorizontal="true"/>
<button id="right" text="→" w="60" h="60" layout_alignParentBottom="true" layout_toRightOf="@id/down"/>
</relative>
</vertical>
);
//蛇的颜色
const SNAKE_COLOR = colors.parseColor("#4caf50");
//背景色
const BG_COLOR = colors.parseColor("#ffffff");
//苹果颜色
const APPLE_COLOR = colors.parseColor("#f44336");
//墙的颜色
const WALL_COLOR = colors.parseColor("#607d8b");
//文本颜色
const TEXT_COLOR = colors.parseColor("#03a9f4");
//蛇自动移动的时间间隔,调小可以增加难度
const MOVE_INTERVAL = 500;
//方块宽度
const BLOCK_WIDTH = 40;
//游戏区域宽高
const GAME_BOARD_HEIGHT = 20;
const GAME_BOARD_WIDTH = 15;
//蛇的四个移动方向
const DIRECTION_LEFT = {x: -1, y: 0};
const DIRECTION_RIGHT = {x: 1, y: 0};
const DIRECTION_UP = {x: 0, y: -1};
const DIRECTION_DOWN = {x: 0, y: 1};
//蛇,是一个蛇身的坐标的数组
var snake = [{x: 4, y: 2}, {x: 3, y: 2}, {x: 2, y: 2}];
//苹果的坐标
var apple = generateApple();
//当前蛇的移动方向
var direction = DIRECTION_RIGHT;
//标记游戏是否结束
var isGameOver = false;
//分数
var score = 0;
var paint = new Paint();
ui.board.on("draw", function(canvas){
//绘制背景色
canvas.drawColor(BG_COLOR);
//绘制分数
paint.setColor(TEXT_COLOR);
paint.setTextSize(50);
canvas.drawText("分数: " + score, 30, 70, paint);
//如果游戏结束则绘制游戏结束字样
if(isGameOver){
canvas.drawText("游戏结束!", canvas.getWidth() - 280, 70, paint);
}
//计算坐标偏移,是的游戏区域绘制在画面的水平居中位置
var offset = {
x: (canvas.getWidth() - (GAME_BOARD_WIDTH + 2) * BLOCK_WIDTH) / 2,
y: 100
};
//偏移坐标
canvas.translate(offset.x, offset.y);
//绘制围墙
paint.setColor(WALL_COLOR);
for(var i = 0; i <= GAME_BOARD_WIDTH + 1; i++){
//上围墙
drawBlock(canvas, paint, i, 0);
//下围墙
drawBlock(canvas, paint, i, GAME_BOARD_HEIGHT + 1);
}
for(var i = 0; i <= GAME_BOARD_HEIGHT + 1; i++){
//左围墙
drawBlock(canvas, paint, 0, i);
//右围墙
drawBlock(canvas, paint, GAME_BOARD_WIDTH + 1, i);
}
//绘制蛇身
paint.setColor(SNAKE_COLOR);
for(var i = 0; i < snake.length; i++){
drawBlock(canvas, paint, snake[i].x, snake[i].y);
}
//绘制苹果
paint.setColor(APPLE_COLOR);
drawBlock(canvas, paint, apple.x, apple.y);
});
//启动游戏线程
var gameThread = threads.start(game);
//按键点击时改变蛇的移动方向
ui.left.on("click", ()=> direction = DIRECTION_LEFT);
ui.right.on("click", ()=> direction = DIRECTION_RIGHT);
ui.up.on("click", ()=> direction = DIRECTION_UP);
ui.down.on("click", ()=> direction = DIRECTION_DOWN);
function game(){
//每隔一段时间让蛇自动前进
setInterval(()=>{
move(direction.x, direction.y);
}, MOVE_INTERVAL);
}
function move(dx, dy){
log("move: %d, %d", dx, dy);
direction.x = dx;
direction.y = dy;
//蛇前进时把一个新的方块添加到蛇头前面
var head = snake[0];
snake.splice(0, 0, {
x: head.x + dx,
y: head.y + dy
});
//如果蛇头吃到了苹果
if(snakeEatsApple()){
//添加分数和重新生成苹果
score += 5;
apple = generateApple();
}else{
//没有吃到苹果的情况下把蛇尾去掉保持蛇身长度不变
snake.pop();
}
//碰撞检测
collisionTest();
}
function snakeEatsApple(){
return snake[0].x == apple.x && snake[0].y == apple.y;
}
function generateApple(){
//循环生成苹果直至苹果不会生成在蛇身上
var x, y;
do{
x = random(1, GAME_BOARD_WIDTH);
y = random(1, GAME_BOARD_HEIGHT);
}while(!isAppleValid(x, y));
return {x: x, y: y};
}
function isAppleValid(x, y){
for (var i = 0; i < snake.length; i++) {
if (snake[i].x == x && snake[i].y == y) {
return false;
}
}
return true;
}
function collisionTest(){
//检测蛇有没有撞到墙上
var head = snake[0];
if(head.x < 1 || head.x > GAME_BOARD_WIDTH
|| head.y < 1 || head.y > GAME_BOARD_HEIGHT){
gameOver();
return;
}
//检测蛇有没有撞到自己
for(var i = 1; i < snake.length; i++){
if(snake[i].x == head && snake[i].y == head){
gameOver();
return;
}
}
}
function gameOver(){
gameThread.interrupt();
isGameOver = true;
}
function drawBlock(canvas, paint, x, y){
x *= BLOCK_WIDTH;
y *= BLOCK_WIDTH;
canvas.drawRect(x, y, x + BLOCK_WIDTH, y + BLOCK_WIDTH, paint);
}
贪吃蛇重力版
"ui";
ui.layout(
<vertical>
<canvas id="board" layout_weight="1"/>
<relative h="120">
<button id="up" text="↑" w="60" h="60" layout_alignParentTop="true" layout_centerHorizontal="true"/>
<button id="left" text="←" w="60" h="60" layout_alignParentBottom="true" layout_toLeftOf="@id/down"/>
<button id="down" text="↓" w="60" h="60" layout_alignParentBottom="true" layout_centerHorizontal="true"/>
<button id="right" text="→" w="60" h="60" layout_alignParentBottom="true" layout_toRightOf="@id/down"/>
</relative>
</vertical>
);
//蛇的颜色
const SNAKE_COLOR = colors.parseColor("#4caf50");
//背景色
const BG_COLOR = colors.parseColor("#ffffff");
//苹果颜色
const APPLE_COLOR = colors.parseColor("#f44336");
//墙的颜色
const WALL_COLOR = colors.parseColor("#607d8b");
//文本颜色
const TEXT_COLOR = colors.parseColor("#03a9f4");
//蛇自动移动的时间间隔,调小可以增加难度
const MOVE_INTERVAL = 500;
//方块宽度
const BLOCK_WIDTH = 40;
//游戏区域宽高
const GAME_BOARD_HEIGHT = 20;
const GAME_BOARD_WIDTH = 15;
//蛇的四个移动方向
const DIRECTION_LEFT = {x: -1, y: 0};
const DIRECTION_RIGHT = {x: 1, y: 0};
const DIRECTION_UP = {x: 0, y: -1};
const DIRECTION_DOWN = {x: 0, y: 1};
//蛇,是一个蛇身的坐标的数组
var snake = [{x: 4, y: 2}, {x: 3, y: 2}, {x: 2, y: 2}];
//苹果的坐标
var apple = generateApple();
//当前蛇的移动方向
var direction = DIRECTION_RIGHT;
//标记游戏是否结束
var isGameOver = false;
//分数
var score = 0;
var paint = new Paint();
ui.board.on("draw", function(canvas){
//绘制背景色
canvas.drawColor(BG_COLOR);
//绘制分数
paint.setColor(TEXT_COLOR);
paint.setTextSize(50);
canvas.drawText("分数: " + score, 30, 70, paint);
//如果游戏结束则绘制游戏结束字样
if(isGameOver){
canvas.drawText("游戏结束!", canvas.getWidth() - 280, 70, paint);
}
//计算坐标偏移,是的游戏区域绘制在画面的水平居中位置
var offset = {
x: (canvas.getWidth() - (GAME_BOARD_WIDTH + 2) * BLOCK_WIDTH) / 2,
y: 100
};
//偏移坐标
canvas.translate(offset.x, offset.y);
//绘制围墙
paint.setColor(WALL_COLOR);
for(var i = 0; i <= GAME_BOARD_WIDTH + 1; i++){
//上围墙
drawBlock(canvas, paint, i, 0);
//下围墙
drawBlock(canvas, paint, i, GAME_BOARD_HEIGHT + 1);
}
for(var i = 0; i <= GAME_BOARD_HEIGHT + 1; i++){
//左围墙
drawBlock(canvas, paint, 0, i);
//右围墙
drawBlock(canvas, paint, GAME_BOARD_WIDTH + 1, i);
}
//绘制蛇身
paint.setColor(SNAKE_COLOR);
for(var i = 0; i < snake.length; i++){
drawBlock(canvas, paint, snake[i].x, snake[i].y);
}
//绘制苹果
paint.setColor(APPLE_COLOR);
drawBlock(canvas, paint, apple.x, apple.y);
});
//启动游戏线程
var gameThread = threads.start(game);
//按键点击时改变蛇的移动方向
ui.left.on("click", ()=> direction = DIRECTION_LEFT);
ui.right.on("click", ()=> direction = DIRECTION_RIGHT);
ui.up.on("click", ()=> direction = DIRECTION_UP);
ui.down.on("click", ()=> direction = DIRECTION_DOWN);
function game(){
//每隔一段时间让蛇自动前进
setInterval(()=>{
move(direction.x, direction.y);
}, MOVE_INTERVAL);
}
function move(dx, dy){
log("move: %d, %d", dx, dy);
direction.x = dx;
direction.y = dy;
//蛇前进时把一个新的方块添加到蛇头前面
var head = snake[0];
snake.splice(0, 0, {
x: head.x + dx,
y: head.y + dy
});
//如果蛇头吃到了苹果
if(snakeEatsApple()){
//添加分数和重新生成苹果
score += 5;
apple = generateApple();
}else{
//没有吃到苹果的情况下把蛇尾去掉保持蛇身长度不变
snake.pop();
}
//碰撞检测
collisionTest();
}
function snakeEatsApple(){
return snake[0].x == apple.x && snake[0].y == apple.y;
}
function generateApple(){
//循环生成苹果直至苹果不会生成在蛇身上
var x, y;
do{
x = random(1, GAME_BOARD_WIDTH);
y = random(1, GAME_BOARD_HEIGHT);
}while(!isAppleValid(x, y));
return {x: x, y: y};
}
function isAppleValid(x, y){
for (var i = 0; i < snake.length; i++) {
if (snake[i].x == x && snake[i].y == y) {
return false;
}
}
return true;
}
function collisionTest(){
//检测蛇有没有撞到墙上
var head = snake[0];
if(head.x < 1 || head.x > GAME_BOARD_WIDTH
|| head.y < 1 || head.y > GAME_BOARD_HEIGHT){
gameOver();
return;
}
//检测蛇有没有撞到自己
for(var i = 1; i < snake.length; i++){
if(snake[i].x == head && snake[i].y == head){
gameOver();
return;
}
}
}
function gameOver(){
gameThread.interrupt();
isGameOver = true;
}
function drawBlock(canvas, paint, x, y){
x *= BLOCK_WIDTH;
y *= BLOCK_WIDTH;
canvas.drawRect(x, y, x + BLOCK_WIDTH, y + BLOCK_WIDTH, paint);
}
AutoX注入webviwe
"ui";
ui.layout(
<vertical>
<horizontal bg="#c7edcc" gravity="center" h="auto">
<button text="网络冲浪" id="surfInternetBtn" style="Widget.AppCompat.Button.Colored" w="auto" />
<button text="记忆翻牌" id="loadLocalHtmlBtn" style="Widget.AppCompat.Button.Colored" w="auto" />
<button text="控制台" id="consoleBtn" style="Widget.AppCompat.Button.Colored" w="auto" />
</horizontal>
<vertical h="*" w="*">
<webview id="webView" layout_below="title" w="*" h="*" />
</vertical>
</vertical>
);
function calljavascript(webViewWidget, script, callback) {
try {
console.assert(webViewWidget != null, "webView控件为空");
//console.log(script.toString())
webViewWidget.evaluatejavascript("javascript:" + script, new JavaAdapter(android.webkit.ValueCallback, {
onReceiveValue: (val) => {
if (callback) {
callback(val);
}
}
}));
} catch (e) {
console.error("执行javascript失败");
console.trace(e);
}
}
function AutoX() {
let getAutoXFrame = () => {
let bridgeFrame = document.getElementById("AutoXFrame");
if (!bridgeFrame) {
bridgeFrame = document.createElement('iframe');
bridgeFrame.id = "AutoXFrame";
bridgeFrame.style = "display: none";
document.body.append(bridgeFrame);
}
return bridgeFrame;
};
const h5Callbackers = {};
let h5CallbackIndex = 1;
let setCallback = (callback) => {
let callId = h5CallbackIndex++;
h5Callbackers[callId] = {
"callback": callback
};
return callId;
};
let getCallback = (callId) => {
let callback = h5Callbackers[callId];
if (callback) {
delete h5Callbackers[callId];
}
return callback;
};
function invoke(cmd, params, callback) {
let callId = null;
try {
let paramsStr = JSON.stringify(params);
let AutoXFrame = getAutoXFrame();
callId = setCallback(callback);
AutoXFrame.src = "jsbridge://" + cmd + "/" + callId + "/" + encodeURIComponent(paramsStr);
} catch (e) {
if (callId) {
getCallback(callId);
}
console.trace(e);
}
};
let callback = (data) => {
let callId = data.callId;
let params = data.params;
let callbackFun = getCallback(callId);
if (callbackFun && callbackFun.callback) {
callbackFun.callback(params);
}
};
return {
invoke: invoke,
callback: callback
};
};
function bridgeHandler_handle(cmd, params) {
console.log('bridgeHandler处理 cmd=%s, params=%s', cmd, JSON.stringify(params));
let fun = this[cmd];
if (!fun) {
throw new Error("cmd= " + cmd + " 没有定义实现");
}
let ret = fun(params)
return ret;
}
function mFunction(params) {
toastLog(params.toString());
device.vibrate(120);
return files.isDir('/storage/emulated/0/Download')//'toast提示成功';
}
function webViewExpand_init(webViewWidget) {
webViewWidget.webViewClient = new JavaAdapter(android.webkit.WebViewClient, {
onPageFinished: (webView, curUrl) => {
try {
// 注入 AutoX
calljavascript(webView, AutoX.toString() + ";var auto0 = AutoX();auto0.invoke('mFunction','This is AutoX!',(data) => {console.log('接收到callback1:' + JSON.stringify(data));});", null);
} catch (e) {
console.trace(e)
}
},
shouldOverrideUrlLoading: (webView, request) => {
let url = '';
try {
url = (request.a && request.a.a) || (request.url);
if (url instanceof android.net.Uri) {
url = url.toString();
}
if (url.indexOf("jsbridge://") == 0) {
let uris = url.split("/");
let cmd = uris[2];
let callId = uris[3];
let params = java.net.URLDecoder.decode(uris[4], "UTF-8");
console.log('AutoX处理javascript调用请求: callId=%s, cmd=%s, params=%s', callId, cmd, params);
let result = null;
try {
result = bridgeHandler_handle(cmd, JSON.parse(params));
} catch (e) {
console.trace(e);
result = {
message: e.message
};
}
result = result || {};
webView.loadUrl("javascript:auto0.callback({'callId':" + callId + ", 'params': " + JSON.stringify(result) + "});");
} else if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("file://") || url.startsWith("ws://") || url.startsWith("wss://")) {
webView.loadUrl(url);
} else {
}
return true;
} catch (e) {
if (e.javaException instanceof android.content.ActivityNotFoundException) {
webView.loadUrl(url);
} else {
toastLog('无法打开URL: ' + url);
}
console.trace(e);
}
},
onReceivedError: (webView, webResourceRequest, webResourceError) => {
let url = webResourceRequest.getUrl();
let errorCode = webResourceError.getErrorCode();
let description = webResourceError.getDescription();
console.trace(errorCode + " " + description + " " + url);
}
});
webViewWidget.webChromeClient = new JavaAdapter(android.webkit.WebChromeClient, {
onConsoleMessage: (msg) => {
console.log("[%s:%s]: %s", msg.sourceId(), msg.lineNumber(), msg.message());
}
});
}
webViewExpand_init(ui.webView)
ui.webView.loadUrl("https://wht.im");
ui.surfInternetBtn.on("click", () => {
webViewExpand_init(ui.webView);
ui.webView.loadUrl("https://wht.im");
});
ui.consoleBtn.on("click", () => {
app.startActivity("console");
});
ui.loadLocalHtmlBtn.on('click', () => {
webViewExpand_init(ui.webView);
let path = "file:" + files.path("game.html");
ui.webView.loadUrl(path);
});
WebSocket
创建客户端
importPackage(Packages["okhttp3"]);
var client = new OkHttpClient.Builder().retryOnConnectionFailure(true).build();
var request = new Request.Builder().url("ws://192.168.31.164:9317").build();
client.dispatcher().cancelAll();//清理一次
myListener = {
onOpen: function (webSocket, response) {
print("onOpen");
var json = {};
json.type="hello";
json.data= {device_name:"模拟设备",client_version:123,app_version:123,app_version_code:"233"};
var hello=JSON.stringify(json);
webSocket.send(hello);
},
onMessage: function (webSocket, msg) {
print("msg");
print(msg);
},
onClosing: function (webSocket, code, reason) {
print("正在关闭");
},
onClosed: function (webSocket, code, reason) {
print("关闭");
},
onFailure: function (webSocket, t, response) {
print("错误");
print( t);
}
}
var webSocket= client.newWebSocket(request, new WebSocketListener(myListener));
setInterval(() => {
}, 1000);
WebSocket示例
// 新建一个WebSocket
// 指定web socket的事件回调在当前线程(好处是没有多线程问题要处理,坏处是不能阻塞当前线程,包括死循环)
// 不加后面的参数则回调在IO线程
let ws = web.newWebSocket("wss://demo.piesocket.com/v3/channel_1?notify_self", {
eventThread: 'this'
});
console.show();
// 监听他的各种事件
ws.on("open", (res, ws) => {
log("WebSocket已连接");
}).on("failure", (err, res, ws) => {
log("WebSocket连接失败");
console.error(err);
}).on("closing", (code, reason, ws) => {
log("WebSocket关闭中");
}).on("text", (text, ws) => {
console.info("收到文本消息: ", text);
}).on("binary", (bytes, ws) => {
console.info("收到二进制消息:");
console.info("hex: ", bytes.hex());
console.info("base64: ", bytes.base64());
console.info("md5: ", bytes.md5());
console.info("size: ", bytes.size());
console.info("bytes: ", bytes.toByteArray());
}).on("closed", (code, reason, ws) => {
log("WebSocket已关闭: code = %d, reason = %s", code, reason);
});
// 发送文本消息
log("发送消息: Hello, WebSocket!");
ws.send("h");
setTimeout(() => {
// 两秒后发送二进制消息
log("发送二进制消息: 5piO5aSp5L2g6IO96ICDMTAw5YiG44CC");
ws.send(web.ByteString.decodeBase64("5piO5aSp5L2g6IO96ICDMTAw5YiG44CC"));
}, 2000);
setTimeout(() => {
// 8秒后断开WebSocket
log("断开WebSocket");
// 1000表示正常关闭
ws.close(1000, null);
}, 8000);
setTimeout(() => {
log("退出程序");
}, 12000)
本文转自 https://blog.csdn.net/qq_37952052/article/details/131743625?spm=1001.2014.3001.5502,如有侵权,请联系删除。
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 程序员HoneyZ
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果