控制台
保存日志
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("\n");
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);
控制台示例
<em>//显示控制台
</em><em></em>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>
);
<em>//getBrightnessMode()返回亮度模式,1为自动亮度
</em><em></em>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 += "\n屏幕高度:" + device.height;
str += "\nbuildId:" + device.buildId;
str += "\n主板:" + device.board;
str += "\n制造商:" + device.brand;
str += "\n型号:" + device.model;
str += "\n产品名称:" + device.product;
str += "\nbootloader版本:" + device.bootloader;
str += "\n硬件名称:" + device.hardware;
str += "\n唯一标识码:" + device.fingerprint;
str += "\nIMEI: " + device.getIMEI();
str += "\nAndroidId: " + device.getAndroidId();
str += "\nMac: " + device.getMacAddress();
str += "\nAPI: " + device.sdkInt;
str += "\n电量: " + device.getBattery();
str += "\n是否有虚拟导航: " + device.checkDeviceHasNavigationBar();
str += "\n虚拟导航高度: " + 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();
获取网络图片并保存
<em>//这个是Auto.js图标的地址
</em><em></em>var url = "https://www.autojs.org/assets/uploads/profile/3-profileavatar.png";
var logo = images.load(url);
<em>//保存到路径/sdcard/auto.js.png
</em><em></em>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();
<em>//0x9966ff为编辑器紫色字体的颜色
</em><em></em>toastLog("开始找色");
var point = findColor(img, 0x9966ff);
if(point){
toastLog("x = " + point.x + ", y = " + point.y);
}else{
toastLog("没有找到");
}
模糊找色
if(!requestScreenCapture()){
toast("请求截图失败");
exit();
}
var img = captureScreen();
<em>//0x9966ff为编辑器紫色字体的颜色
</em><em></em>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("开始找色");
<em>//指定在位置(100, 220)宽高为400*400的区域找色。
</em><em>//#75438a是编辑器默认主题的棕红色字体(数字)颜色,位置大约在第5行的"2000",坐标大约为(283, 465)
</em><em></em>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();
<em>//0xffffff为白色
</em><em></em>toastLog("开始找色");
<em>//指定在位置(90, 220)宽高为900*1000的区域找色。
</em><em>//0xff00cc是编辑器的深粉红色字体(字符串)颜色
</em><em></em>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>
);
<em>//把一张图片设置到图片控件中
</em><em></em>function setImage(img) {
ui.run(() => {
ui.img.setImageBitmap(img.bitmap);
var oldImg = currentImg;
<em>//不能立即回收currentImg,因为此时img控件还在使用它,应该在下次消息循环再回收它
</em><em></em> ui.post(()=>{
if(oldImg != null){
oldImg.recycle();
}
});
currentImg = img;
});
}
<em>//启动一个处理图片的线程
</em><em></em>var imgProcess = threads.start(function () {
setInterval(() => { }, 1000);
});
<em>//处理图片的函数,把任务交给图片处理线程处理
</em><em></em>function processImg(process) {
imgProcess.setTimeout(() => {
if (logo == null) {
logo = images.load(url);
}
<em>//处理图片
</em><em></em> var result = process(logo);
<em>//把处理后的图片设置到图片控件中
</em><em></em> setImage(result);
}, 0);
}
var degress = 0;
ui.rotate.on("click", () => {
processImg(img => {
degress += 90;
<em>//旋转degress角度
</em><em></em> return images.rotate(img, degress);
});
});
ui.concat.on("click", () => {
processImg(img => {
if(currentImg == null){
toast("请先点击其他按钮,再点击本按钮");
return img.clone();
}
<em>//把currentImg拼接在img右边
</em><em></em> return images.concat(img, currentImg, "right");
});
});
ui.grayscale.on("click", () => {
processImg(img => {
<em>//灰度化
</em><em></em> return images.grayscale(img);
});
});
ui.binary.on("click", () => {
processImg(img => {
var g = images.grayscale(img);
<em>//二值化,取灰度为30到200之间的图片
</em><em></em> var result = images.threshold(g, 100, 200);
g.recycle();
return result;
});
});
ui.adaptiveBinary.on("click", () => {
processImg(img => {
var g = images.grayscale(img);
<em>//自适应二值化,最大值为200,块大小为25
</em><em></em> var result = images.adaptiveThreshold(g, 200, "MEAN_C", "BINARY", 25, 10);
g.recycle();
return result;
});
});
ui.hsv.on("click", () => {
processImg(img => {
<em>//RGB转HSV
</em><em></em> return images.cvtColor(img, "BGR2HSV");
});
});
ui.blur.on("click", () => {
processImg(img => {
<em>//模糊
</em><em></em> return images.blur(img, [10, 10]);
});
});
ui.medianBlur.on("click", () => {
processImg(img => {
<em>//中值滤波
</em><em></em> return images.medianBlur(img, 5);
});
});
ui.gaussianBlur.on("click", () => {
processImg(img => {
<em>//高斯模糊
</em><em></em> return images.gaussianBlur(img, [5, 5]);
});
});
颜色获取和检测
if(!requestScreenCapture()){
toast("请求截图失败");
exit
}
sleep(2000);
var x = 760;
var y = 180;
<em>//获取在点(x, y)处的颜色
</em><em></em>var c = images.pixel(captureScreen(), x, y);
<em>//显示该颜色
</em><em></em>var msg = "";
msg += "在位置(" + x + ", " + y + ")处的颜色为" + colors.toString(c);
msg += "\nR = " + colors.red(c) + ", G = " + colors.green(c) + ", B = " + colors.blue(c);
<em>//检测在点(x, y)处是否有颜色#73bdb6 (模糊比较)
</em><em></em>var isDetected = images.detectsColor(captureScreen(), "#73bdb6", x, y);
msg += "\n该位置是否匹配到颜色#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("没有找到");
}
文件读写
读取文本文件
<em>//文件路径
</em><em></em>var path = "/sdcard/1.txt";
<em>//打开文件
</em><em></em>var file = open(path);
<em>//读取文件的所有内容
</em><em></em>var text = file.read();
<em>//打印到控制台
</em><em></em>print(text);
<em>//关闭文件
</em><em></em>file.close();
console.show();
读写文本文件
<em>//以写入模式打开SD卡根目录文件1.txt
</em><em></em>var file = open("/sdcard/1.txt", "w")
<em>//写入aaaa
</em><em></em>file.write("aaaa");
<em>//写入bbbbb后换行
</em><em></em>file.writeline("bbbbb");
<em>//写入ccc与ddd两行
</em><em></em>file.writelines(["ccc", "ddd"]);
<em>//关闭文件
</em><em></em>file.close();
<em>//以附加模式打开文件
</em><em></em>file = open("/sdcard/1.txt", "a");
<em>//附加一行"啦啦啦啦"
</em><em></em>file.writeline("啦啦啦啦");
<em>//附加一行"哈哈哈哈"
</em><em></em>file.writeline("哈哈哈哈");
<em>//附加两行ccc, ddd
</em><em></em>file.writelines(["ccc", "ddd"]);
<em>//输出缓冲区
</em><em></em>file.flush();
<em>//关闭文件
</em><em></em>file.close();
<em>//以读取模式打开文件
</em><em></em>file = open("/sdcard/test.txt", "r")
<em>//读取一行并打印
</em><em></em>print(file.readline());
<em>//读取剩余所有行并打印
</em><em></em>for each(line in file.readlines()){
print(line)
}
file.close()
<em>//显示控制台
</em><em></em>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);
}
}
}
文件编码转换
<em>//以UTF-8编码打开SD卡上的1.txt文件
</em><em></em>var f = open("/sdcard/1.txt", "r", "utf-8");
<em>//读取文件所有内容
</em><em></em>var text = f.read();
<em>//关闭文件
</em><em></em>f.close();
<em>//以gbk编码打开SD卡上的2.txt文件
</em><em></em>var out = open("/sdcard/2.txt", "w", "gbk");
<em>//写入内容
</em><em></em>out.write(text);
<em>//关闭文件
</em><em></em>out.close();
文件编码转换(高级)
convert("/sdcard/1.txt", "utf-8", "/sdcard/2.txt", "gbk");
<em>/**
</em><em> * fromFile: 源文件路径
</em><em> * fromEncoding: 源文件编码
</em><em> * toFile: 输出文件路径
</em><em> * toEncoding: 输出文件编码
</em><em> */</em>
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);
}
}
写入文本文件
<em>//文件路径
</em><em></em>var path = "/sdcard/1.txt";
<em>//要写入的文件内容
</em><em></em>var text = "Hello, AutoJs";
<em>//以写入模式打开文件
</em><em></em>var file = open(path, "w");
<em>//写入文件
</em><em></em>file.write(text);
<em>//关闭文件
</em><em></em>file.close();
消息处理(加密、摘要、编码)
加密解密
let message = "未加密字符串";
log("明文: ", message);
<em>// 密钥,由于AES等算法要求是16位的倍数,我们这里用一个16位的密钥
</em><em></em>let key = new $crypto.Key("password12345678");
log("密钥: ", key);
<em>// AES加密
</em><em></em>let aes = $crypto.encrypt(message, key, "AES/ECB/PKCS5padding");
log("AES加密后二进制数据: ", aes);
log("AES解密: ", $crypto.decrypt(aes, key, "AES/ECB/PKCS5padding", {output: 'string'}));
<em>// RSA加密
</em><em>// 生成RSA密钥
</em><em></em>let keyPair = $crypto.generateKeyPair("RSA");
log("密钥对: ", keyPair);
<em>// 使用私钥加密
</em><em></em>let rsa = $crypto.encrypt(message, keyPair.privateKey, "RSA/ECB/PKCS1padding");
log("RSA私钥加密后二进制数据: ", rsa);
<em>// 使用公钥解密
</em><em></em>log("RSA公钥解密: ", $crypto.decrypt(rsa, keyPair.publicKey, "RSA/ECB/PKCS1padding", {output: 'string'}));
消息摘要(MD5,SHA)
<em>// 字符串消息摘要
</em><em></em>let message = "Hello, Autox.js";
<em>// 输出各种消息摘要算法结果的hex值
</em><em></em>log("字符串: ", message);
log("MD5: ", $crypto.digest(message, "MD5"));
log("SHA1: ", $crypto.digest(message, "SHA-1"));
log("SHA256: ", $crypto.digest(message, "SHA-256"));
<em>// 输出各种消息摘要算法结果的base64值
</em><em></em>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'}));
<em>// 文件消息摘要
</em><em></em>let file = "/sdcard/脚本/_test_for_message_digest.js"
<em>// 写入文件内容,提供为后续计算MD5等
</em><em></em>$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
<em>// 注意,要使用协程这个特性,必须使用项目功能,并且在project.json配置好features属性
</em><em></em>
<em>// delay不同于sleep,不会阻塞当前线程
</em><em></em>function delay(millis) {
var cont = continuation.create();
setTimeout(()=>{
cont.resume();
}, millis);
cont.await();
}
<em>// 异步IO例子,在另一个线程读取文件,读取完成后返回当前线程继续执行
</em><em></em>function read(path) {
var cont = continuation.create();
threads.start(function(){
try {
cont.resume(files.read(path));
}catch(err){
cont.resumeError(err);
}
});
return cont.await();
}
<em>// 使用Promise和协程的例子
</em><em></em>function add(a, b) {
return new Promise(function(resolve, reject) {
var sum = a + b;
resolve(sum);
});
}
toastLog("Hello, Continuation!");
<em>//3秒后发出提示
</em><em></em>setTimeout(()=>{
toastLog("3秒后....");
}, 3000);
<em>// 你可以尝试把delay更换成sleep,看会发生什么!
</em><em></em>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);
<em>// project.json
</em><em></em>{
"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();
}
<em>// 退出应用对话框
</em><em></em>ui.emitter.on("back_pressed", function (e) {
e.consumed = true;
let exit = dialogs.confirm("确定要退出程序").await();
if (exit) {
ui.finish();
}
});
<em>// project.json
</em><em></em>{
"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(()=>{
<em>//对控件的操作需要在UI线程中执行
</em><em></em> ui.run(function(){
window.text.setText(dynamicText());
});
}, 1000);
function dynamicText(){
var date = new Date();
var str = util.format("时间: %d:%d:%d\n", date.getHours(), date.getMinutes(), date.getSeconds());
str += util.format("内存使用量: %d%%\n", getMemoryUsage());
str += "当前活动: " + currentActivity() + "\n";
str += "当前包名: " + currentPackage();
return str;
}
<em>//获取内存使用率
</em><em></em>function getMemoryUsage(){
var usage = (100 * device.getAvailMem() / device.getTotalMem());
<em>//保留一位小数
</em><em></em> 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;
<em>//记录按键被按下时的触摸坐标
</em><em></em>var x = 0, y = 0;
<em>//记录按键被按下时的悬浮窗位置
</em><em></em>var windowX, windowY;
<em>//记录按键被按下的时间以便判断长按等动作
</em><em></em>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:
<em>//移动手指时调整悬浮窗位置
</em><em></em> window.setPosition(windowX + (event.getRawX() - x),
windowY + (event.getRawY() - y));
<em>//如果按下的时间超过1.5秒判断为长按,退出脚本
</em><em></em> if(new Date().getTime() - downTime > 1500){
exit();
}
return true;
case event.ACTION_UP:
<em>//手指弹起时如果偏移很小则判断为点击
</em><em></em> 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('开始运行');
}
}