You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Flutter实现跨应用自动点击?求基于uiautomatorviewer的示例代码

实现Flutter跨App自动点击指定ID按钮的方案

一、核心原理

Flutter本身没有直接操作其他应用UI的API,必须依赖Android原生的AccessibilityService(无障碍服务)——这是Android系统提供的系统级辅助服务,用户授权后可监听并操作其他应用的UI元素。你通过uiautomatorviewer获取的控件ID,就是定位目标按钮的关键标识。

二、分步实现

1. 配置Android无障碍服务

在Android项目的src/main/res/xml目录下创建accessibility_service_config.xml文件,配置服务权限:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews|flagRequestTouchExplorationMode"
    android:canPerformGestures="true"
    android:canRetrieveWindowContent="true"
    android:description="@string/accessibility_service_description" />

在src/main/res/values/strings.xml添加服务描述:

<string name="accessibility_service_description">用于自动点击其他应用的指定按钮</string>

2. 编写Android原生AccessibilityService类

在src/main/kotlin/[你的包名]/路径下创建AutoClickService.kt:

package com.yourpackage.name

import android.accessibilityservice.AccessibilityService
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo

class AutoClickService : AccessibilityService() {
    // 替换为你从uiautomatorviewer获取的目标控件完整ID(格式:包名:id/控件ID)
    private val TARGET_BUTTON_ID = "com.target.app:id/btn_submit"
    // 替换为目标应用的包名
    private val TARGET_APP_PACKAGE = "com.target.app"

    override fun onAccessibilityEvent(event: AccessibilityEvent) {
        // 监听前台窗口切换,仅处理目标应用的界面
        if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            val currentPackage = event.packageName?.toString()
            if (currentPackage == TARGET_APP_PACKAGE) {
                findAndClickButton(rootInActiveWindow)
            }
        }
    }

    private fun findAndClickButton(node: AccessibilityNodeInfo?) {
        node ?: return
        // 遍历所有子节点匹配目标ID
        for (i in 0 until node.childCount) {
            val childNode = node.getChild(i)
            childNode ?: continue
            
            if (TARGET_BUTTON_ID == childNode.viewIdResourceName) {
                // 执行点击操作
                childNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                return
            }
            // 递归查找深层子节点
            findAndClickButton(childNode)
            childNode.recycle() // 回收节点避免内存泄漏
        }
    }

    override fun onInterrupt() {
        // 服务被中断时的空实现,可按需添加逻辑
    }
}

3. 在AndroidManifest中注册服务

在AndroidManifest.xml的<application>标签内添加服务注册代码:

<service
    android:name=".AutoClickService"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_service_config" />
</service>

4. Flutter端实现权限引导与控制

Flutter代码中添加权限引导按钮,并通过MethodChannel与原生交互:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('自动点击工具')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () async {
                  // 跳转至系统无障碍设置页面
                  await const MethodChannel('com.yourpackage.name/accessibility')
                      .invokeMethod('openAccessibilitySettings');
                },
                child: const Text('开启无障碍权限'),
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  // 可扩展:通过MethodChannel向原生传递动态目标ID或启停指令
                },
                child: const Text('启动自动点击'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

修改Android原生MainActivity.kt,添加MethodChannel处理逻辑:

package com.yourpackage.name

import android.content.Intent
import android.provider.Settings
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.yourpackage.name/accessibility"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            when (call.method) {
                "openAccessibilitySettings" -> {
                    val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
                    startActivity(intent)
                    result.success(null)
                }
                else -> result.notImplemented()
            }
        }
    }
}

三、关键注意事项

  • 权限要求:必须由用户手动开启无障碍权限,应用无法自动获取
  • 控件ID格式:必须使用uiautomatorviewer获取的完整ID(包含包名前缀),不能仅使用控件ID后缀
  • 包名准确性:目标应用的包名必须准确,否则服务无法识别前台应用
  • 内存管理:遍历AccessibilityNodeInfo时必须调用recycle()回收节点,避免内存泄漏

内容的提问来源于stack exchange,提问作者MINH-HAI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:31:15