提示:如果你的项目名称不是"test"
这行package com.example.test就会报错改正即可
build.gradle(Project:test)

pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
        maven { url 'https://jitpack.io' }
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        repositories {
            google()
            mavenCentral()
            // 下面这两个允许引入第三方库
            jcenter()
            maven { url 'https://jitpack.io' }
        }
    }

}
rootProject.name = "test"
include ':app'

build.gradle(Module:app)

plugins {
    ···
}

android {
	···
    // 开启data binding
    dataBinding {
        enabled = true
    }
	···
}


dependencies {
    ···
}

主界面 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <LinearLayout
        android:id="@+id/linear"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#D65B5B"
        android:backgroundTint="#D65B5B"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center">
          <Button
                android:id="@+id/btn01"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="3dp"
                android:minHeight="48dp"
                android:text="Toast" />
            <Button
                android:id="@+id/btn02"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="3dp"
                android:minHeight="48dp"
                android:text="开启无障碍" />
     

        </LinearLayout>

    </LinearLayout>
</layout>

主界面MainActivity.tk

package com.example.test

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Environment
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import com.example.test.databinding.ActivityMainBinding
import kotlin.system.exitProcess


class MainActivity : AppCompatActivity() {
    private var id = R.layout.activity_main
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // databinding对象自己上网搜索一下即可,不用findViewByMe了
        binding = DataBindingUtil.setContentView(this, id)
        // 将自动点击该按钮
        binding.btn01.setOnClickListener{
        	print("点击了Toast")
        	Log.i("tag","点击了Toast")
        }
        binding.btn02.setOnClickListener {
            // 挑转到无障碍服务
        if (!ASHelper.isAccessibilitySettingsOn(this, TheAccessibilityService::class.java.name)) {
            ASHelper.jumpToSettingPage(this)
        }
        }
    }

}

上面需要用到的ASHelper.kt类

package com.example.test

import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.provider.Settings

object ASHelper {
    //跳转到设置页面无障碍服务开启自定义辅助功能服务
    fun jumpToSettingPage(context: Context) {
        val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        context.startActivity(intent)
    }

    //判断自定义辅助功能服务是否开启
    fun isAccessibilitySettingsOn(context: Context?, className: String): Boolean {
        if (context == null) {
            return false
        }
        val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        if (activityManager != null) {
            val runningServices = activityManager.getRunningServices(100) // 获取正在运行的服务列表
            if (runningServices.size < 0) {
                return false
            }
            for (i in runningServices.indices) {
                val service = runningServices[i].service
                if (service.className == className) {
                    return true
                }
            }
        }
        return false
    }
}

接下来准备一个acuton.xml文件放入layout文件夹,用于在桌面上悬浮
acuton.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="text"
            type="String" />
    </data>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <Button
            android:id="@+id/start"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="模拟点击" />
    </LinearLayout>
</layout>

配置无障碍服务的xml

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagReportViewIds"
    android:canRetrieveWindowContent="true"
    android:canPerformGestures="true"
    android:notificationTimeout="100"
    android:description="描述"
    <!-- 这个是你要操作的APP的包名比如QQ的包名就是com.tencent.mobileqq -->
    <!-- 包名都可以在网上搜索到,这里用我自己的项目包名去点击本程序 -->
    android:packageNames="com.example.test" />

配置自己的无障碍程序

package com.example.test

import android.accessibilityservice.AccessibilityService
import android.annotation.SuppressLint
import android.graphics.PixelFormat
import android.graphics.Rect
import android.os.Build
import android.os.Environment
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.WindowManager
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.Button
import android.widget.FrameLayout
import android.widget.TextView
import androidx.annotation.RequiresApi
import com.alibaba.fastjson.JSON
import java.io.File


class TheAccessibilityService : AccessibilityService() {
    private lateinit var mLayout: FrameLayout

