自动点击android按钮,Android实现自动点击无障碍服务功能的实例代码

ps: 不想看代码的滑到最下面有apk包百度网盘下载地址

1. 先看效果图 不然都是耍流氓

596b615be3dab82375e7255233478a8e.gif

2.项目目录

325bee08b28e0cabfcb5df69cd446395.png

3.一些配置

build.gradle

plugins {

id 'com.android.application'

id 'kotlin-android'

id 'kotlin-android-extensions'

}

android {

compileSdkVersion 30

buildToolsVersion "30.0.3"

defaultConfig {

applicationId "com.znan.autoclick"

minSdkVersion 24

targetSdkVersion 30

versionCode 1

versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

}

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

}

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_8

targetCompatibility JavaVersion.VERSION_1_8

}

kotlinOptions {

jvmTarget = '1.8'

}

}

dependencies {

implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

implementation 'androidx.core:core-ktx:1.3.2'

implementation 'androidx.appcompat:appcompat:1.2.0'

implementation 'com.google.android.material:material:1.3.0'

implementation 'androidx.constraintlayout:constraintlayout:2.0.4'

testImplementation 'junit:junit:4.+'

androidTestImplementation 'androidx.test.ext:junit:1.1.2'

androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

//协程

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3"

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"

}

accessibility.xml

android:accessibilityEventTypes="typeAllMask"

android:accessibilityFeedbackType="feedbackAllMask"

android:canPerformGestures="true"

android:canRetrieveWindowContent="true"

android:description="@string/accessibility_desc" />

AndroidManifest.xml 注册权限和服务

package="com.znan.autoclick">

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:roundIcon="@mipmap/ic_launcher_round"

android:supportsRtl="true"

android:theme="@style/Theme.AutoClick">

android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">

android:name="android.accessibilityservice"

android:resource="@xml/accessibility" />

4.代码

AutoClickService.kt 无障碍服务

import android.accessibilityservice.AccessibilityService

import android.accessibilityservice.GestureDescription

import android.app.Notification

import android.content.Intent

import android.graphics.Path

import android.os.Build

import android.util.Log

import android.view.accessibility.AccessibilityEvent

import androidx.annotation.RequiresApi

import androidx.core.app.NotificationCompat

import kotlinx.coroutines.*

class AutoClickService : AccessibilityService() {

private val TAG = javaClass.canonicalName

var mainScope: CoroutineScope? = null

//点击间隔

private var mInterval = -1L

//点击坐标xy

private var mPointX = -1f

private var mPointY = -1f

//悬浮窗视图

private lateinit var mFloatingView: FloatingClickView

companion object {

val FLAG_ACTION = "flag_action"

//打开悬浮窗

val ACTION_SHOW = "action_show"

//自动点击事件 开启/关闭

val ACTION_PLAY = "action_play"

val ACTION_STOP = "action_stop"

//关闭悬浮窗

val ACTION_CLOSE = "action_close"

}

override fun onCreate() {

super.onCreate()

startForegroundNotification()

mFloatingView = FloatingClickView(this)

}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

Log.d(TAG, "onStartCommand " + intent?.extras)

intent?.apply {

val action = getStringExtra(FLAG_ACTION)

Log.d(TAG, "action " + action)

when (action) {

ACTION_SHOW -> {

mInterval = getLongExtra("interval", 5000)

mFloatingView.show()

}

ACTION_PLAY -> {

mPointX = getFloatExtra("pointX", 0f)

mPointY = getFloatExtra("pointY", 0f)

mainScope = MainScope()

autoClickView(mPointX, mPointY)

}

ACTION_STOP -> {

mainScope?.cancel()

}

ACTION_CLOSE -> {

mFloatingView.remove()

mainScope?.cancel()

}

else -> {

Log.e(TAG, "action error")

}

}

}

return super.onStartCommand(intent, flags, startId)

}

