javascript
Auto.JS 开发
From:https://blog.csdn.net/a6892255/article/details/107302369
autojs 代碼大全(實(shí)戰(zhàn)演練):https://blog.csdn.net/qq_30931547/article/details/106459765
:https://github.com/snailuncle/autojsCommonFunctions/blob/master/autojsCommonFunctions.js8
確定要控件(唯一性),以下三個(gè)方法基本可滿足日常:
- ① depth-desc-id-classname等控件的常規(guī)的唯一屬性.
- ② findone.parent().child(xx)等控件的父子依存順序關(guān)系.
- ③ 最后實(shí)在無法確定可用坐標(biāo)法bounds,click(x,y)操作控件
?
autojs 一些問題解決的方案
怎么用其他按鍵強(qiáng)行停止腳本
events.onKeyDown("home", function (event) {//按home停止toast("程序結(jié)束")console.hide()threads.shutDownAll()})events.onKeyDown("volume_down", function (event) {//按音量下停止toast("程序結(jié)束")console.hide()threads.shutDownAll()})遇到 ui 堵塞怎么辦
解決方案,將 sleep 重寫為一個(gè)暫停的 function
function sleep(ms) {return new Promise(resolve => setTimeout(resolve, ms)); }如何方便的申請(qǐng)權(quán)限
function 權(quán)限申請(qǐng)() {if (!floaty.checkPermission()) {toast("請(qǐng)開啟懸浮窗和后臺(tái)彈出界面權(quán)限");floaty.requestPermission();return}if (auto.service == null) {toast("請(qǐng)開啟腳本的無障礙服務(wù)");auto.waitFor();return} } 權(quán)限申請(qǐng)();怎么運(yùn)行 engines.execScript(“運(yùn)行腳本名字”, Source);
var url = "http://源碼所在位置"//你要運(yùn)行的js云端源碼 var res = http.post(url, {}); var Source = res.body.string();//變量自己隨便寫就行 if (Source != "") {engines.execScript("運(yùn)行腳本名字", Source); } else {toast("似乎出了點(diǎn)問題,請(qǐng)聯(lián)系作者解決"); }無法安裝,報(bào)毒.沒有安裝的入口,怎么破
一般打開設(shè)置,打開安全與隱私關(guān)閉即可。
如果是vivo 去安全中心。把應(yīng)用加白名單即可。
為什么有時(shí)候 launchApp(‘應(yīng)用名’); 會(huì)失效
第一,這是因?yàn)槟闶謾C(jī)存在同名軟件.找不到你想要的app,要使用launch(‘應(yīng)用包名’)。第二,是因?yàn)槟銢]有給軟件(后臺(tái)彈出界面)權(quán)限
auto.waitFor();
語(yǔ)句增加是非常必要的這個(gè)在你沒有無障礙時(shí)候會(huì)提示你無障礙模式的開啟。并且開啟之后,會(huì)接著繼續(xù)運(yùn)行.
AutoJs創(chuàng)建項(xiàng)目后打包成Apk后Apk無法運(yùn)行
AutoJs單文件打包成Apk說是風(fēng)險(xiǎn)Apk。這個(gè)問題現(xiàn)在已經(jīng)比較好解決了.就是使用AUTO.JS Pro版本即可,破解版可以打包.
怎么黑屏跑腳本(省電)
原理很簡(jiǎn)單,就是去創(chuàng)建一個(gè)黑色的懸浮窗,在oled屏幕上,就不會(huì)發(fā)光,降低功耗.兼容任何腳本
function 息屏() {var h = confirm("是否要進(jìn)入息屏掛機(jī)模式嗎?可按下音量上鍵停止輔助。并不能鎖定屏幕!!!通知欄會(huì)正常顯示(oled屏可用)");if (h) {var w = floaty.rawWindow(<frame gravity="center" bg="#000000" />);w.setSize(-1, -1);w.setTouchable(true);//保持腳本運(yùn)行setInterval(() => { }, 1000);} } 息屏()按 F5 之后不是運(yùn)行腳本, 而是出現(xiàn)調(diào)試 Node.js
解決方案如下
?然后刪除除了 autojs 運(yùn)行外的 F5 快捷鍵
如何打開控制臺(tái)
幫助 -----> 切換開發(fā)者工具 ------>?console
一、基礎(chǔ)知識(shí)和使用方法
1.1 基本常識(shí)
Auto.JS作為一款基于JavaScript語(yǔ)言的一款腳本,基本語(yǔ)法和結(jié)構(gòu)可通過學(xué)習(xí)JavaScript來了解。要知道,安卓的app界面就是由一堆控件組成的,這些父子控件相互嵌套,組成了我們熟悉的app界面,因此,你要執(zhí)行自動(dòng)化操作,那么最常用的就是先精確的找到這個(gè)控件(唯一性),再來說下一步對(duì)其進(jìn)行操作,而我個(gè)人認(rèn)為Auto.JS之所以方便好用,最大的一點(diǎn)就是查找你想要操作的控件(包括但不限于點(diǎn)擊、設(shè)置文本等)時(shí)特別方便明了,一眼就能看懂并能迅速定位。
比如,在Auto.JS懸浮窗點(diǎn)擊[探測(cè)]按鈕(圖1.1),選擇[布局范圍分析],之后Auto.JS會(huì)自動(dòng)分析當(dāng)前范圍界面的控件組成,在分析探測(cè)完成后(圖1.2),可以點(diǎn)擊[查看控件信息]來查看想要操作的控件的各種屬性,控件最基本也最常見的屬性有:
- id(“XXX”),
- className(“XXX”),
- depth(xx),
- text(“XXX”),
- desc(“XXX”)
?
?
?
??在這里以右上角的【?】按鈕為例,我想要點(diǎn)擊它,那么先查看其控件屬性(圖1.3),如其所示,在該控件的諸多屬性里,有此控件的bounds(),id(),className(),depth(),desc()等(圖1.4),這就是該按鈕所有的特性,同樣的,其他控件也同此控件一樣,具有這些屬性,我們要利用Auto.JS執(zhí)行自動(dòng)化操作,核心無非就是利用各種方法先找到這個(gè)控件,其次再操作這個(gè)控件。因此,學(xué)習(xí)Auto.JS的基礎(chǔ)部分就是學(xué)習(xí)如何唯一的確定想要操作的控件。
1.2 基于控件屬性確定控件
通過查看這些屬性,我們不難發(fā)現(xiàn)有其中一項(xiàng)屬性desc("更多選項(xiàng)"),很可能是不和其他控件相同的,也就是此控件屬性具有唯一性,能唯一的確定此控件,這個(gè)屬性就是我們要找的。因此,我們想要對(duì)其進(jìn)行操作只需要:
if (desc("更多選項(xiàng)").exists()) {sleep(1000);desc("更多選項(xiàng)").findonce().click(); }上述代碼執(zhí)行后,在該界面時(shí),desc("更多選項(xiàng)")首先會(huì)被查找(findonce),查找后執(zhí)行點(diǎn)擊(click),從而【?】按鈕也就被點(diǎn)擊了。總結(jié)下無非就是我們找到了此按鈕的唯一控件屬性desc("更多選項(xiàng)")從而再對(duì)其操作,僅此而已。
另外,加上“.exist()”是為了增加程序魯棒性,萬一控件不存在或者沒找到,則程序不會(huì)執(zhí)行,否則對(duì)不存在(或沒找到)的控件操作會(huì)拋出異常。基于此,往往要判定控件存在與否后再進(jìn)行操作,而“.exist()”返回的是一個(gè)布爾值,方便后續(xù)進(jìn)行判斷和操作。另外一個(gè)常用的操作就是加上“while(!)”死循環(huán)等待控件出現(xiàn),如:
//當(dāng)"更多選項(xiàng)"不存在等價(jià)于此按鈕還沒出現(xiàn) while (!desc("更多選項(xiàng)").exists()) {//繼續(xù)循環(huán)等待,直到按鈕出現(xiàn)sleep(1000); }//執(zhí)行到這里說明"更多選項(xiàng)"存在了,對(duì)該按鈕執(zhí)行點(diǎn)擊操作 desc("更多選項(xiàng)").findonce().click(); return;當(dāng)分析了很多控件后不難發(fā)現(xiàn),控件的文本信息往往是以desc或text屬性來呈現(xiàn)的,比如一個(gè)該按鈕名為"更多選項(xiàng)",其控件的desc屬性或text屬性就是其按鈕名字,確定其名字也就確定了此控件,針對(duì)此按鈕具體來說,就是其desc屬性是"更多選項(xiàng)"。(此處要說的意思就是要具體問題具體分析,文本信息不是desc就是text,如果是desc屬性就操作desc,是text屬性就操作text)但是,往往就有時(shí)候我們只知道包含的部分desc或text,這時(shí)候可用這四個(gè)函數(shù)來確定:
//descContains即desc包含部分信息即可匹配 if (descContains("選項(xiàng)").exists()) {//需要執(zhí)行的操作 }//descStartsWith即desc以此信息開頭即可匹配 if (descStartsWith("更多").exists()) {//需要執(zhí)行的操作 }///同理,text也有對(duì)應(yīng)的兩個(gè)函數(shù),比如一個(gè)按鈕text屬性為("我的學(xué)習(xí)積分")///textContains即text包含部分信息即可匹配 if (textContains("學(xué)習(xí)積分").exists()) {//需要執(zhí)行的操作 }//textStartsWith即text以此信息開頭即可匹配 if (textStartsWith("我的").exists()) {//需要執(zhí)行的操作 }當(dāng)然,更多情況是desc和text屬性并不能唯一確定要操作的控件,我們往往用其他屬性(常用的有className、id、depth等)一起疊加使用來盡可能的使之唯一,比如:
//往往是諸多控件屬性一起才可唯一確定待操作的控件 var myObject = className(“XXX”).depth(xx).id(“XXX”).text(“XXX”).findone(); myObject.click();?需要注意的是:在不同的Android系統(tǒng)上,同一版本的app的控件屬性可能會(huì)變化。同樣,app版本更新后,控件屬性、布局也可能發(fā)生變化,所以,若要對(duì)不同版本不同系統(tǒng)具有兼容性,應(yīng)盡可能選擇不變化的控件屬性。
1.3 基于控件父子關(guān)系確定控件
? ? ? ? 有時(shí)候,控件屬性是變化的、隨機(jī)的,這時(shí)候我們便不能通過控件的本身固有屬性如 id,className,depth?等來唯一的確定出需要的控件,這時(shí)候我們可以通過控件之間的上下級(jí)關(guān)系(也叫父子關(guān)系)來確定出需要操作的控件。
? ? ? ? 首先需要了解的是控件間的依存關(guān)系,還是以之前的 app 界面為例,我們這次來分析右下角的的 “+” 號(hào)按鈕,和之前一樣利用Auto.JS分析控件布局,我們點(diǎn)擊右下角的 “+” 號(hào)按鈕,點(diǎn)擊 [在布局層次中查看] ,便可以查看當(dāng)前控件在整個(gè)布局層次中的上下級(jí)關(guān)系(父子關(guān)系),如圖1.6所示,不難發(fā)現(xiàn),從上到下,左側(cè)五顏六色的 豎棍丨就代表著其層級(jí)關(guān)系,豎棍丨越多也就越處于底層,該 “+” 號(hào)按鈕控件名為 “ImageButton”,對(duì)應(yīng)著擁有 8根豎棍丨,所以其是在 第八級(jí)。
另外,和 “ImageButton” 平級(jí)的控件是圖1.6所示的8.2—“ImageView”控件,“ImageButton” 的父控件也就是它的上級(jí)控件是圖1.6所示的7.3—“android.view.View”控件,所以我們可以建立以下關(guān)系:
8.1中 "ImageButton" 的 parent() = 7.3中 "android.view.View"7.3中 "android.view.View" 的child(0) = 8.1中 "ImageButton"7.3中 "android.view.View" 的child(1) = 8.2中 "ImageView"7.3中 "android.view.View" 的parent() = 6 中 "android.view.View"6 中 "android.view.View" 的child(0) = 7.1中 "LinearLayout"6 中 "android.view.View" 的child(1) = 7.2中 "android.view.View"6 中 "android.view.View" 的child(2) = 7.3中 "android.view.View"?建立了以上隸屬關(guān)系,我們就可以通過唯一確定任意其中一個(gè)不變的固定控件,便可通過控件間的隸屬關(guān)系來確定我們想要的控件,從而規(guī)避了我們要找的控件屬性動(dòng)態(tài)變化這一情況。
?
?在這里,我們假定以之前右上角的【?】按鈕為固定控件(因?yàn)?#34;更多選項(xiàng)"這幾個(gè)字基本不會(huì)變化),通過【?】按鈕來和控件間的父子關(guān)系來確定出右下角的“+”號(hào)按鈕。
首先分析右上角的【?】按鈕的層級(jí)關(guān)系,如圖1.7所示,【?】按鈕位于第10級(jí),它的父級(jí)parent是圖1.7所示的9.3—“android.support.v7.widget.LinearLayoutCompat”,9.3的父級(jí)是8—“android.view.View”,以此類推,發(fā)現(xiàn)我們想要操作的控件也就是“ImageButton”控件(8.1)和右上角的【?】按鈕即“ImageView”控件(10)關(guān)系是:
"ImageView"控件(10)是從7.1—"LinearLayout"繼承下來的;"ImageButton"控件(8.1)是從7.3—"android.view.View"繼承下來的;而7.1和7.3是平級(jí)關(guān)系,擁有共同的父級(jí)6—"android.view.View"?明白了這一點(diǎn),我們便可通過【?】按鈕(10)來確定右下角的“+”號(hào)按鈕(8.1),如下所示:
//首先,通過desc屬性確定出【?】按鈕(圖1.7所示的10) //屬性.findone()首先找到一個(gè)控件,再在此基礎(chǔ)上加.parent等 var moreButton = desc("更多選項(xiàng)").findone();//其次,找到【?】按鈕和右下角“+”號(hào)按鈕共同的父級(jí)parent //在這里是一層層往上找是為了方便理解,實(shí)際操作可一步到位 var 9_3Supportv7 = moreButton.parent(); //找到圖1.7所示的9.3控件 var 8viewView = moreButton.parent().parent(); //找到圖1.7所示的8控件 var 7_1LinearLayout = moreButton.parent().parent().parent(); //找到圖1.7所示的7.1控件 var 6viewView = moreButton.parent().parent().parent().parent(); //找到圖1.7所示的6控件//最后,通過共同的父級(jí)parent找到右下角“+”號(hào)按鈕 //在這里是一層層往下找是為了方便理解,實(shí)際操作可一步到位 var 7_3viewView = 6viewView.child(2); //找到圖1.7所示的7.3控件 var plusButton = 6viewView.child(2).child(0); //找到圖1.7所示的8.1控件(也就是+號(hào)按鈕)//所以,如果一步到位,總結(jié)如下: var plusButton = moreButton.parent().parent().parent().parent().child(2).child(0); //再對(duì)+號(hào)按鈕進(jìn)行點(diǎn)擊 plusButton.click();?此處例子里的的兩個(gè)控件【?】按鈕(10)和右下角的“+”號(hào)按鈕(8.1)之間相差了很多層,因此顯著有些復(fù)雜,在實(shí)際情況中,我們往往不需要跨越這么多的層級(jí)來確定控件,一般情況下不會(huì)那么復(fù)雜。實(shí)際上,父子關(guān)系嵌套兩三層往往即可確定出另一控件。最后,在這里需要注意的是,確定控件時(shí)要加上“.findone()”,此方法調(diào)用后會(huì)返回所有符合條件的控件集合。因此,首先要找到一個(gè)不容易變化的或容易找的控件“.findone()”后再在此基礎(chǔ)上進(jìn)行“.parent()”“.child(index)”操作找到另一控件。
1.4 基于坐標(biāo)來確定控件
如果一個(gè)控件本身無法通過click()點(diǎn)擊,那么我們可以利用bounds()函數(shù)獲取其坐標(biāo),再利用坐標(biāo)點(diǎn)擊。總體來說,基于坐標(biāo)來確定要操作的控件比較簡(jiǎn)單,核心是確定要操作的控件的坐標(biāo)即可。Auto.JS里可以直接獲取控件的坐標(biāo),每一個(gè)控件包含其“.bounds()”屬性,bounds()其實(shí)表示的是一個(gè)范圍矩陣。此處還是以右下角的“+”號(hào)按鈕為例,查看控件屬性信息,包含“.bounds()”屬性。
?從上圖看,bounds()屬性是四個(gè)坐標(biāo)值,其分別為(left, top, right, buttom),各值含義如圖1.9所示:
left:控件左邊緣與屏幕左邊的距離top:控件上邊緣與屏幕上邊的距離right:控件右邊緣與屏幕左邊的距離buttom : 控件下邊緣與屏幕上邊的距離因此,在獲得控件的坐標(biāo)bounds()屬性后,就可以對(duì)控件執(zhí)行基于坐標(biāo)的操作,常見的操作有:?
bounds().left: 長(zhǎng)方形左邊界的x坐標(biāo) bounds().right: 長(zhǎng)方形右邊界的x坐標(biāo) bounds().top: 長(zhǎng)方形上邊界的y坐標(biāo) bounds().bottom:長(zhǎng)方形下邊界的y坐標(biāo) bounds().centerX():長(zhǎng)方形中點(diǎn)x坐標(biāo) bounds().centerY():長(zhǎng)方形中點(diǎn)y坐標(biāo) bounds().width(): 長(zhǎng)方形寬度也就是控件寬度 bounds().height(): 長(zhǎng)方形高度也就是控件高度 click(x,y):坐標(biāo)(x,y)處執(zhí)行點(diǎn)擊操作 //注意:安卓7以下點(diǎn)擊需要root權(quán)限且函數(shù)為Tap(x,y) bounds(left, right, top, bottom).clickable().click():點(diǎn)擊該長(zhǎng)方形區(qū)域另外,因?yàn)椴煌O(shè)備的分辨率大小是不同的,那么我們click(x,y)在不同分辨率下就會(huì)出錯(cuò),Auto.JS針對(duì)這一問題內(nèi)置了一個(gè)函數(shù)"setScreenMetrics(width, height)",具體用法如下:
//設(shè)置在特定屏幕分辨率下要點(diǎn)擊的坐標(biāo)值(x,y) setScreenMetrics(1080, 1920); //聲明是基于分辨率1080,1920的點(diǎn)擊 click(800, 200); //分辨率1080,1920下點(diǎn)擊(800,200) longClick(300, 500); //分辨率1080,1920下長(zhǎng)點(diǎn)擊(300,500)? ?當(dāng)我們使用540,960分辨率的設(shè)備(x,y各縮小了一半)后執(zhí)行上述代碼時(shí),他會(huì)自動(dòng)計(jì)算縮放的比例,從而實(shí)際點(diǎn)擊的是坐標(biāo)(400,100)和(150,250)這兩個(gè)坐標(biāo)值。
當(dāng)然,基于坐標(biāo)的操作不僅有click()操作,常用的還有swipe()滑動(dòng)操作,gesture()手勢(shì)滑動(dòng)操作等,具體可查看官方文檔,在這里僅對(duì)swipe(),gesture()這兩個(gè)函數(shù)進(jìn)行介紹。
?
下面以一個(gè)某APP注冊(cè)時(shí)的滑動(dòng)驗(yàn)證為例(為防止被人惡意利用,在此打上碼。再次聲明,此處做僅舉例用,所有代碼僅供學(xué)習(xí)交流!),如圖2.0所示,當(dāng)我們輸入手機(jī)號(hào)點(diǎn)擊注冊(cè)時(shí),此時(shí)需要將滑塊拖動(dòng)到指定位置處才可以發(fā)送驗(yàn)證碼從而進(jìn)行下一步的注冊(cè)。在這里,我們將想要拖動(dòng)的滑塊稱為控件①,想要拖到的目標(biāo)處稱為控件②。那么,如果想要實(shí)現(xiàn)一個(gè)自動(dòng)化拖動(dòng)首先就要確定的是控件①和控件②的坐標(biāo),又因?yàn)槠渥鴺?biāo)每次都是隨機(jī)的,所以只需要根據(jù)兩個(gè)控件的特有屬性唯一確定出控件①和控件②,再每次獲取其坐標(biāo)即可。
通過對(duì)兩個(gè)控件的屬性分析,如圖2.1所示,我們不難發(fā)現(xiàn),控件①和控件②的indexInParent()不同,因此可通過此分別唯一的定位出兩個(gè)控件,確定控件后,我們?cè)僬{(diào)用swipe()或gesture()函來執(zhí)行滑動(dòng),從而實(shí)現(xiàn)自動(dòng)滑動(dòng)的操作。
?具體實(shí)現(xiàn)代碼如下:
//首先判斷是否進(jìn)入了"滑動(dòng)驗(yàn)證"界面 if (text("滑動(dòng)驗(yàn)證").exists()) {sleep(2000);//判斷控件1是否存在if (className("android.widget.Button").depth(8).indexInParent(1).exists()) {//控件1存在,獲取其坐標(biāo)bounds()屬性var Button1 = className("android.widget.Button").depth(8).indexInParent(1).findOne().bounds();sleep(500);console.log("Button1的坐標(biāo)為:" + Button1);}//判斷控件2是否存在if (className("android.widget.Button").depth(8).indexInParent(3).exists()) {var Button2 = className("android.widget.Button").depth(8).indexInParent(3).findOne().bounds();sleep(500);console.log("Button2的坐標(biāo)為:" + Button2);}//兩個(gè)控件的坐標(biāo)都獲取到后,執(zhí)行swipe或gesture操作sleep(2000);//swipe(x1,y1,x2,y2,[time])swipe(Button1.left, Button1.top, Button2.left, Button2.top, [random(500, 1200)]);sleep(2000);//gesture(time,[x1,y1],[x2,y2])console.log("Swipe完成!");gesture(random(500, 1200), [Button1.left, Button1.top], [Button2.left, Button2.top]);console.log("gesture完成!");//結(jié)束 }二、其他的一些方法和函數(shù)
2.1 點(diǎn)擊 click 的一些說明
click是點(diǎn)擊操作,實(shí)際上,使用click函數(shù)我們可以對(duì)坐標(biāo)進(jìn)行點(diǎn)擊,也可以對(duì)控件進(jìn)行點(diǎn)擊,最后也可以對(duì)某些特定字符點(diǎn)擊,總結(jié)如下:
//一:根據(jù)控件屬性唯一確定出控件后,再對(duì)控件進(jìn)行點(diǎn)擊click操作 desc("更多選項(xiàng)").depth(9).findone().click(); text("注冊(cè)").click();//二:根據(jù)坐標(biāo)來實(shí)現(xiàn)基于坐標(biāo)的點(diǎn)擊 setScreenMetrics(1080, 1920); // 聲明是基于分辨率1080,1920的點(diǎn)擊 click(800, 200); // 分辨率1080,1920下點(diǎn)擊(800,200)//三:有時(shí)候控件可能是個(gè)Image或是不可點(diǎn)擊的(clickable=false),這時(shí)我們可以對(duì)屏幕進(jìn)行點(diǎn)擊 click("2020-07-15"); // 點(diǎn)擊"2020-07-15" click("2020-07-15", 0); // 點(diǎn)擊第一個(gè)"2020-07-15" click("str", index); // 點(diǎn)擊第index個(gè)字符"str"(因?yàn)橛袝r(shí)str會(huì)出現(xiàn)多次,另外注意下標(biāo)從0開始)2.2 查找函數(shù) find、findone、findonce
之前說過,根據(jù)我們?cè)O(shè)定的一些屬性,我們可以對(duì)屏幕上的控件進(jìn)行搜索和查找,并返回符合條件的控件。因此,想要對(duì)返回的控件進(jìn)行下一步操作的前提是必須要“.findone()”,如前面所述,要想從父子關(guān)系查找關(guān)聯(lián)控件必須先“.findone().parent()”,再比如要想獲取控件的坐標(biāo)矩陣也必須“.findone().bounds()”。三個(gè)搜索函數(shù)“.find()” “.findone()” “.findonce()”在使用上是有點(diǎn)差別的,具體如下:
//find()函數(shù)會(huì)找出所有滿足條件的控件并返回一個(gè)控件集合,之后可以對(duì)控件集合進(jìn)行操作 var findAssemble = textContains("2020-07-15").find(); //找到所有包含"2020-07-15"的控件集合findAssemble //findone()函數(shù)會(huì)對(duì)屏幕上的控件進(jìn)行搜索,直到屏幕上出現(xiàn)滿足條件的一個(gè)控件為止,并返回該控件 //如果找不到控件,當(dāng)屏幕內(nèi)容發(fā)生變化時(shí)會(huì)重新尋找,直至找到 //注意:如果findone不加限制時(shí)間且屏幕上一直沒有出現(xiàn)所描述的控件,則該函數(shù)會(huì)阻塞,直到找到為止 var findoneAssem1 = textContains("2020-07-15").findone(); //找到一個(gè)包含"2020-07-15"的控件findoneAssem1 var findoneAssem2 = textContains("2020-07-15").findone(500); //在500毫秒內(nèi)找到一個(gè)包含"2020-07-15"的控件findoneAssem,若找不到,終止搜索返回null//findonce(i)函數(shù)會(huì)根據(jù)當(dāng)前所確定的篩選條件,對(duì)屏幕上的控件進(jìn)行搜索,并返回第 i + 1 個(gè)符合條件的控件 //如果沒有找到符合條件的控件,或者符合條件的控件個(gè)數(shù) < i, 則返回null var findonce1 = textContains("2020-07-15").findonce(0); //搜索第一個(gè)包含"2020-07-15"的控件findonce1 var findonce2 = textContains("2020-07-15").findonce(1); //搜索第二個(gè)包含"2020-07-15"的控件findonce22.3 上下滑動(dòng)和翻頁(yè)
Auto.JS上下滑動(dòng)可以是對(duì)整個(gè)屏幕的滑動(dòng)或?qū)δ程囟丶幕瑒?dòng),對(duì)整個(gè)屏幕滑動(dòng)如下例2.3.1所示:
//滑動(dòng)函數(shù)swipe(x1,y1,x2,y2,time) var h = device.height; //屏幕高 var w = device.width; //屏幕寬 var x = (w / 3) * 2; //橫坐標(biāo)2分之3處 var h1 = (h / 6) * 5; //縱坐標(biāo)6分之5處 var h2 = (h / 6); //縱坐標(biāo)6分之1處swipe(x, h1, x, h2, 500); //向下翻頁(yè)(從縱坐標(biāo)6分之5處拖到縱坐標(biāo)6分之1處) swipe(x, h2, x, h1, 500); //向上翻頁(yè)(從縱坐標(biāo)6分之1處拖到縱坐標(biāo)6分之5處)在很多時(shí)候,我們經(jīng)常會(huì)見到className名為“.ListView”的控件,實(shí)際上其往往是充當(dāng)裝在很多list的集合,以此控件為例,我們可以實(shí)現(xiàn)對(duì)此控件的上下滑動(dòng),如下例2.3.2所示:
// scrollForward()函數(shù)會(huì)對(duì)控件執(zhí)行向前滑動(dòng)的操作,并返回是否操作成功 // scrollBackward()函數(shù)會(huì)對(duì)控件執(zhí)行向后滑動(dòng)的操作,并返回是否操作成功 var listView = ClassName(“ListView”).id(XXX).findone(); ListView.scrollForward(); // 向前滑動(dòng) ListView.scrollBackward(); // 向后滑動(dòng)?在此只是以“.ListView”的控件進(jìn)行舉例,實(shí)際使用過程中,只要控件是可上下滑動(dòng)的,都可以調(diào)用函數(shù)“scrollForward()”和“scrollBackward()”來實(shí)現(xiàn)對(duì)控件的滑動(dòng)操作。
2.4 其他通用函數(shù)和全局函數(shù)
因?yàn)锳uto.JS是基于JavaScript的語(yǔ)言,因此基本的語(yǔ)法結(jié)構(gòu)、很多兩者通用的函數(shù)等都是可以在JavaScript里面找到,如常見的“.replace()”“.indexof()”“.test()”等這些都在JavaScript網(wǎng)站上有相關(guān)的用法說明。可見:JavaScript學(xué)習(xí):JavaScript 正則表達(dá)式 | 菜鳥教程
另外,Auto.JS的一些全局函數(shù)如啟動(dòng)程序函數(shù)“l(fā)aunch(“XXX”)”,控制臺(tái)的函數(shù)如“console.show()”、“console.log()”等,再如返回函數(shù)“back()”,隨機(jī)函數(shù)“random(start,end)”等這些都可在官方的提取文檔里找到。可見:Auto.JS官方提取文檔:【Auto.JS】Autojs官方提取文檔使用說明函數(shù) (1)_小宋小宋-CSDN博客
1. 對(duì)于文本設(shè)置函數(shù)“.setText(index,文本內(nèi)容)”,如果index沒有,則默認(rèn)是在當(dāng)前頁(yè)面找所有文本框中填入“文本內(nèi)容”。
2. 函數(shù)“.split("")”可用于分割字符串,比如文本“我愛你中國(guó)”會(huì)被分成“我”“愛”“你”“中”“國(guó)”,可以用在取隨機(jī)姓名時(shí)百家姓的分割。
3.有些控件的“.clickable()”屬性是為false的,這意味著你進(jìn)行click()點(diǎn)擊操作會(huì)返回false失敗,因此,在對(duì)控件操作時(shí)要注意查看其“.clickable()”屬性,如果其不可點(diǎn)擊,我們可用一些屏幕點(diǎn)擊或坐標(biāo)點(diǎn)擊的方法來對(duì)其進(jìn)行點(diǎn)擊。
Auto.js 一些高級(jí)用法
判斷打開應(yīng)用失敗,未安裝
打開應(yīng)用("微信") function 打開應(yīng)用(應(yīng)用名) {if (getPackageName(應(yīng)用名) != null) {app.launchApp(應(yīng)用名);toastLog("打開成功")} else {alert("溫馨提示", "請(qǐng)下載安裝" + 應(yīng)用名);console.log("請(qǐng)下載安裝" + 應(yīng)用名);console.hide();console.log("關(guān)閉控制臺(tái)");console.log("停止" + 應(yīng)用名 + "腳本");exit();} }在線更新,在線強(qiáng)制更新
function 版本更新() {var 當(dāng)前版本號(hào) = app.versionName, 新版本號(hào)var url = "驗(yàn)證網(wǎng)址"var res = http.get(url)res = res.body.string()新版本號(hào) = res.substr(0, 5)//截取字符,前面5位作為版本號(hào)對(duì)比log("當(dāng)前版本號(hào): " + 當(dāng)前版本號(hào))log("最新版本號(hào): " + 新版本號(hào))var 更新信息 = res.substr(5)//截取字符,第5位以后的作為公告log(更新信息)if (新版本號(hào) != 當(dāng)前版本號(hào)) {toastLog(更新信息)//自己在這里添加其他功能//returnexit()} else {log("當(dāng)前是最新版本!!!")} } 版本更新()判斷本腳本是否重復(fù)運(yùn)行
my_count = 0; ne = engines.myEngine(); my_path = ne.mTags.get("execute_path") + "/" + ne.source; engines.all().forEach(e => {path = e.mTags.get("execute_path") + "/" + e.source;if (path == my_path) my_count++; }); if (my_count > 1) toast("本腳本重復(fù)運(yùn)行");在坐標(biāo)位置顯示一個(gè)十字架,提示2秒后關(guān)閉,方便調(diào)試
function showXyTap(x, y) {var xy = floaty.window(<frame gravity="center" w="30" h="30" alpha="0.6"><View w="2" h="30" bg="#ff00e4"></View><View w="30" h="2" bg="#00ff42"></View></frame>);xy.setPosition(Math.abs(x - 15), Math.abs(y - 15));setTimeout(() => {xy.close();}, 2000); }監(jiān)控腳本是否卡在某界面不動(dòng),發(fā)現(xiàn)此情況重啟腳本
function Observer() {function unique(arr) {let newArr = [arr[0]];for (let i = 1; i < arr.length; i++) {let flag = false;for (var j = 0; j < newArr.length; j++) {if (arr[i] == newArr[j]) {flag = true;break;}}if (!flag) {newArr.push(arr[i]);}}return newArr;}currentActis = new Array();for (let c = 0; c < 100; c++) {sleep(500);currentActis[c] = currentActivity();}ac = unique(currentActis);if (ac.length == 1) {return false}return true }// 》》》》》》》》》》》》》》》》》》》 START work_thread = threads.start(function () {Main(); });observer_thread = threads.start(function () {while (true) {sleep(5000);if (!Observer()) {work_thread.interrupt();work_thread = threads.start(function () {console.setPosition(device.width / 2, device.height / 1.5);console.show();console.warn("Main線程在5秒后重啟!");sleep(5000);console.hide();Main();});}} });兼容安卓7.0以上與6.0以下的點(diǎn)擊,6.0需要root
function clickHelper2(x, y) {showXyTap(x, y);if (IS_GT_SDK23) {click(x, y);} else {try {// 容易出毛病,toomanyevenliserExceptionTap(x, y);runtime.sleep(1000);} catch (e) {try {if (!ra) {ra = new RootAutomator();}// 保險(xiǎn)點(diǎn)擊ra.tap(x, y, 1);runtime.sleep(800);// ra.press(x, y, 10, 1);} catch (e) {ErrorHandle("在此設(shè)備上需要Root權(quán)限才能運(yùn)行本腳本!", true);}}} }跳轉(zhuǎn) 到 添加QQ
app.startActivity({action: "android.intent.action.VIEW",data: "mqqapi://car/show_pslcard?&uin=542999277" })加群,加qq的彈窗
//測(cè)試寫法qq,qq群 聯(lián)系(1906507927, 553908361) function 聯(lián)系(QQ, QQ群) {var Q群 = QQ群var isFold = false,isRunning = false,isRotate = null;function sjcl() {let d = ["red", "green", "blue", "purple"]let y = random(0, 3)return d[y]}var ys = sjcl();var h = device.height;var w = device.width;dialogs.build({title: "歡迎加入更多項(xiàng)目群",titleColor: ys,content: "作者QQ:" + QQ + "\nautojs交流群:" + Q群,contentColor: ys,cancelable: true,positive: "加入Q群",positiveColor: ys,neutral: "取消",neutralColor: ys,negative: "聯(lián)系作者",negativeColor: ys}).on("positive", () => {app.startActivity({action: "android.intent.action.VIEW",data: "mqqapi://card/show_pslcard?card_type=group&uin=" + Q群,packageName: "com.tencent.mobileqq",});toast("加入Q群")}).on("negative", () => {app.startActivity({action: "android.intent.action.VIEW",data: "mqqapi://card/show_pslcard?uin=" + QQ,packageName: "com.tencent.mobileqq",})toast("聯(lián)系作者")}).on("neutral", () => {//取消鍵toast("返回")}).show(); }提醒開啟無障礙服務(wù)
ui.autoService.on("check", function (checked) {// 用戶勾選無障礙服務(wù)的選項(xiàng)時(shí),跳轉(zhuǎn)到頁(yè)面讓用戶去開啟if (checked && auto.service == null) {app.startActivity({action: "android.settings.ACCESSIBILITY_SETTINGS"});}if (!checked && auto.service != null) {auto.service.disableSelf();} });跳轉(zhuǎn)到開啟懸浮窗
(在其它應(yīng)用窗口上顯示,貌似要先設(shè)置一下無障礙,才能成功跳這個(gè))
int = app.startActivity({packageName: "com.android.settings",className: "com.android.settings.Settings$AppDrawOverlaySettingsActivity",data: "package:" + auto.service.getPackageName().toString() });結(jié)束 autojs
var nowPid = android.os.Process.myPid(); var am = context.getSystemService(java.lang.Class.forName("android.app.ActivityManager")); var list = am.getRunningAppProcesses(); for (var i = 0; i < list.size(); i++) {var info = list.get(i)if (info.pid != nowPid) {kill(info.pid);} } kill(nowPid); function kill(pid) {android.os.Process.killProcess(pid); }base64 加密和解密
function FuckYourFamily(str) {return java.lang.String(android.util.Base64.decode(java.lang.String(str).getBytes(), 0)); } //調(diào)用方式,直接 FuckYourFamily(str) 即可,其中str為base64加密適配安卓5到9.如果有root,會(huì)用root點(diǎn)擊或者滑動(dòng).
function 滑動(dòng)(x1, y1, x2, y2, time) {if (device.sdkInt < 24) {Swipe(x1, y1, x2, y2, time)} else {swipe(x1, y1, x2, y2, time)} } function 點(diǎn)擊(x, y) {if (device.sdkInt < 24) {Tap(x, y)} else {click(x, y)} } function home() {if (device.sdkInt < 24) {Home()} else {home()} } function back() {if (device.sdkInt < 24) {Back()} else {back()} }/** * 不能點(diǎn)擊的控件,通過坐標(biāo)點(diǎn)擊 * @param {*} uiSelector */
function clickUiBounds(ui) {if (ui.exists()) {var a = ui.findOnce();if (a) {var b = a.bounds();if (b) {click(b.centerX(), b.centerY());return true;}}}return false; }配置讀寫
function 寫配置(文件名, 鍵, 值) {const storage = storages.create(文件名);storage.put(鍵, 值); } function 讀配置(文件名, 鍵, 默認(rèn)值) {const storage = storages.create(文件名);if (storage.contains(鍵)) {return storage.get(鍵, 默認(rèn)值);};寫配置(文件名, 鍵, 默認(rèn)值);return 默認(rèn)值; }文本操作
function 到文本(數(shù)值) {return 數(shù)值 + "" }function 到整數(shù)(文本) {return 文本 * 1 }function 隨機(jī)數(shù)(min, max) {return Math.floor(Math.random() * (max - min + 1)) + min } //log(隨機(jī)數(shù)(1,5))function 子文本替換(原始文本, 欲被替換的文本, 用作替換的文本) {return 原始文本.replace(eval("/" + 欲被替換的文本 + "/g"), 用作替換的文本) } log(子文本替換("1234567890", "123", "qwe")) function 取文本中間(str, firstStr, secondStr) //字符串,開頭,結(jié)尾 {if (firstStr == "") { str = "**" + str; firstStr = "**" }if (secondStr == "") { str = str + "**"; secondStr = "**" }if (str == "" || str == null || str == undefined) {return "";}if (str.indexOf(firstStr) < 0) {return "";}var subFirstStr = str.substring(str.indexOf(firstStr) + firstStr.length, str.length);var subSecondStr = subFirstStr.substring(0, subFirstStr.indexOf(secondStr));return subSecondStr; }判斷系統(tǒng)是否 ROOT
function isRoot() {var r = shell("ls /system/bin", true).result.toString()if (r.length > 50) {return true} else {return false} }判斷網(wǎng)絡(luò)狀態(tài)
function networkInfo() {importClass(android.net.ConnectivityManager);var mConnectivityManager = context.getSystemService(context.CONNECTIVITY_SERVICE);netInfo = mConnectivityManager.getActiveNetworkInfo();if (netInfo != null && netInfo.isAvailable()) {/網(wǎng)絡(luò)連接var name = netInfo.getTypeName();if (netInfo.getType() == ConnectivityManager.TYPE_WIFI) {/WiFi網(wǎng)絡(luò)return "WIFI"} else if (netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) {/有線網(wǎng)絡(luò)return "有線"} else if (netInfo.getType() == ConnectivityManager.TYPE_MOBILE) {/3g網(wǎng)絡(luò)return "移動(dòng)"}else {return "未知"}} else {網(wǎng)絡(luò)斷開return "斷開"} }清理緩存
checkSpace() function clickUi(ui) {if (ui.exists()) {var a = ui.findOnce();if (a) {var b = a.bounds();if (b) {click(b.centerX(), b.centerY());return true;}}}return false; } //清理緩存,如果緩存空間不足 function checkSpace() {if (textStartsWith('存儲(chǔ)空間').exists() && text('取消').exists()) {var o = text('取消').findOnce();if (o) {clickui(o);sleep(1000);}if (device.sdkInt > 24) {var intent = new Intent();intent.setAction("android.settings.INTERNAL_STORAGE_SETTINGS"); //MEMORY_CARD_SETTINGSapp.startActivity(intent);sleep(3000);var o = text('緩存數(shù)據(jù)').findOnce(); //小米if (o) {clickui(o);sleep(1000);if (text('取消').exists() && text('確定').exists()) {var o = text('確定').findOnce();clickui(o);sleep(10000);}}swipe(100, 200, 100, 500, 500);//z注意,這里需要修改.這里是用于滑動(dòng)的var o = text('垃圾清理').findOnce(); //小米if (o.length > 0) {// clickObject(o[o.length - 1]);o.click()sleep(3000);var iii = 10;while (iii-- > 0) {if (textStartsWith('清理選中垃圾').exists()) {var o = textStartsWith('清理選中垃圾').findOnce();o.click()sleep(5000);back();break;}elsesleep(5000);}}}else {app.startActivity({action: "android.settings.INTERNAL_STORAGE_SETTINGS",root: true});sleep(8000);var o = text('緩存數(shù)據(jù)').findOnce(); //小米if (o) {o.click();sleep(1000);if (text('取消').exists() && text('確定').exists()) {var o = text('確定').findOnce();clickui(o);sleep(10000);}}}back();} }示例:
Auto.JS 取隨機(jī)姓名
/*** @description: 取隨機(jī)姓名函數(shù)* @param: null* @return: randomName隨機(jī)姓名*/ function randomName() {var allFirstName = "王李張劉陳楊黃吳趙周徐孫馬朱胡林郭何高羅鄭梁謝宋唐許鄧馮韓曹曾彭蕭蔡潘田董袁于余葉蔣杜蘇魏程呂丁沈任姚盧傅鐘姜崔譚廖范汪陸金石戴賈韋夏邱方侯鄒熊孟秦白江閻薛尹段雷黎史龍?zhí)召R顧毛郝龔邵萬錢嚴(yán)賴覃洪武莫孔"var firstNameArray = allFirstName.split("");var firstNameIndex = random(0, firstNameArray.length - 1);var firstName = firstNameArray[firstNameIndex];var allSecondNames = "偉剛勇毅俊峰強(qiáng)軍平保東文輝力明永健世廣志義興良海山仁波寧貴福生龍?jiān)珖?guó)勝學(xué)祥才發(fā)武新利清飛彬富順信子杰濤昌成康星光天達(dá)安巖中茂進(jìn)林有堅(jiān)和彪博誠(chéng)先敬震振壯會(huì)思群豪心邦承樂紹功松善厚慶磊民友裕河哲江超浩亮政謙亨奇固之輪翰朗伯宏言若鳴朋斌梁棟維啟克倫翔旭鵬澤晨辰士以建家致樹炎德行時(shí)泰盛雄琛鈞冠策騰楠榕風(fēng)航弘秀娟英華慧巧美娜靜淑惠珠翠雅芝玉萍紅娥玲芬芳燕彩春菊蘭鳳潔梅琳素云蓮真環(huán)雪榮愛妹霞香月鶯媛艷瑞凡佳嘉瓊勤珍貞莉桂娣葉璧璐婭琦晶妍茜秋珊莎錦黛青倩婷姣婉嫻瑾穎露瑤怡嬋雁蓓紈儀荷丹蓉眉君琴蕊薇菁?jí)魨乖锋架拌ョ嵢趫@藝詠卿聰瀾純毓悅昭冰爽琬茗羽希寧欣飄育瀅馥筠柔竹靄凝曉歡霄楓蕓菲寒伊亞宜可姬舒影荔枝思麗子璇淼國(guó)棟夫子瑞堂甜敏尚國(guó)賢賀祥晨濤昊軒易軒益辰益帆益冉瑾春瑾昆春齊楊文昊東東雄霖浩晨熙涵溶溶冰楓欣欣宜豪欣慧建政美欣淑慧文軒文杰欣源忠林榕潤(rùn)欣汝慧嘉新建建林亦菲林冰潔佳欣涵涵禹辰淳美澤惠偉洋涵越潤(rùn)麗翔淑華晶瑩凌晶苒溪雨涵嘉怡佳毅子辰佳琪紫軒瑞辰昕蕊萌明遠(yuǎn)欣宜澤遠(yuǎn)欣怡佳怡佳惠晨茜晨璐運(yùn)昊汝鑫淑君晶瀅潤(rùn)莎榕汕佳鈺佳玉曉慶一鳴語(yǔ)晨添池添昊雨澤雅晗雅涵清妍詩(shī)悅嘉樂晨涵天赫玥傲佳昊天昊萌萌若萌"var secondNameArray = allSecondNames.split("");var secondName = "";var givenNameLength = random(1, 2);if (givenNameLength == 1) {var secondNameIndex = random(0, secondNameArray.length - 1);secondName = secondNameArray[secondNameIndex];}if (givenNameLength == 2) {var secondNameIndex1 = random(0, secondNameArray.length - 1);var secondNameIndex2 = random(0, secondNameArray.length - 1);secondName = secondNameArray[secondNameIndex1] + secondNameArray[secondNameIndex2];}randomName = (firstName + secondName).toString();return randomName; }UI 用戶界面設(shè)計(jì)
/********************************************UI部分***********************************************/ auto.waitFor(); //等待獲取無障礙輔助權(quán)限 var form = {isText: false, } let deviceWidth = device.width; let deviceHeight = device.height; let margin = parseInt(deviceWidth * 0.03); let buttonWidth = parseInt(deviceWidth * 0.40); ui.layout(<vertical margin={margin + "px"} gravity="left|top"><appbar><toolbar id="toolbar" title="軟件Title" /></appbar><Switch id="autoService" text="無障礙服務(wù)" checked="{{auto.service != null}}" padding="8 8 8 8" textSize="15sp" /><text textSize="16sp" textColor="red" text="使用前請(qǐng)確保無障礙服務(wù)和懸浮窗權(quán)限已經(jīng)開啟!" /><vertical><button id="all" h="50" text="開始運(yùn)行" /></vertical><horizontal><button margin={margin + "px"} id="dq" h="40" text="單獨(dú)功能1" w={buttonWidth + "px"} /><button margin={margin + "px"} id="cq" h="40" text="單獨(dú)功能2" w={buttonWidth + "px"} /></horizontal><horizontal><button margin={margin + "px"} id="wq" h="40" text="單獨(dú)功能3" w={buttonWidth + "px"} /><button margin={margin + "px"} id="sq" h="40" text="單獨(dú)功能4" w={buttonWidth + "px"} /></horizontal><horizontal><button margin={margin + "px"} id="update" h="40" text=" 單獨(dú)功能5 " w={buttonWidth + "px"} /><button margin={margin + "px"} id="stop" h="40" text="停止運(yùn)行" w={buttonWidth + "px"} /></horizontal><horizontal><text textSize="16sp" marginLeft="15" textColor="black" text="用戶參數(shù)輸入:" /><input id="acatlog" text="" /></horizontal><vertical><text text="用戶參數(shù)選擇" textColor="#222222" /><horizontal><radio id="yes_read" text="是" checked="true"></radio><radio id="no_read" text="否"></radio></horizontal></vertical><text id={"resultLabel"} textColor="red" w="*" /><button w="250" layout_gravity="center" id="about" text="關(guān)于本軟件" /></vertical> );//創(chuàng)建選項(xiàng)菜單(右上角) ui.emitter.on("create_options_menu", menu => {menu.add("啟動(dòng)懸浮窗");menu.add("運(yùn)行日志"); });//監(jiān)聽選項(xiàng)菜單點(diǎn)擊 ui.emitter.on("options_item_selected", (e, item) => {switch (item.getTitle()) {case "啟動(dòng)懸浮窗":var intent = new Intent();intent.setAction("android.settings.action.MANAGE_OVERLAY_PERMISSION");app.startActivity(intent);break;case "運(yùn)行日志":app.startActivity('console');break;}e.consumed = true; });ui.yes_read.on("check", function (check) {if (check) {form.isText = true;textTarget = true;} }); ui.no_read.on("check", function (check) {if (check) {form.isText = false;textTarget = false;} });ui.acatlog.setText(aCatlog.toString());ui.autoService.on("check", function (checked) {// 用戶勾選無障礙服務(wù)的選項(xiàng)時(shí),跳轉(zhuǎn)到頁(yè)面讓用戶去開啟if (checked && auto.service == null) {app.startActivity({ action: "android.settings.ACCESSIBILITY_SETTINGS" });}if (!checked && auto.service != null) {auto.service.disableSelf();} });// 當(dāng)用戶回到本界面時(shí),resume事件會(huì)被觸發(fā) ui.emitter.on("resume", function () {// 此時(shí)根據(jù)無障礙服務(wù)的開啟情況,同步開關(guān)的狀態(tài)ui.autoService.checked = auto.service != null; });var thread = null; ui.all.click(function () {if (thread != null && thread.isAlive()) {alert("注意!", "當(dāng)前程序正在運(yùn)行,請(qǐng)結(jié)束之前進(jìn)程");return;}toast("開始運(yùn)行");thread = threads.start(function () {aCatlog = ui.acatlog.getText();if (auto.service == null) {toastLog("請(qǐng)先開啟無障礙服務(wù)!");return;}main(); //主函數(shù)開始運(yùn)行}); });ui.cq.click(function () {if (thread != null && thread.isAlive()) {alert("注意!", "當(dāng)前程序正在運(yùn)行,請(qǐng)結(jié)束之前進(jìn)程");return;}thread = threads.start(function () {if (auto.service == null) {toastLog("請(qǐng)先開啟無障礙服務(wù)!");return;}//此處開始執(zhí)行函數(shù)();}); });ui.dq.click(function () {if (thread != null && thread.isAlive()) {alert("注意!", "當(dāng)前程序正在運(yùn)行,請(qǐng)結(jié)束之前進(jìn)程");return;}thread = threads.start(function () {if (auto.service == null) {toastLog("請(qǐng)先開啟無障礙服務(wù)!");return;}//此處開始執(zhí)行函數(shù)();}); });ui.wq.click(function () {if (thread != null && thread.isAlive()) {alert("注意!", "當(dāng)前程序正在運(yùn)行,請(qǐng)結(jié)束之前進(jìn)程");return;}thread = threads.start(function () {if (auto.service == null) {toastLog("請(qǐng)先開啟無障礙服務(wù)!");return;}//此處開始執(zhí)行函數(shù)();}); });ui.sq.click(function () {if (thread != null && thread.isAlive()) {alert("注意!", "當(dāng)前程序正在運(yùn)行,請(qǐng)結(jié)束之前進(jìn)程");return;}thread = threads.start(function () {if (auto.service == null) {toastLog("請(qǐng)先開啟無障礙服務(wù)!");return;}//此處開始執(zhí)行函數(shù)();}); });ui.stop.click(function () {if (thread != null && thread.isAlive()) {threads.shutDownAll();toast("已停止運(yùn)行!")console.hide();}else {toast("當(dāng)前沒有線程在運(yùn)行!")} });ui.about.click(function () {alert("說明", "本文中所有代碼和舉例均為學(xué)習(xí)交流之用,不得用于其他用途!"); });總結(jié)
以上是生活随笔為你收集整理的Auto.JS 开发的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓逆向_24( 一 ) --- Hoo
- 下一篇: Xvfb 虚拟现实库 之 Python