autojs 对标 autohotkey,是安卓平台的自动化编程平台。使用js语言,通过查询系统无障碍接口,能够实现检测界面、自动点击按钮、自动填写内容等功能。还能在js中内联xml,画出好看的用户界面,比如<scroll>对应scrollview,<vertical>对应,<radiogroup>对应、<radio> 对应、等等,当然还支持属性,比如bg是背景色,style="Widget.AppCompat.Button.Colored" 是样式,text是,height是,width是等等。
编译过程:略
编程体验一言难尽,是vscode开启服务端,而不是手机开启。vscode将代码发送至手机,手机刷新出来,点击允许按钮允许。
调试难,一言难尽。两个功能,鼓捣好久。真奇怪,明明安卓更灵活,但auto开发起来和ahk一样,一言难尽。
两个痛点:向下滚动有时不滚动。toast有时运行了但是没有消息显示。
main.js 完整代码如下
"ui";
var _proxy_port = 8888;
init_ui();
function init_ui() {
ui.layout(
<scroll bg="#888888" >
<vertical>
<appbar>
<toolbar title="WiFi代理设置 v1.1"/>
</appbar>
<vertical padding="16">
<vertical>
<text>代理IP</text>
<input id="proxy_ip" text="192.168.0.101"/>
<text>代理端口</text>
<radiogroup id="proxy_port" orientation="horizontal">
<radio text="8080" id="r1" marginRight="16"></radio>
<radio text="8888" id="r2" marginRight="16" checked="true"></radio>
<radio text="8866" id="r3" marginRight="16"></radio>
</radiogroup>
</vertical>
<vertical marginTop="16">
<text>[Android 9] 设置 → WLAN → WLAN → 已连接 → 修改 → ...</text>
<horizontal height="88">
<button bg="#ababab" id="open_android_9" text="开启代理" marginRight="10" style="Widget.AppCompat.Button.Colored" height="match_parent" layout_weight="1"/>
<button bg="#ababab" id="close_android_9" text="关闭代理" height="match_parent" layout_weight="1" />
</horizontal>
</vertical>
{/*
<vertical marginTop="16">
<text>[双击亮屏] 设置 → 锁屏 → 双击亮屏</text>
<horizontal height="88">
<button id="drive_xiaomi_sjlp"
text="切换"
style="Widget.AppCompat.Button.Colored"
width="match_parent"
height="match_parent"
/>
</horizontal>
</vertical>
*/}
<vertical marginTop="16">
<text>[熄屏显示] 设置 → 显示 → 熄屏提醒</text>
<horizontal height="88">
<button bg="#ababab" id="drive_1ui_xipingxianshi"
text="切换"
style="Widget.AppCompat.Button.Colored"
width="match_parent"
height="match_parent"
/>
</horizontal>
</vertical>
</vertical>
</vertical>
</scroll>
);
// Port checked
ui.r1.on("click", (checked)=>{
_proxy_port = 8080;
});
ui.r2.on("click", (checked)=>{
_proxy_port = 8888;
});
ui.r3.on("click", (checked)=>{
_proxy_port = 8866;
});
if(ui.drive_xiaomi_sjlp)
ui.drive_xiaomi_sjlp.click(function(){
var proxy_ip = ui.proxy_ip.getText();
// ...
threads.start(function(){
drive_xiaomi_sjlp_handler(proxy_ip, _proxy_port);
});
});
if(ui.drive_1ui_xipingxianshi)
ui.drive_1ui_xipingxianshi.click(function(){
threads.start(function(){
drive_1ui_xipingxianshi();
});
});
// Android 9
ui.open_android_9.click(function(){
var proxy_ip = ui.proxy_ip.getText();
// ...
threads.start(function(){
open_android_9_handler(proxy_ip, _proxy_port);
});
});
ui.close_android_9.click(function(){
threads.start(function(){
close_android_9_handler();
});
});
var proxy_ip = ui.proxy_ip.getText();
// ...
threads.start(function(){
// tg
// open_android_9_handler(proxy_ip, _proxy_port);
});
}
const interval = 300;
/**
* 开启代理(Android 7)
* @param proxy_ip
* @param proxy_port
*/
function drive_xiaomi_sjlp_handler(proxy_ip, proxy_port) {
// 打开设置
var settingsPackageName = app.getPackageName("设置");
app.launchPackage("com.android.settings")
// app.startActivity({
// // action: "android.settings.SECURITY_SETTINGS",
// packageName: "com.android.settings",
// // className :"com.android.settings.ChooseLockGeneric"
// });
waitForPackage(settingsPackageName)
sleep(500);
// 滚动到顶部
// scrollUp();
sleep(500);
scrollForward();
swipe(0,1000,0,800,100);
var ret = try_(function(){
//sleep(100);
// for(let i = 200;i<800;i+=10){
// sleep(8)
// swipe(i,800,i,1600,8)
// }
// gesture(2000,[200,800],[200,1500],[1000,1500],[1000,800],[200,800])
if(!click("锁屏", 0)) throw 1;
var b = text("锁屏").findOne().bounds();
click(b.centerX(), b.centerY());
}, interval*2, 9);
if(!ret) {toast("错误::锁屏");return;}
sleep(500);
var ret = try_(function(){
var b = className("android.widget.TextView").textContains("双击").findOne().bounds();
click(b.centerX(), b.centerY());
}, interval, 9);
if(!ret) {toast("错误::双击亮屏");return;}
toast("自动开完毕");
}
function try_(fun, _interval, theta){
while(--theta>0) try{
sleep(_interval);
fun();
return 1;
}catch(e){}
return 0;
}
// https://bjun.tech/blog/xphp/35
function auto_is(){
importClass("android.provider.Settings");
//获取已打开无障碍的服务列表
var check_auto;
let AccessibilityService = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
if(AccessibilityService){
//检测当前包名是否在已开启无障碍服务的列表中
check_auto = new RegExp((context.getPackageName()).replace('.','\\.')).test(AccessibilityService)
}else{
check_auto = false
}
return check_auto;
}
// https://blog.csdn.net/shuishen49/article/details/125283752
function auto_(){
if(!auto_is()) {
importClass("android.content.pm.PackageManager");
importClass("android.provider.Settings");
let mServices = ":"+context.getPackageName()+"/com.stardust.autojs.core.accessibility.AccessibilityService";
let enabledServices = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES).replace(new RegExp(mServices, "g"), "");
Settings.Secure.putString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
Settings.Secure.putString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices + mServices);
sleep(500);
auto();
sleep(500);
}
else sleep(100);
}
// 切换 熄屏提醒
function drive_1ui_xipingxianshi() {
auto_();
// 打开设置
var pak = app.getPackageName("设置");
if(pak.includes(".SettingsReceiver")) pak = "com.android.settings";
app.launchPackage(pak)
waitForPackage(pak)
scrollUp();
// 滚动到顶部
// scrollDown();
sleep(100)
swipe(device.width / 2, device.height/3-100 , device.width / 2, 0, 700);
sleep(100)
// 点击 锁定屏幕
var ret = try_(function(){
var b = text("锁定屏幕").findOne().bounds();
click(b.centerX(), b.centerY());
}, interval, 9);
if(!ret) {toast("错误::锁定屏幕");return;}
scrollUp();
// 点击 息屏提醒
var ret = try_(function(){
var b = text("息屏提醒").findOne().bounds();
click(b.centerX(), b.centerY());
}, interval, 9);
if(!ret) {toast("错误::锁定屏幕");return;}
var ret = try_(function(){
var b = (text("开").exists()?text("开").findOnce():text("关").findOne()).bounds();
// if(b.top<=0) b = text("关").findOne().bounds();
click(b.centerX(), b.centerY());
}, interval, 9);
if(!ret) {toast("错误::锁定屏幕");return;}
//home();
}
/**
* 开启代理(Android 9)
* @param proxy_ip
* @param proxy_port
*/
function open_android_9_handler(proxy_ip, proxy_port) {
// 检查无障碍
auto_();
// toast("1自动开启代理 " + proxy_ip + ":" + proxy_port);
// toast("点击 修改??" + (className("android.widget.TextView").textContains("WiFi").find().empty()));
// return
// 打开设置
var pak = app.getPackageName("设置");
if(pak.includes(".SettingsReceiver")) pak = "com.android.settings";
app.launchPackage(pak)
waitForPackage(pak)
// 滚动到顶部
scrollUp();
// 点击 连接
var ret = try_(function(){
var b = text("连接").findOne().bounds();
click(b.centerX(), b.centerY());
}, interval, 9);
if(!ret) {toast("错误::WLAN");return;}
// 点击 WLAN
//while(!click("WLAN", 0)) sleep(interval/2);
var ret = try_(function(){
var b = text("WLAN").findOne().bounds();
click(b.centerX(), b.centerY());
}, interval, 9);
if(!ret) {toast("错误::WLAN");return;}
//className("android.widget.TextView").descContains("网络详情").findOne().click();
// click("我的设备", 0);
// toast("点击 修改??" + className("android.widget.TextView").textContains("双卡与移动网x络").find().empty());
// className("android.widget.TextView").textContains("WLAN").findOne().parent().parent().click();
click("WLAN", 0);
// // 点击 WLAN
// while(!click("WLAN", 0));
sleep(interval);
toast("点击 修改??" + (className("android.view.View").textContains("网络详情").find().empty()));
// 点击 修改
// className("android.widget.ImageView").descContains("网络详情").findOne().click();
className("android.widget.ImageView").descContains("设置").findOne().click();
scrollDown();
swipe(device.width / 2, device.height-100 , device.width / 2, 0, 800);
// className("android.widget.ListView").findOne().scrollDown();
text("高级设置").findOne().click();
var ret = try_(function(){
var b = text("高级设置").findOne().bounds();
text("高级设置").findOne().parent().parent().click()
text("高级设置").findOne().parent().parent().parent().click()
text("高级设置").findOne().parent().parent().parent().parent().click()
// click(b.centerX(), b.centerY());
}, interval, 9);
if(!ret) {toast("错误::高级设置");return;}
scrollDown();
sleep(500);
var ret = try_(function(){
var b = text("代理服务器").findOne().bounds();
click(b.left+10, b.bottom+10);
sleep(interval/2);
click(proxy_ip?"手动":"无", 0);
}, interval, 5);
if(!ret) {toast("错误::代理设置--手动");return;}
scrollDown();
sleep(500);
scrollDown();
sleep(500);
if(proxy_ip) {
//设置ip、port
var ret = try_(function(){
var ets = className("EditText").find();
ets[0].setText("" + proxy_ip);
ets[1].setText("" + proxy_port);
//ets[1].setText("" + proxy_port);
}, interval, 5);
if(!ret) {toast("错误::设置ip、port");return;}
}
//sleep(parseInt(interval*1.25));
sleep(200);
// 点击 保存
var ret = try_(function(){
// var sel = descContains("确");
// var b = sel.findOne().bounds();
var b = text("保存").findOne().bounds();
click(b.centerX(), b.centerY());
}, interval, 5);
if(!ret) {toast("错误::点击 保存");return;}
// // 返回
home();
if(proxy_ip) toast("自动开启代理!!!");
else toast("代理已关闭 -- ");
}
/**
* 关闭代理(Android 9)
*/
function close_android_9_handler() {
open_android_9_handler();
}