private fun startForegroundNotification() {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

val notificationBuilder =

NotificationCompat.Builder(this, NotificationConstants.CHANNEL_ID)

val notification = notificationBuilder.setOngoing(true)

.setSmallIcon(R.mipmap.ic_launcher)

.setCategory(Notification.CATEGORY_SERVICE)

.build()

startForeground(-1, notification)

} else {

startForeground(-1, Notification())

}

}

@RequiresApi(Build.VERSION_CODES.N)

private fun autoClickView(x: Float, y: Float) {

mainScope?.launch {

while (true) {

delay(mInterval)

Log.d(TAG, "auto click x:$x y:$y")

val path = Path()

path.moveTo(x, y)

val gestureDescription = GestureDescription.Builder()

.addStroke(GestureDescription.StrokeDescription(path, 100L, 100L))

.build()

dispatchGesture(

gestureDescription,

object : AccessibilityService.GestureResultCallback() {

override fun onCompleted(gestureDescription: GestureDescription?) {

super.onCompleted(gestureDescription)

Log.d(TAG, "自动点击完成")

}

override fun onCancelled(gestureDescription: GestureDescription?) {

super.onCancelled(gestureDescription)

Log.d(TAG, "自动点击取消")

}

},

null

)

}

}

}

override fun onInterrupt() {

}

override fun onAccessibilityEvent(event: AccessibilityEvent?) {

}

override fun onDestroy() {

super.onDestroy()

mainScope?.cancel()

}

}

悬浮窗

SingletonHolder.kt

open class SingletonHolder(creator: (A) -> T) {

private var creator: ((A) -> T)? = creator

@Volatile private var instance: T? = null

fun getInstance(arg: A): T {

val i = instance

if (i != null) {

return i

}

return synchronized(this) {

val i2 = instance

if (i2 != null) {

i2

} else {

val created = creator!!(arg)

instance = created

creator = null

created

}

}

}

}

FloatingManager.kt

import android.content.Context

import android.view.View

import android.view.WindowManager

class FloatingManager private constructor(context: Context) {

//获得WindowManager对象

private var mWindowManager: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager

companion object : SingletonHolder(::FloatingManager)

/**

* 添加悬浮窗

* @param view

* @param params

* @return

*/

fun addView(view: View, params: WindowManager.LayoutParams): Boolean {

try {

mWindowManager.addView(view, params)

return true

} catch (e: Exception) {

e.printStackTrace()

}

return false

}

/**

* 移除悬浮窗

*

* @param view

* @return

*/

fun removeView(view: View): Boolean {

try {

mWindowManager.removeView(view)

return true

} catch (e: Exception) {

e.printStackTrace()

}

return false

}

/**

* 更新悬浮窗参数

*

* @param view

* @param params

* @return

*/

fun updateView(view: View, params: WindowManager.LayoutParams): Boolean {

try {

mWindowManager.updateViewLayout(view, params)

return true

} catch (e: Exception) {

e.printStackTrace()

}

return false

}

}

FloatingClickView.kt

import android.annotation.SuppressLint

import android.content.Context

import android.content.Intent

import android.graphics.PixelFormat

import android.os.Build

import android.view.*

import android.widget.FrameLayout

import androidx.appcompat.widget.AppCompatImageView

