Flutter无障碍服务插件flutter_accessibility_service的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter无障碍服务插件flutter_accessibility_service的使用

flutter_accessibility_service 是一个用于与Android系统的无障碍服务进行交互的Flutter插件。无障碍服务旨在帮助残障用户更好地使用Android设备和应用程序,或者获取系统事件如键盘按键事件或通知接收事件等。下面将详细介绍该插件的安装、配置及使用方法,并提供完整的示例代码。

安装与配置

1. 添加依赖

在项目的pubspec.yaml文件中添加以下内容:

dependencies:
  flutter_accessibility_service: ^最新版本号 # 请根据实际情况填写具体版本号

然后执行 flutter pub get 命令以下载并安装插件。

2. 配置 AndroidManifest.xml

android/app/src/main/AndroidManifest.xml 文件中的 <application> 标签内添加如下代码片段,以便将无障碍服务绑定到您的应用程序上:

<service android:name="slayer.accessibility.service.flutter_accessibility_service.AccessibilityListener"
         android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" android:exported="false">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService"/>
    </intent-filter>
    <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice"/>
</service>

3. 创建无障碍服务配置文件

res/xml 目录下创建名为 accessibilityservice.xml 的文件,并添加如下内容:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeWindowsChanged|typeWindowStateChanged|typeWindowContentChanged"
    android:accessibilityFeedbackType="feedbackVisual"
    android:notificationTimeout="300"
    android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews|flagRequestTouchExplorationMode|flagRequestEnhancedWebAccessibility|flagReportViewIds|flagRetrieveInteractiveWindows"
    android:canRetrieveWindowContent="true"/>

使用说明

检查并请求无障碍权限

在使用无障碍功能之前,您需要先检查是否已经授予了无障碍权限,如果没有,则可以引导用户去设置页面开启它。

// 检查无障碍权限状态
final bool isEnabled = await FlutterAccessibilityService.isAccessibilityPermissionEnabled();

// 请求无障碍权限
if (!isEnabled) {
  final bool granted = await FlutterAccessibilityService.requestAccessibilityPermission();
}

监听无障碍事件

通过订阅 accessStream 来监听来自其他应用或系统的无障碍事件流。

FlutterAccessibilityService.accessStream.listen((event) {
  print("Received Event: $event");
});

自动化操作

您可以对特定节点执行一系列预定义的操作,例如点击、滚动等。

await FlutterAccessibilityService.performAction(
  event.nodeId!,
  NodeAction.actionClick,
);

全局动作

除了针对特定节点的操作外,还可以执行一些全局级别的动作,比如返回主页、截屏等。

await FlutterAccessibilityService.performGlobalAction(
  GlobalAction.globalActionTakeScreenshot,
);

示例项目

以下是包含上述所有特性的完整示例代码,您可以直接复制并在自己的项目中运行。

