校園一卡通余額自動(dòng)查詢提醒腳本

校園一卡通余額自動(dòng)查詢提醒腳本?
原文鏈接 https://sxdl.site/2023/08/02/202308021407/
背景
宿舍的水電費(fèi)在晚上23:30到3:30這一時(shí)間段內(nèi)是無(wú)法充值的,這就導(dǎo)致了經(jīng)常半夜欠費(fèi)停電??照{(diào)還無(wú)法充值的問(wèn)題。學(xué)校提供的水電余額查詢的唯一途徑是企業(yè)微信的應(yīng)用,且沒(méi)有自動(dòng)提醒的功能,因此自己開(kāi)發(fā)一個(gè)程序用來(lái)定時(shí)自動(dòng)查詢余額然后發(fā)送微信提醒。
由于查詢的 api 并不清楚,而且企業(yè)微信中的應(yīng)用都需要身份驗(yàn)證,實(shí)在太麻煩。想著先盡快把功能實(shí)現(xiàn),之后再考慮穩(wěn)定性和擴(kuò)展性,采用腳本的方式實(shí)現(xiàn)。
實(shí)現(xiàn)思路
設(shè)備選擇
水電費(fèi)查詢的入口都在企業(yè)微信中,而企業(yè)微信只有Windows和移動(dòng)客戶端,沒(méi)有Linux客戶端。如果要放在服務(wù)器上跑的話環(huán)境配置十分麻煩,因此考慮將腳本放在本地設(shè)備上跑。本地設(shè)備需要確保在指定的時(shí)間段內(nèi)保持開(kāi)機(jī)并不被使用,因?yàn)槟_本運(yùn)行的時(shí)候不能對(duì)設(shè)備頁(yè)面進(jìn)行操作(腳本是按照步驟順序運(yùn)行的,外界操作會(huì)干擾腳本運(yùn)行)。手頭目前的設(shè)備有:兩臺(tái)筆記本,一臺(tái)Windows,一臺(tái)Ubuntu,一個(gè)華為平板,一個(gè)華為手機(jī)。其中Windows筆記本日常經(jīng)常使用,另一臺(tái)用作學(xué)習(xí)折騰和本地Linux環(huán)境,不方便重新刷系統(tǒng),手機(jī)日常一直在用。平板倒是合適,一般從來(lái)不關(guān)機(jī),平常只是用來(lái)記筆記用。最后就決定使用平板,在平板上跑腳本。
腳本工具
安卓平臺(tái)上有個(gè)很不錯(cuò)的腳本工具,`Auto.js`,現(xiàn)在似乎已經(jīng)停止維護(hù)了,還能用的有 [AutoX.js](http://doc.autoxjs.com/#/) 和 [OpenAuto.js](https://openautojs.github.io/#/). 本著對(duì)開(kāi)源項(xiàng)目的偏好,我這里使用了 `OpenAuto.js`。
運(yùn)行流程
預(yù)先登錄企業(yè)微信和微信(用于消息提醒,可換用公眾號(hào)或其他),腳本首先打開(kāi)企業(yè)微信,找到查詢的服務(wù),查詢到余額后將余額通過(guò)微信發(fā)送到指定聊天對(duì)話中(個(gè)人或群聊)。
環(huán)境準(zhǔn)備
?華為平板(HarmonyOS 3.0)
OpenAuto.js
企業(yè)微信
微信
一鍵鎖屏(OpenAutojs沒(méi)有提供鎖屏的功能, 一鍵鎖屏通過(guò)應(yīng)用市場(chǎng)安裝)
編寫(xiě)腳本
由于不同的環(huán)境腳本會(huì)有差異,不放詳細(xì)代碼了,只寫(xiě)關(guān)鍵的幾個(gè)命令。詳細(xì)說(shuō)明查看[OpenAuto.js文檔](https://openautojs.github.io/#/)
自動(dòng)喚醒
用于從息屏狀態(tài)中喚醒屏幕,然后解鎖,注意必須沒(méi)有密碼,直接上滑解鎖的那種。
```javascript
device.wakeUp();
```
手勢(shì)
模擬上滑解鎖或屏幕下滑,嘗試使用過(guò) swipe() 但是并不好用。
```javascript
gestures([350, [500, 1600], [500, 300]]);? // 上滑
gestures([350, [500, 300], [500, 1600]]);? // 下滑
```
其中`350`這個(gè)位置的參數(shù)指持續(xù)時(shí)間(毫秒),后面兩個(gè)參數(shù)是起始點(diǎn)的坐標(biāo),默認(rèn)屏幕是1080x1920像素。
等待
參數(shù)等待時(shí)間(毫秒),如果腳本出現(xiàn)問(wèn)題,如某個(gè)控件找不到,可能是沒(méi)有設(shè)置sleep,等待頁(yè)面完全加載出來(lái)。
```javascript
sleep(1000);
```
控件點(diǎn)擊
嘗試了各種點(diǎn)擊方法,發(fā)現(xiàn)只有一種能用(不是我不會(huì)用,是真的就找不到控件),直接通過(guò)文字點(diǎn)擊控件。
```javascript
click("控件名稱")
```
啟動(dòng)程序
```javascript
var appName = "應(yīng)用名稱"
launchApp(appName);
sleep(3000);? // 記得添加以等待程序啟動(dòng)
```
OCR文字識(shí)別
先截圖(需要獲取權(quán)限,可以使用多線程自動(dòng)允許),然后OCR提取文字
```javascript
if(!requestScreenCapture()){? // 獲取截圖權(quán)限
? ? toast("請(qǐng)求截圖失敗");
? ? exit();
}
sleep(1000);
var img = captureScreen();
const stringList = paddle.ocrText(img, true);? // 識(shí)別到的文字列表
img.recycle();? // 回收?qǐng)D片,避免內(nèi)存泄漏
```
多線程
在截圖時(shí),需要應(yīng)用內(nèi)獲取權(quán)限,一般需要手動(dòng)授權(quán),也可以通過(guò)多線程自動(dòng)授權(quán)。
```javascript
threads.start(function(){
? ? sleep(1000);
? ? click("允許");
})
```
界面操作
一些基礎(chǔ)的界面操作
```javascript
home();? // 返回主菜單
sleep(1000);
back();? // 返回上一級(jí)
sleep(1000);
```
對(duì)話框輸入
輸入文本到當(dāng)前頁(yè)面中的對(duì)話框,用于微信發(fā)消息。
```javascript
input("message");
```
腳本調(diào)試
開(kāi)發(fā)過(guò)程中,可能需要顯示調(diào)試信息
```javascript
console.show();? // 顯示控制臺(tái)信息在應(yīng)用上層,需要開(kāi)啟權(quán)限
toastLog("日志信息");
console.log("另一種方法,效果相同")
```
腳本退出
```javascript
exit();
```
運(yùn)行腳本
首次運(yùn)行腳本需要開(kāi)啟應(yīng)用無(wú)障礙服務(wù)權(quán)限,點(diǎn)擊運(yùn)行即可。
設(shè)置定時(shí)任務(wù)
在 `OpenAuto.js` App 中可以設(shè)置腳本為定時(shí)任務(wù)。需要開(kāi)啟程序后臺(tái)運(yùn)行權(quán)限。
運(yùn)行效果

后續(xù)
用了一個(gè)晚上,目前是基本實(shí)現(xiàn)了主要功能,后面考慮做一些穩(wěn)定性和適用性的優(yōu)化,簡(jiǎn)單列個(gè)Todo:
更多提醒方式(郵件,公眾號(hào),企業(yè)微信)
腳本打包成apk,其他用戶可以開(kāi)包即用
將查詢結(jié)果發(fā)送到服務(wù)器上,服務(wù)器做一個(gè)余額變化統(tǒng)計(jì)