class FloatingClickView(private val mContext: Context) : FrameLayout(mContext) {

private lateinit var mWindowManager: FloatingManager

private var mParams: WindowManager.LayoutParams? = null

private lateinit var mView: View

//按下坐标

private var mTouchStartX = -1f

private var mTouchStartY = -1f

val STATE_CLICKING = "state_clicking"

val STATE_NORMAL = "state_normal"

private var mCurrentState = STATE_NORMAL

private var ivIcon: AppCompatImageView? = null

init {

initView()

}

private fun initView() {

mView = LayoutInflater.from(context).inflate(R.layout.view_floating_click, null)

ivIcon = mView.findViewById(R.id.iv_icon)

mWindowManager = FloatingManager.getInstance(mContext)

initListener()

}

@SuppressLint("ClickableViewAccessibility")

private fun initListener() {

mView.setOnTouchListener { v, event ->

when (event.action) {

MotionEvent.ACTION_DOWN -> {

mTouchStartX = event.rawX

mTouchStartY = event.rawY

}

MotionEvent.ACTION_MOVE -> {

mParams?.let {

it.x += (event.rawX - mTouchStartX).toInt()

it.y += (event.rawY - mTouchStartY).toInt()

mWindowManager.updateView(mView, it)

}

mTouchStartX = event.rawX

mTouchStartY = event.rawY

}

}

false

}

mView.setOnClickListener {

val location = IntArray(2)

it.getLocationOnScreen(location)

val intent = Intent(context, AutoClickService::class.java)

when (mCurrentState) {

STATE_NORMAL -> {

mCurrentState = STATE_CLICKING

intent.putExtra(AutoClickService.FLAG_ACTION, AutoClickService.ACTION_PLAY)

intent.putExtra("pointX", (location[0] - 1).toFloat())

intent.putExtra("pointY", (location[1] - 1).toFloat())

ivIcon?.setImageResource(R.drawable.ic_auto_click_icon_green_24)

}

STATE_CLICKING -> {

mCurrentState = STATE_NORMAL

intent.putExtra(AutoClickService.FLAG_ACTION, AutoClickService.ACTION_STOP)

ivIcon?.setImageResource(R.drawable.ic_auto_click_icon_gray_24)

}

}

context.startService(intent)

}

}

fun show() {

mParams = WindowManager.LayoutParams()

mParams?.apply {

gravity = Gravity.CENTER

//总是出现在应用程序窗口之上

type = if (Build.VERSION.SDK_INT >= 26) {

WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY

} else {

WindowManager.LayoutParams.TYPE_SYSTEM_ALERT

}

//设置图片格式,效果为背景透明

format = PixelFormat.RGBA_8888

flags =

WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or

WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR or

WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH

width = LayoutParams.WRAP_CONTENT

height = LayoutParams.WRAP_CONTENT

if (mView.isAttachedToWindow) {

mWindowManager.removeView(mView)

}

mWindowManager.addView(mView, this)

}

}

fun remove() {

mWindowManager.removeView(mView)

}

}

页面事件

MainActivity.kt

import android.app.NotificationChannel

import android.app.NotificationManager

import android.content.Context

import android.content.Intent

import android.graphics.Color

import android.os.Build

import androidx.appcompat.app.AppCompatActivity

import android.os.Bundle

import android.provider.Settings

import android.text.TextUtils

import android.util.Log

import android.view.inputmethod.InputMethodManager

import android.widget.Toast

import com.google.android.material.snackbar.Snackbar

import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

private val TAG = javaClass::class.java.canonicalName

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

initNotification()

initListener()

}

private fun initListener() {

btn_accessibility.setOnClickListener {

checkAccessibility()

}

btn_floating_window.setOnClickListener {

checkFloatingWindow()

}

btn_show_window.setOnClickListener {

hideKeyboard()

if (TextUtils.isEmpty(et_interval.text.toString())) {

Snackbar.make(et_interval, "请输入间隔", Snackbar.LENGTH_SHORT).show()

return@setOnClickListener

}

showFloatingWindow()

}

btn_close_window.setOnClickListener {

closeFloatWindow()

}

btn_test.setOnClickListener {

Log.d(TAG, "btn_test on click")

}

}

/**

* 跳转设置开启无障碍

*/

private fun checkAccessibility() {

val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)

startActivity(intent)

}

/**

* 跳转设置顶层悬浮窗

*/