import 'dart:async';
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter_accessibility_service/accessibility_event.dart';
import 'package:flutter_accessibility_service/constants.dart';
import 'package:flutter_accessibility_service/flutter_accessibility_service.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  StreamSubscription<AccessibilityEvent>? _subscription;
  List<AccessibilityEvent?> events = [];
  DateTime eventDateTime = DateTime.now();
  bool foundSearchField = false;
  bool setText = false;
  bool clickFirstSearch = false;

  void handleAccessiblityStream() {
    foundSearchField = false;
    setText = false;
    if (_subscription?.isPaused ?? false) {
      _subscription?.resume();
      return;
    }
    _subscription =
        FlutterAccessibilityService.accessStream.listen((event) async {
      setState(() {
        events.add(event);
      });
      // 这里可以根据接收到的事件做进一步处理
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Column(
            children: [
              SingleChildScrollView(
                scrollDirection: Axis.horizontal,
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    TextButton(
                      onPressed: () async {
                        await FlutterAccessibilityService.requestAccessibilityPermission();
                      },
                      child: const Text("Request Permission"),
                    ),
                    const SizedBox(width: 20.0),
                    TextButton(
                      onPressed: () async {
                        final bool res = await FlutterAccessibilityService.isAccessibilityPermissionEnabled();
                        log("Is enabled: $res");
                      },
                      child: const Text("Check Permission"),
                    ),
                    const SizedBox(width: 20.0),
                    TextButton(
                      onPressed: handleAccessiblityStream,
                      child: const Text("Start Stream"),
                    ),
                    const SizedBox(width: 20.0),
                    TextButton(
                      onPressed: () {
                        _subscription?.cancel();
                      },
                      child: const Text("Stop Stream"),
                    ),
                    TextButton(
                      onPressed: () async {
                        await FlutterAccessibilityService.performGlobalAction(
                          GlobalAction.globalActionTakeScreenshot,
                        );
                      },
                      child: const Text("Take ScreenShot"),
                    ),
                    TextButton(
                      onPressed: () async {
                        final list = await FlutterAccessibilityService.getSystemActions();
                        log('$list');
                      },
                      child: const Text("List GlobalActions"),
                    ),
                  ],
                ),
              ),
              Expanded(
                child: ListView.builder(
                  shrinkWrap: true,
                  itemCount: events.length,
                  itemBuilder: (_, index) => ListTile(
                    title: Text(events[index]?.packageName ?? ''),
                    subtitle: Text(
                      (events[index]?.subNodes ?? [])
                          .map((e) => e.actions)
                          .expand((element) => element!)
                          .contains(NodeAction.actionClick)
                          ? 'Have Action to click'
                          : '',
                    ),
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

以上就是关于 flutter_accessibility_service 插件的基本介绍和使用指南。希望这些信息能帮助您更好地理解和利用这个强大的工具来增强您应用的无障碍特性。


更多关于Flutter无障碍服务插件flutter_accessibility_service的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter无障碍服务插件flutter_accessibility_service的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,flutter_accessibility_service插件允许开发者创建无障碍服务,以支持视觉、听觉或运动障碍的用户。以下是一个基本的使用案例,展示如何设置和使用该插件。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加flutter_accessibility_service依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_accessibility_service: ^x.y.z # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

2. 配置Android无障碍服务

android/app/src/main/AndroidManifest.xml中,添加必要的无障碍服务声明:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <application
        ...>
        <service
            android:name=".MyAccessibilityService"
            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>
    </application>
</manifest>

创建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:packageNames="com.example.targetapp"
    android:accessibilityFeedbackType="feedbackAllMask"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:accessibilityFlags="flagIncludeNotImportantViews | flagReportViewIds"
    android:description="@string/accessibility_service_description"
    android:settingsActivity="com.example.yourapp.SettingsActivity" />

res/values/strings.xml中添加描述:

<resources>
    <string name="accessibility_service_description">Your Accessibility Service Description</string>
</resources>

3. 创建无障碍服务类

android/app/src/main/kotlin/com/example/yourapp/(或Java对应的目录)下创建一个Kotlin/Java类,继承AccessibilityService

package com.example.yourapp

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

class MyAccessibilityService : AccessibilityService() {

    override fun onAccessibilityEvent(event: AccessibilityEvent?) {
        event?.let {
            // 处理无障碍事件,例如读取文本、执行动作等
            val source = it.source
            val text = source?.className?.toString() ?: "No text found"
            // 打印或处理文本
        }
    }

    override fun onInterrupt() {
        // 当服务被中断时调用
    }
}

4. Flutter端调用

在Flutter中,你可以通过MethodChannel与原生无障碍服务进行通信,但这通常需要更多的自定义逻辑。由于flutter_accessibility_service插件本身不直接提供高级API来启动或管理无障碍服务(它更多是作为桥接层),你可能需要更深入地集成原生代码。

不过,基本的Flutter代码结构可能如下:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Accessibility Service Demo'),
        ),
        body: Center(
          child: Text('Check your device settings to enable the accessibility service.'),
        ),
      ),
    );
  }
}

注意

  • 由于无障碍服务涉及用户隐私和系统安全,因此在发布应用前,请确保你遵循了所有相关的隐私政策和平台指南。
  • flutter_accessibility_service插件的具体用法可能会随着版本更新而变化,请参考官方文档和示例代码以获取最新信息。

这个示例提供了一个基本的框架,但具体实现将取决于你的应用需求和服务逻辑。

回到顶部