diff --git a/app/build.gradle b/app/build.gradle index f96f9718..3fae4f85 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "com.stardust.scriptdroid" minSdkVersion 19 targetSdkVersion 23 - versionCode 125 - versionName "2.0.9 Beta" + versionCode 126 + versionName "2.0.10 Beta" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { diff --git a/app/src/main/assets/sample/选择器/QQ互赞脚本.js b/app/src/main/assets/sample/QQ与微信/QQ名片点赞脚本.js similarity index 82% rename from app/src/main/assets/sample/选择器/QQ互赞脚本.js rename to app/src/main/assets/sample/QQ与微信/QQ名片点赞脚本.js index ced0b269..94694c59 100644 --- a/app/src/main/assets/sample/选择器/QQ互赞脚本.js +++ b/app/src/main/assets/sample/QQ与微信/QQ名片点赞脚本.js @@ -14,7 +14,9 @@ function 显示更多(){ } } -toast("请打开点赞自己的人的界面"); +toast("请打开自己的资料页,点击点赞图标"); +sleep(100); + while(notStopped()){ for(let i = 0; i < 10; i++){ 赞(); diff --git a/app/src/main/assets/sample/QQ与微信/QQ循环发送图片.js b/app/src/main/assets/sample/QQ与微信/QQ循环发送图片.js new file mode 100644 index 00000000..f109259f --- /dev/null +++ b/app/src/main/assets/sample/QQ与微信/QQ循环发送图片.js @@ -0,0 +1,17 @@ +"auto"; + +launchApp("QQ"); +toast("请打开一个聊天窗口,将会循环发送第一张图片100次"); + +while(!id("ivTitleBtnRightImage").exists()); + +var listParent = className("AbsListView").findOne().parent(); +var icons = listParent.child(listParent.childCount() - 2); +icons.child(1).click(); +sleep(200); + +for(i = 0; i < 100;i++){ + className("CheckBox").untilFindOne().click(); + sleep(200); + id("send_btn").click(); +} \ No newline at end of file diff --git a/app/src/main/assets/sample/选择器/QQ空间点赞(不完美).js b/app/src/main/assets/sample/QQ与微信/QQ空间点赞(没卵用).js similarity index 100% rename from app/src/main/assets/sample/选择器/QQ空间点赞(不完美).js rename to app/src/main/assets/sample/QQ与微信/QQ空间点赞(没卵用).js diff --git a/app/src/main/assets/sample/自动操作/QQ自动抢红包.js b/app/src/main/assets/sample/QQ与微信/QQ自动抢红包(没卵用).js similarity index 100% rename from app/src/main/assets/sample/自动操作/QQ自动抢红包.js rename to app/src/main/assets/sample/QQ与微信/QQ自动抢红包(没卵用).js diff --git a/app/src/main/assets/sample/QQ与微信/取关全部公众号.js b/app/src/main/assets/sample/QQ与微信/取关全部公众号.js new file mode 100644 index 00000000..dfd9220f --- /dev/null +++ b/app/src/main/assets/sample/QQ与微信/取关全部公众号.js @@ -0,0 +1,27 @@ +"auto"; + +if (confirm("将会取关所有公众号,是否继续")) { + unfollowAll(); +} + +function unfollowAll() { + launchApp("微信"); + sleep(1000); + while (!click("通讯录")); + while (!click("公众号")); + sleep(500); + while (true) { + className("ListView").findOne().children().each(function(item) { + if (item.longClickable()) { + unfollow(item); + sleep(400); + } + }); + } +} + +function unfollow(item) { + item.longClick(); + while (!click("取消关注")); + while (!click("不再关注")); +} diff --git a/app/src/main/assets/sample/QQ与微信/好友列表名片点赞(不完美).js b/app/src/main/assets/sample/QQ与微信/好友列表名片点赞(不完美).js new file mode 100644 index 00000000..8fc980d1 --- /dev/null +++ b/app/src/main/assets/sample/QQ与微信/好友列表名片点赞(不完美).js @@ -0,0 +1,54 @@ +"auto"; + +//漏赞过多请稍微调大延迟 +var 延迟 = 200; + +launchApp("QQ"); +//点击联系人图标 +className("TabWidget").findOne().child(1).click(); +toast("请展开要点赞的分组"); +var fail = 0; + +while(true){ + + var list = id("elv_buddies").className("AbsListView").findOne(); + var count = list.childCount(); + print("count" + list.childCount()); + + for(let i = 0; i < count; i++){ + try{ + let child = list.child(i); + print(i); + if(isFriend(child)){ + //点进好友名片 + child.click(); + fav(10); + backToList(); + sleep(延迟); + } + }catch(e){ + fail++; + toast("可能漏赞:" + fail); + } + } + list.scrollForward(); +} + +//点赞 +function fav(times){ + var i = 0; + var btn = descEndsWith("点击可赞").findOne(); + while(i < times){ + i += btn.click()? 1 : 0; + } +} + +//判断是否是好友的视图 +function isFriend(child){ + return child && child.className().endsWith("LinearLayout") && child.childCount() == 2 && child.child(0).className().endsWith("FrameLayout"); +} + +//返回好友列表 +function backToList(){ + id("ivTitleBtnLeft").click(); +} \ No newline at end of file diff --git a/app/src/main/assets/sample/自动操作/屏蔽QQ通知.js b/app/src/main/assets/sample/QQ与微信/屏蔽QQ通知.js similarity index 100% rename from app/src/main/assets/sample/自动操作/屏蔽QQ通知.js rename to app/src/main/assets/sample/QQ与微信/屏蔽QQ通知.js diff --git a/app/src/main/assets/sample/QQ与微信/循环发送消息.js b/app/src/main/assets/sample/QQ与微信/循环发送消息.js new file mode 100644 index 00000000..703dc4ad --- /dev/null +++ b/app/src/main/assets/sample/QQ与微信/循环发送消息.js @@ -0,0 +1,10 @@ +"auto"; + +toast("请打开一个聊天窗口"); +sleep(500); + +while(true){ + input("我喜欢你"); + click("发送"); + sleep(200); +} \ No newline at end of file diff --git a/app/src/main/assets/sample/选择器/微信一键已读.js b/app/src/main/assets/sample/QQ与微信/微信一键已读.js similarity index 81% rename from app/src/main/assets/sample/选择器/微信一键已读.js rename to app/src/main/assets/sample/QQ与微信/微信一键已读.js index 6a7df4e7..95af5d7c 100644 --- a/app/src/main/assets/sample/选择器/微信一键已读.js +++ b/app/src/main/assets/sample/QQ与微信/微信一键已读.js @@ -3,6 +3,6 @@ while(true){ if(id("i4").untilFindOne().parent().parent().click()){ sleep(700); - id("gf").click(); + back(); } } \ No newline at end of file diff --git a/app/src/main/assets/sample/自动操作/微信扫一扫.js b/app/src/main/assets/sample/QQ与微信/微信扫一扫.js similarity index 100% rename from app/src/main/assets/sample/自动操作/微信扫一扫.js rename to app/src/main/assets/sample/QQ与微信/微信扫一扫.js diff --git a/app/src/main/assets/sample/QQ与微信/批量删除微信好友.js b/app/src/main/assets/sample/QQ与微信/批量删除微信好友.js new file mode 100644 index 00000000..64886d74 --- /dev/null +++ b/app/src/main/assets/sample/QQ与微信/批量删除微信好友.js @@ -0,0 +1,18 @@ +"auto"; + +launchApp("微信"); +while(!click("通讯录")); + +toast("在好友列表中点谁删谁。被删除的好友将在日志中记录。"); +while(true){ + if(desc("更多").exists()){ + var weChatId = textContains("微信号").find(); + if(weChatId && weChatId.size()){ + console.log(weChatId.get(0).text()); + } + while(!desc("更多").click()); + while(!click("删除")); + while(!click("删除")); + sleep(200); + } +} \ No newline at end of file diff --git a/app/src/main/assets/sample/QQ与微信/批量删除朋友圈.js b/app/src/main/assets/sample/QQ与微信/批量删除朋友圈.js new file mode 100644 index 00000000..0668b5f6 --- /dev/null +++ b/app/src/main/assets/sample/QQ与微信/批量删除朋友圈.js @@ -0,0 +1,29 @@ +"auto"; + +launchApp("微信"); +sleep(500); +while(!click("发现")); +while(!click("朋友圈")); +descContains("我的头像").click(); +toast("请点击要删除的朋友圈"); + +while(true){ + deletePost(); + sleep(200); +} + + +function deletePost(){ + var isPhoto = desc("更多").exists(); + if(isPhoto){ + desc("更多").click(); + } + if(click("删除")){ + while(!click("确定")); + sleep(200); + if(isPhoto){ + while(!back()); + } + } + +} \ No newline at end of file diff --git a/app/src/main/assets/sample/QQ与微信/批量取关公众号.js b/app/src/main/assets/sample/QQ与微信/批量取关公众号.js new file mode 100644 index 00000000..409b147c --- /dev/null +++ b/app/src/main/assets/sample/QQ与微信/批量取关公众号.js @@ -0,0 +1,25 @@ +"auto"; +launchApp("微信"); +enterOfficialAccounts(); +sleep(200); +toast("请点击要取关的公众号"); +while(true){ + //点击右上角小人图标 + desc("聊天信息").findOne().click(); + //获取微信号并记录 + var weChatId = textContains("微信号").findOne(); + console.log("取关: " + weChatId.text()); + //点击右上角三个小点儿 + desc("更多").findOne().click(); + while(!click("不再关注")); + sleep(200); + while(!click("不再关注")); + sleep(200); + enterOfficialAccounts(); +} + +//进入公众号界面 +function enterOfficialAccounts(){ + while(!click("通讯录")); + while(!click("公众号")); +} \ No newline at end of file diff --git a/app/src/main/assets/sample/自动操作/支付宝扫一扫.js b/app/src/main/assets/sample/QQ与微信/支付宝扫一扫.js similarity index 100% rename from app/src/main/assets/sample/自动操作/支付宝扫一扫.js rename to app/src/main/assets/sample/QQ与微信/支付宝扫一扫.js diff --git a/app/src/main/assets/sample/QQ与微信/朋友圈点赞.js b/app/src/main/assets/sample/QQ与微信/朋友圈点赞.js new file mode 100644 index 00000000..def86b62 --- /dev/null +++ b/app/src/main/assets/sample/QQ与微信/朋友圈点赞.js @@ -0,0 +1,23 @@ +"auto"; + +//下滑 +function scroll(){ + className("ListView").scrollForward(); +} + +//尝试点赞 +function tryFav(btn){ + btn.click(); + sleep(300); + if(!click("赞")){ + btn.click(); + } +} + +while(true){ + var c = className("ImageView").desc("评论").untilFind(); + c.each(function(btn){ + tryFav(btn); + }); + scroll(); +} \ No newline at end of file diff --git a/app/src/main/assets/sample/选择器/清空酷安动态.js b/app/src/main/assets/sample/其他应用/清空酷安动态.js similarity index 100% rename from app/src/main/assets/sample/选择器/清空酷安动态.js rename to app/src/main/assets/sample/其他应用/清空酷安动态.js diff --git a/app/src/main/assets/sample/其他应用/网易云音乐批量点赞.js b/app/src/main/assets/sample/其他应用/网易云音乐批量点赞.js new file mode 100644 index 00000000..2b6209d3 --- /dev/null +++ b/app/src/main/assets/sample/其他应用/网易云音乐批量点赞.js @@ -0,0 +1,34 @@ +"auto"; + +launchApp("网易云音乐"); +toast("打开一个歌曲的评论页面"); + +//循环直至当前为评论页面 +waitActivity("com.netease.cloudmusic.activity.ResourceCommentActivity"); + + +while(true){ + var list = className("ListView").findOne(); + list.find(className("RelativeLayout")).each(function(item){ + if(item && item.childCount() >= 3){ + //点赞按钮 + var fav = item.child(2); + if(fav){ + //获取点赞次数 + var favCount = parseInt(fav.text()); + fav.click(); + sleep(100); + fav.refresh(); + //如果点了以后点赞数减少了,那么说明赞被取消了,再点一次 + if(parseInt(fav.text()) < favCount){ + fav.click(); + } + sleep(100); + } + + } + }); + //下滑 + list.scrollForward(); +} + diff --git a/app/src/main/assets/sample/其他应用/网易云音乐签到.js b/app/src/main/assets/sample/其他应用/网易云音乐签到.js new file mode 100644 index 00000000..f08d9875 --- /dev/null +++ b/app/src/main/assets/sample/其他应用/网易云音乐签到.js @@ -0,0 +1,6 @@ +"auto"; + +launchApp("网易云音乐"); +sleep(500); +classNameEndsWith("DrawerLayout").findOne().child(0).child(1).child(0).child(0).click(); +text("签到").className("TextView").click(); \ No newline at end of file diff --git a/app/src/main/assets/sample/其他应用/贴吧一键签到.js b/app/src/main/assets/sample/其他应用/贴吧一键签到.js new file mode 100644 index 00000000..5921958a --- /dev/null +++ b/app/src/main/assets/sample/其他应用/贴吧一键签到.js @@ -0,0 +1,40 @@ +"auto"; + +launchApp("百度贴吧"); +sleep(1000); +while(!click("进吧")); +toast("开始签到"); +var signed = {}; + +while(true){ + var list = id("fragment_pager").findOne().findOne(id("listview")); + list.children().each(function(child){ + if(child && child.className().endsWith("RelativeLayout")){ + if(child.childCount() > 1){ + sign(child); + } + } + }); + list.scrollForward(); +} + +function sign(child){ + var li = child.child(1); + if(li && li.childCount() > 0){ + var name = li.child(0).text(); + if(signed[name]){ + return; + } + child.click(); + sleep(400); + for(var i = 0; i < 3; i ++){ + if(click("签到")){ + break; + } + sleep(200); + } + sleep(400); + while(!back()); + signed[name] = true; + } +} \ No newline at end of file diff --git a/app/src/main/assets/sample/应用/强制停止应用.js b/app/src/main/assets/sample/应用/强制停止应用.js new file mode 100644 index 00000000..22c9cfef --- /dev/null +++ b/app/src/main/assets/sample/应用/强制停止应用.js @@ -0,0 +1,5 @@ +"auto"; + +var appName = rawInput("请输入应用名称"); +openAppSetting(getPackageName(appName)); +while(!click("强制停止")); \ No newline at end of file diff --git a/app/src/main/assets/sample/界面/QQ强制聊天.js b/app/src/main/assets/sample/界面/QQ打开聊天窗口.js similarity index 74% rename from app/src/main/assets/sample/界面/QQ强制聊天.js rename to app/src/main/assets/sample/界面/QQ打开聊天窗口.js index e2e8b20a..3fb77bd6 100644 --- a/app/src/main/assets/sample/界面/QQ强制聊天.js +++ b/app/src/main/assets/sample/界面/QQ打开聊天窗口.js @@ -16,7 +16,9 @@ container.addView(btnOk); activity.setContentView(container); btnOk.setOnClickListener(function(view){ - activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin=" + qq.getText())) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + app.startActivity({ + action: "android.intent.action.VIEW", + data: "mqqwpa://im/chat?chat_type=wpa&uin=" + qq.getText() + }); activity.finish(); }); \ No newline at end of file diff --git a/app/src/main/assets/sample/自动操作/打开自动运行的服务.js b/app/src/main/assets/sample/自动操作/打开自动运行的服务.js deleted file mode 100644 index ed10722e..00000000 --- a/app/src/main/assets/sample/自动操作/打开自动运行的服务.js +++ /dev/null @@ -1,24 +0,0 @@ -"auto"; - -function 打开正在运行的服务(){ - launch("com.android.settings"); - var i = 0; - while(!click("开发者选项")){ - i++; - if(i == 10){ - toast("开发者选项未开启"); - return; - } - scrollDown(); - } - while(!click("正在运行的服务")); -} - - -importClass(android.os.Build); - -if(Build.VERSION.SDK_INT < 23){ - toast("本代码只适用于Android6.0以上"); -}else{ - 打开正在运行的服务(); -} \ No newline at end of file diff --git a/app/src/main/assets/sample/选择器/QQ图片轰炸.js b/app/src/main/assets/sample/选择器/QQ图片轰炸.js deleted file mode 100644 index 8fa33bf5..00000000 --- a/app/src/main/assets/sample/选择器/QQ图片轰炸.js +++ /dev/null @@ -1,8 +0,0 @@ -"auto"; - -launchApp("QQ"); -toast("打开一个聊天窗口,并点击下面的图片按钮"); -for(i = 0; i < 100;i++){ - className("CheckBox").untilFindOne().click(); - id("send_btn").click(); -} \ No newline at end of file diff --git a/app/src/main/assets/sample/选择器/批量取关公众号.js b/app/src/main/assets/sample/选择器/批量取关公众号.js deleted file mode 100644 index 03691dc7..00000000 --- a/app/src/main/assets/sample/选择器/批量取关公众号.js +++ /dev/null @@ -1,15 +0,0 @@ -"auto"; - -function 取消关注(){ - id("af9").longClickable().longClick(); - click("取消关注"); - click("不再关注"); -} - -toast("请在10秒内打开订阅号界面"); -toast("10秒后如果没有反应请稍微滑动一下页面"); -sleep(10 * 1000); - -while(true){ - 取消关注(); -} diff --git a/app/src/main/assets/sample/选择器/朋友圈点赞.js b/app/src/main/assets/sample/选择器/朋友圈点赞.js deleted file mode 100644 index be431142..00000000 --- a/app/src/main/assets/sample/选择器/朋友圈点赞.js +++ /dev/null @@ -1,18 +0,0 @@ -function 下滑(){ - className("ListView").scrollForward(); -} - -function 尝试点赞(btn){ - btn.click(); - sleep(300); - if(!click("赞")) - btn.click(); -} - -while(true){ -var c = className("ImageView").desc("评论").untilFind(); -c.each(function(btn){ - 尝试点赞(btn); -}); -下滑(); -} \ No newline at end of file diff --git a/app/src/main/assets/sample/选择器/网易云音乐签到.js b/app/src/main/assets/sample/选择器/网易云音乐签到.js deleted file mode 100644 index 337079c2..00000000 --- a/app/src/main/assets/sample/选择器/网易云音乐签到.js +++ /dev/null @@ -1,5 +0,0 @@ -"auto"; - -launchApp("网易云音乐"); -id("kp").click(); -text("签到").className("TextView").click(); \ No newline at end of file diff --git a/autojs/src/main/assets/modules/__general__.js b/autojs/src/main/assets/modules/__general__.js index 20cde5a9..cd1a13af 100644 --- a/autojs/src/main/assets/modules/__general__.js +++ b/autojs/src/main/assets/modules/__general__.js @@ -35,4 +35,11 @@ module.exports = function(__runtime__, scope){ scope.currentActivity = function(){ return __runtime__.info.getLatestActivity(); } + + scope.waitActivity = function(activity, delay){ + delay = delay || 200; + while(scope.currentActivity() != activity){ + sleep(delay); + } + } } \ No newline at end of file diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/UiSelector.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/UiSelector.java index 1eec0e08..5287963d 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/UiSelector.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/UiSelector.java @@ -87,12 +87,13 @@ public class UiSelector extends UiGlobalSelector { mAllocator = allocator; } + @NonNull @ScriptInterface public UiObjectCollection find() { ensureAccessibilityServiceEnabled(); if (AutomatorConfig.isUnintendedGuardEnabled() && isRunningPackageSelf()) { Log.d(TAG, "isSelfPackage return null"); - return null; + return UiObjectCollection.EMPTY; } AccessibilityService service = mAccessibilityBridge.getService(); if (service != null) { @@ -101,7 +102,7 @@ public class UiSelector extends UiGlobalSelector { return findOf(UiObject.createRoot(root, mAllocator)); } } - return null; + return UiObjectCollection.EMPTY; } private void ensureAccessibilityServiceEnabled() { @@ -123,7 +124,7 @@ public class UiSelector extends UiGlobalSelector { throw new ScriptInterruptedException(); } uiObjectCollection = find(); - } while (uiObjectCollection == null || uiObjectCollection.size() == 0); + } while (uiObjectCollection.empty()); return uiObjectCollection; } @@ -132,6 +133,12 @@ public class UiSelector extends UiGlobalSelector { return untilFindOne(); } + @ScriptInterface + public boolean exists() { + UiObjectCollection collection = find(); + return collection.nonEmpty(); + } + @NonNull public UiObject untilFindOne() { UiObjectCollection collection = untilFind(); @@ -159,10 +166,6 @@ public class UiSelector extends UiGlobalSelector { return untilFind().performAction(action, arguments); } - public boolean exists() { - UiObjectCollection collection = find(); - return collection != null && collection.size() > 0; - } @ScriptInterface public boolean click() { diff --git a/automator/src/main/java/com/stardust/automator/UiObject.java b/automator/src/main/java/com/stardust/automator/UiObject.java index 5233e0ed..cf2f74f4 100644 --- a/automator/src/main/java/com/stardust/automator/UiObject.java +++ b/automator/src/main/java/com/stardust/automator/UiObject.java @@ -9,6 +9,7 @@ import android.support.annotation.Nullable; import android.support.v4.util.Pools; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.util.Log; +import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator; @@ -308,10 +309,65 @@ public class UiObject extends AccessibilityNodeInfoCompat { return mAllocator.getParent(this); } + + public boolean checkable() { + return isCheckable(); + } + + + public boolean checked() { + return isChecked(); + } + + + public boolean focusable() { + return isFocusable(); + } + + + public boolean focused() { + return isFocused(); + } + + public boolean visibleToUser() { return isVisibleToUser(); } + + public boolean accessibilityFocused() { + return isAccessibilityFocused(); + } + + + public boolean selected() { + return isSelected(); + } + + public boolean clickable() { + return isClickable(); + } + + + public boolean longClickable() { + return isLongClickable(); + } + + + public boolean enabled() { + return isEnabled(); + } + + + public boolean password() { + return isPassword(); + } + + + public boolean scrollable() { + return isScrollable(); + } + @Override public List findAccessibilityNodeInfosByText(String text) { if (mAllocator == null) @@ -356,5 +412,4 @@ public class UiObject extends AccessibilityNodeInfoCompat { } } - } diff --git a/automator/src/main/java/com/stardust/automator/UiObjectCollection.java b/automator/src/main/java/com/stardust/automator/UiObjectCollection.java index 4596ab69..e1fe6594 100644 --- a/automator/src/main/java/com/stardust/automator/UiObjectCollection.java +++ b/automator/src/main/java/com/stardust/automator/UiObjectCollection.java @@ -9,6 +9,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import com.stardust.util.Consumer; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.*; @@ -27,6 +28,8 @@ import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat. public class UiObjectCollection { + public static final UiObjectCollection EMPTY = UiObjectCollection.of(Collections.emptyList()); + public static UiObjectCollection ofCompat(List list) { return new UiObjectCollection(UiObject.compatListToUiObjectList(list)); } @@ -217,4 +220,12 @@ public class UiObjectCollection { } return null; } + + public boolean empty() { + return size() == 0; + } + + public boolean nonEmpty() { + return size() != 0; + } }