如何将Expo安卓应用转为无障碍服务?构建开发版遇报错
问题背景
我接触Expo仅几周,想要开发一款安卓应用拦截器(App Blocker),比如限制每日打开YouTube不超过1小时,这类应用属于Android Accessibility Service。我了解需使用开发构建版本(Expo Go无法作为无障碍服务),因此通过npx create-expo-module@latest --local创建本地自定义模块(否则会触发GitHub上的相关报错)。随后我参照Android官方指南修改了模块中modules/my-module/android/src/main/AndroidManifest.xml文件,并创建了继承AccessibilityService的类:
import android.accessibilityservice.AccessibilityService import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo class MyAccessibilityService : AccessibilityService() { override fun onAccessibilityEvent(event: AccessibilityEvent) { if (event.packageName != null && event.packageName.toString() == "com.google.android.youtube") { performGlobalAction(GLOBAL_ACTION_BACK) } } override fun onInterrupt() { } }
但运行eas build --profile development --platform android构建时,在“Run gradlew”步骤出现错误:
FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:processDebugMainManifest'. > Manifest merger failed with multiple errors, see logs * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 4m 3s Error: Gradle build failed with unknown error. See logs for the "Run gradlew" phase for more information.
请问我的实现方式是否正确?若正确,该如何解决此构建错误?
解答
一、实现方式的合理性
整体思路没问题:
- 无障碍服务确实不能用Expo Go,必须用开发构建包,这个判断正确
- 用本地自定义模块创建的方式避开远程模块的GitHub报错,操作正确
- AccessibilityService的基础代码结构符合要求,重写了两个必要方法,当前逻辑能检测到YouTube并执行返回操作
但要注意:当前代码只是简单拦截打开,还没实现「每日不超过1小时」的计时逻辑,后续得补充本地存储(比如用Expo Secure Store或者安卓SharedPreferences)记录使用时长,结合时间戳判断是否超限。
二、修复Manifest合并错误
Manifest合并失败的核心是无障碍服务的配置不符合Expo模块规范,或者和主应用Manifest冲突,按以下步骤处理:
修正模块Manifest的服务声明
打开modules/my-module/android/src/main/AndroidManifest.xml,确保无障碍服务的声明包含以下内容:- 必须加
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"权限 - 必须用
<intent-filter>指定android.accessibilityservice.AccessibilityService动作 - 必须通过
<meta-data>关联无障碍服务的配置文件
正确示例:
<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>- 必须加
添加无障碍服务配置文件
在模块的android/src/main/res/xml目录下新建accessibility_service_config.xml(xml目录不存在就手动创建),内容至少包含基础监听配置:<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canPerformGestures="true" />其中
typeWindowStateChanged是检测应用切换必须的事件类型,正好匹配你的拦截需求。排查具体冲突项
如果上述两步做完仍报错,直接执行eas build --profile development --platform android --debug查看详细合并日志,找到具体冲突点(比如权限重复、服务名冲突等)。常见冲突是主应用和模块Manifest重复声明权限,此时可在模块Manifest的冲突项上添加tools:replace属性(需先在根节点添加xmlns:tools="http://schemas.android.com/tools")。验证模块配置文件
检查modules/my-module/package.json中的android字段,确保正确声明了服务:"android": { "package": "com.yourname.mymodule", "services": [ ".MyAccessibilityService" ] }
内容的提问来源于stack exchange,提问作者Oraylien