    @RequiresApi(Build.VERSION_CODES.R)
    @SuppressLint("ServiceCast")
    override fun onServiceConnected() {
        // 在屏幕顶部添加一个 View
        val wm = getSystemService(WINDOW_SERVICE) as? WindowManager
        mLayout = FrameLayout(this)
        // 一个视图对象
        val lp = WindowManager.LayoutParams().apply {
            type =
                WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY // 因为此权限才能展示处理, 只能配合 AccessibilityService 使用
            format = PixelFormat.TRANSLUCENT
            flags = flags or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            width = WindowManager.LayoutParams.WRAP_CONTENT
            height = WindowManager.LayoutParams.WRAP_CONTENT
            gravity = Gravity.TOP
        }
        // 加入布局到View
        val inflater = LayoutInflater.from(this@TheAccessibilityService)
        inflater.inflate(R.layout.acuton_bar, mLayout)
        wm?.addView(mLayout, lp)
        // 获取按钮
        var start = mLayout.findViewById<Button>(R.id.start)
        // 点击事件
        start.setOnClickListener {
            try {
            	// 根据控件的文本获取节点(返回一个List)	
                var node = rootInActiveWindow?.findAccessibilityNodeInfosByText("Toast")
                // 判断是否有节点
                if (node != null && node.isNotEmpty()) {
                	// 新建矩阵
                    val rect = Rect()
                    // 根据节点位置写入矩阵内
                    node[0].getBoundsInScreen(rect)
                    // 模拟点击
                    AutoClick().clickCMD(rect, this@TheAccessibilityService)
                }
            } catch (e: java.lang.Exception) {
                Log.i("mine", "error: $e")
            }
        }
    }
    override fun onAccessibilityEvent(event: AccessibilityEvent?) {}
    override fun onInterrupt() {}
}

上面用到的AutoClick.tk类

package com.example.test;

import android.accessibilityservice.AccessibilityService
import android.accessibilityservice.GestureDescription
import android.graphics.Path
import android.graphics.Point
import android.graphics.Rect
import android.os.Build
import android.util.Log
import android.view.accessibility.AccessibilityNodeInfo
import androidx.annotation.RequiresApi
import java.io.OutputStream


class AutoClick {

    /**
     * 使用安卓内部cmd模拟点击,需要root权限
     */
    open fun clickCMD(rect: Rect, service: AccessibilityService) {
        var os: OutputStream? = null
        val x = (rect.left + rect.right) / 2
        val y = (rect.top + rect.bottom) / 2
        val cmd = "input tap $x $y"
        try {
            if (os == null) {
                os = Runtime.getRuntime().exec("su").outputStream
            }
            os!!.write(cmd.toByteArray())
            os!!.flush() //清空缓存
            os!!.close() //停止流
        } catch (e: Exception) {
        	// 如果没有root的设备就会异常,尝试使用无障碍手势模拟点击
            gestureClick(rect,service)
        }
    }


    /**
     * 无障碍模拟手势点击
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    open fun gestureClick(rect: Rect, service: AccessibilityService): Boolean {
        val x: Int = (rect.left + rect.right) / 2
        val y: Int = (rect.top + rect.bottom) / 2
        val point = Point(x, y)
        val builder: GestureDescription.Builder = GestureDescription.Builder()
        val path = Path()
        path.moveTo(point.x.toFloat(), point.y.toFloat())
        builder.addStroke(GestureDescription.StrokeDescription(path, 0L, 100L))
        val gesture: GestureDescription = builder.build()
        return service.dispatchGesture(
            gesture,
            object : AccessibilityService.GestureResultCallback() {
                override fun onCompleted(gestureDescription: GestureDescription?) {
                    super.onCompleted(gestureDescription)
                    Log.i("mine", "dispatchGesture onCompleted: 完成...");
                }

                override fun onCancelled(gestureDescription: GestureDescription?) {
                    super.onCancelled(gestureDescription)
                    Log.i("mine", "dispatchGesture onCancelled: 取消...");
                }
            },
            null
        )
    }

}

另外的,别忘记了在AndroidManifest.xml里面配置
canPerformGestures="true"允许执行手势

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!--    // Android6.0~Android10.0添加-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!--    // Android11.0添加-->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

    <application
        android:accessibilityFlags="flagDefault|flagRetrieveInteractiveWindows|flagIncludeNotImportantViews"
        canPerformGestures="true"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service
            android:name=".TheAccessibilityService"
            android:enabled="true"
            android:exported="true"
            android:label="服务名称"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
            android:process=":BackgroundService">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_config" />
        </service>
    </application>

</manifest>
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