private fun checkFloatingWindow() {

if (Build.VERSION.SDK_INT >= 23) {

if (Settings.canDrawOverlays(this)) {

Toast.makeText(this, "已开启", Toast.LENGTH_SHORT).show()

} else {

val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)

startActivity(intent)

}

}

}

private fun showFloatingWindow() {

val intent = Intent(this, AutoClickService::class.java)

intent.apply {

putExtra(AutoClickService.FLAG_ACTION, AutoClickService.ACTION_SHOW)

putExtra("interval", et_interval.text.toString().toLong())

}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

startForegroundService(intent)

} else {

startService(intent)

}

}

private fun closeFloatWindow() {

val intent = Intent(this, AutoClickService::class.java)

intent.putExtra(AutoClickService.FLAG_ACTION, AutoClickService.ACTION_CLOSE)

startService(intent)

}

private fun initNotification() {

//注册渠道id

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

val name = NotificationConstants.CHANNEl_NAME

val descriptionText = NotificationConstants.CHANNEL_DES

val importance = NotificationManager.IMPORTANCE_DEFAULT

val channel =

NotificationChannel(NotificationConstants.CHANNEL_ID, name, importance).apply {

description = descriptionText

}

channel.enableLights(true)

channel.lightColor = Color.GREEN

// Register the channel with the system

val notificationManager: NotificationManager =

getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

notificationManager.createNotificationChannel(channel)

}

}

override fun onDestroy() {

val intent = Intent(this, AutoClickService::class.java)

stopService(intent)

super.onDestroy()

}

//收起输入法

fun hideKeyboard() {

val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

if (imm.isActive && currentFocus != null) {

imm.hideSoftInputFromWindow(currentFocus!!.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)

}

}

}

object NotificationConstants {

val CHANNEL_ID = "auto_channel_id"

val CHANNEl_NAME ="Auto Click"

val CHANNEL_DES = "Auto Click Service"

}

5.布局

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/tv_message"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginStart="50dp"

android:layout_marginTop="20dp"

android:text="先打开无障碍权限 和 悬浮窗顶层权限\n点击位置在图标左上角xy偏移一个px\n程序将会在延迟一个间隔后开始执行"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toTopOf="parent" />

android:id="@+id/btn_accessibility"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginStart="50dp"

android:layout_marginTop="20dp"

android:text="无障碍选项"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@id/tv_message" />

android:id="@+id/btn_floating_window"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginStart="20dp"

android:text="悬浮窗选项"

app:layout_constraintStart_toEndOf="@id/btn_accessibility"

app:layout_constraintTop_toTopOf="@id/btn_accessibility" />

android:id="@+id/tv_unit"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginEnd="50dp"

android:text="ms"

android:textSize="24sp"

app:layout_constraintBottom_toBottomOf="@id/et_interval"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintTop_toTopOf="@id/et_interval" />

android:id="@+id/et_interval"

android:layout_width="0dp"

android:layout_height="48dp"

android:layout_marginStart="50dp"

android:layout_marginTop="50dp"

android:layout_marginEnd="10dp"

android:hint="点击的间隔(建议大于100)(毫秒)"

android:inputType="number"

android:textColor="#FF0000"

android:textSize="14sp"

app:layout_constraintEnd_toStartOf="@id/tv_unit"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@id/btn_accessibility" />

android:id="@+id/btn_show_window"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="50dp"

android:text="打开悬浮视图"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@id/et_interval" />

android:id="@+id/btn_close_window"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="10dp"

android:text="关闭悬浮视图"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@id/btn_show_window" />

android:id="@+id/btn_test"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginBottom="100dp"

android:text="测试点击按钮"

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintStart_toStartOf="parent" />

android:layout_width="wrap_content"

android:layout_height="wrap_content">

android:id="@+id/iv_icon"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ic_auto_click_icon_gray_24" />

6.debug.apk

提取码: va43

到此这篇关于Android实现自动点击无障碍服务功能的文章就介绍到这了,更多相关android无障碍自动点击内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值