目前版本3.1.8 仅供学习使用!!!!!切勿用作非法用途,否则后果自负!
直接写这个东西 可能是有些唐突
因为你们可能不知道这是一个什么玩意 如果你想看过于这个Accessibility服务的一些资料
可以到 我的分类 下面去看
下面将直接进入正题
AccessibilityService 的出现原本为了帮助盲人 来那啥那啥和那啥的
没想到却被我们那啥那啥和那啥了
他使用方法需要手动到无障碍里面去开启 开启成功以后代码就开始运行了
集成的一般步骤就是
创建服务 继承AccessibilityService实现相关方法
package com.example.liuan.test;
import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;
import java.io.DataOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class MyService extends AccessibilityService {
private static final String TAG = "MyService";
// 大多数的手机包名一样,联想部分机型的手机不一样
private String[] packageNames = {"com.p1.mobile.putong"};
int startFlag = 0;
AccessibilityNodeInfo[] noteInfo = new AccessibilityNodeInfo[2];
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getSource() != null) {
findNodesByText(event, "继续探索");
}
switch (event.getEventType()) {
case AccessibilityEvent.TYPE_VIEW_CLICKED:
if (SpUtils.getBoolean(this, "reSet", false)) {
SpUtils.putBoolean(this, "reSet", false);
startFlag = 0;
}
if (startFlag == 0) {
//记录正确
startFlag = 1;
noteInfo[0] = event.getSource();
} else if (startFlag == 1) {
//记录错误 只记录一次即可
startFlag = 2;
noteInfo[1] = event.getSource();
}
if (startFlag == 2) {
autoClick();
}
break;
}
}
private void autoClick() {
try {
String time = SpUtils.getString(this, "time", "1000");
Thread.sleep(Integer.parseInt(time));
} catch (InterruptedException e) {
e.printStackTrace();
}
String time = SpUtils.getString(this, "like", "50");
int percent = Integer.parseInt(time);
//随机数字 是1-100
int random = new Random().nextInt(100) + 1;
//如果设置了百分之50 那么就是各一半
//如果设置了百分之10 那么就是点第一个 8 10
Log.e(TAG, "onAccessibilityEvent:random " + random);
Log.e(TAG, "onAccessibilityEvent:percent " + percent);
if (random <= percent) {
//第一次按键
noteInfo[0].performAction(AccessibilityNodeInfo.ACTION_CLICK);
} else {
noteInfo[1].performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
@Override
public void onInterrupt() {
startFlag = 0;
}
@Override
public void onDestroy() {
super.onDestroy();
startFlag = 0;
}
private void findNodesByText(AccessibilityEvent event, String text) {
List nodes = event.getSource().findAccessibilityNodeInfosByText(text);
if (nodes != null && !nodes.isEmpty()) {
for (AccessibilityNodeInfo info : nodes) {
if (info.isClickable()) {// 只有根据节点信息是下一步,安装,完成,打开,且是可以点击的时候,才执行后面的点击操作
if ("继续探索".equals(text)) {
info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
}
}
private boolean isTextExist(AccessibilityEvent event, String text) {
List nodes = event.getSource().findAccessibilityNodeInfosByText(text);
if (nodes != null && !nodes.isEmpty()) {
for (AccessibilityNodeInfo info : nodes) {
if (info.isClickable()) {// 只有根据节点信息是下一步,安装,完成,打开,且是可以点击的时候,才执行后面的点击操作
if ("继续探索".equals(text)) {
return true;
}
}
}
}
return false;
}
}
我的思路 我简单来说一下 因为就算你层级用的没问题 但是却获取不到id
我就急中生智 使用了event.getSource() 把这个保存到数组 让自己点两下 然后开始模仿我的点击
这个方法不仅仅使用与这里 可以用作好多的地方
AccessiblityServices 要比脚本稳定 脚本存在一种情况就是脚本会崩溃 或者由于某个地方的偏移导致点击错误
这个从节点点击 彻底的解决了这个问题 无论开发者怎么骚操作 这里都可以点击 好气的
获取那个文件的id 或者文字什么的 用到了studio工具中的(本文代码风骚 没有用到这个)
G:\android\sdk\tools\bin\uiautomatorviewer.bat
as 3.0居然丧尽天良把他搞没了 反正我没找到 可能是没了
只能去sdk 目录下去找了 如果你记忆力够好的话找到你曾经安装的sdk目录
如果记忆力不够好 可以在alt+ctrl+s System Settings-->Android SDK看到你的sdk目录 找到打开即可
具体使用方法这里不做教程
四大组件逃不过的清单文件
application节点下
res/xml/accessibility.xml 没有这个目录请自行创建
Test
仅供学习使用,切勿乱搞,否则后果自负
MainActivity
package com.example.liuan.test;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
private Button mBtOpen;
private EditText mEtDelay;
private EditText mEtLike;
/**
* 保存配置
*/
private Button mBtReset;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// String apkRoot="chmod 777 "+getPackageCodePath();
//
// SystemManager.RootCommand(apkRoot);
initView();
initData();
}
private void initData() {
SpUtils.putString(this, "time", mEtDelay.getText().toString().trim());
SpUtils.putString(this, "like", mEtLike.getText().toString().trim());
SpUtils.putBoolean(MainActivity.this, "reSet", true);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Toast.makeText(MainActivity.this, "半径", Toast.LENGTH_LONG);
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
Toast.makeText(MainActivity.this, "半径", Toast.LENGTH_LONG);
mBtOpen.setText("已经关闭");
return true;
}
return super.onKeyDown(keyCode, event);
}
private void initView() {
mBtOpen = (Button) findViewById(R.id.bt_open);
mBtOpen.setOnClickListener(this);
mEtDelay = (EditText) findViewById(R.id.et_delay);
mEtLike = (EditText) findViewById(R.id.et_like);
mEtLike.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
initData();
}
});
mEtDelay.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
initData();
}
});
mBtReset = (Button) findViewById(R.id.bt_reset);
mBtReset.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
default:
break;
case R.id.bt_open:
initData();
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);
break;
case R.id.bt_reset:
initData();
break;
}
}
}
SpUtils
package com.example.liuan.test;
import android.content.Context;
import android.content.SharedPreferences;
/**
* Created by liuan on 2018-04-28.
*/
public class SpUtils {
private static SharedPreferences sp;
public static void getSharedPreference(Context context){
if(sp==null){
sp=context.getSharedPreferences("config",context.MODE_PRIVATE);
}
}
public static void putString(Context context,String key,String value){
getSharedPreference(context);
sp.edit().putString(key,value).commit();
}
public static String getString(Context context,String key,String defValue){
getSharedPreference(context);
return sp.getString(key,defValue);
}
public static boolean getBoolean(Context context,String key,boolean defValue){
getSharedPreference(context);
return sp.getBoolean(key,false);
}
public static void putBoolean(Context context,String key,boolean value){
getSharedPreference(context);
sp.edit().putBoolean(key,value).commit();
}
}
布局文件
开始方法 并不是直接点开启就开启了
第一步 开启探探点击的服务
第二步 打开探探先把其他的第一次引导的东西点完 然后 点一个喜欢 点一个不喜欢 再然后就能看到神奇的自动了
那天我本来想写了按音量键暂停的方法 后来发现没必要 暂停服务就行了