Android无障碍服务截图返回错误码1的原因及解决方法
错误码1的原因分析
错误码1是Android辅助功能服务启动失败的常见标识,主要由以下几种情况导致:
- 辅助功能服务未被系统启用:AccessibilityService必须由用户在系统设置的「辅助功能」页面手动开启,未启用状态下所有服务调用都会返回失败。
- 权限声明不完整:Manifest文件中缺少
android.permission.BIND_ACCESSIBILITY_SERVICE权限,或者辅助服务的配置文件(accessibility_service_config.xml)参数错误,导致系统无法绑定服务。 - MediaProjection权限未获取:截图依赖MediaProjection的屏幕录制权限,若用户拒绝授权请求,或未正确发起授权流程,会导致截图服务启动失败。
- 调用时机错误:在AccessibilityService未完成绑定(未触发
onServiceConnected)时就调用截图逻辑,或在非服务上下文(如普通Activity)直接执行截图操作。
AccessibilityService实现截图的正确方式
1. 配置辅助功能服务
(1)Manifest注册服务
确保在AndroidManifest.xml中正确声明服务,包含必要权限和配置:
<service android:name=".ScreenshotAccessibilityService" 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>
(2)创建辅助服务配置文件
在res/xml/目录下创建accessibility_service_config.xml,开启窗口内容获取权限:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:description="@string/accessibility_service_desc" />
description需要在strings.xml中定义,用于系统设置中展示服务说明。
2. 获取MediaProjection权限
截图依赖屏幕录制权限,必须从Activity发起授权请求:
private static final int REQ_SCREEN_CAPTURE = 100; private void requestScreenCapturePermission() { MediaProjectionManager manager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); Intent captureIntent = manager.createScreenCaptureIntent(); startActivityForResult(captureIntent, REQ_SCREEN_CAPTURE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQ_SCREEN_CAPTURE && resultCode == RESULT_OK) { // 将授权结果传递给AccessibilityService ScreenshotAccessibilityService.setCaptureParams(resultCode, data); } }
3. 实现AccessibilityService截图逻辑
@AutoService(AccessibilityService.class) public class ScreenshotAccessibilityService extends AccessibilityService { private static int sResultCode; private static Intent sCaptureData; private MediaProjection mMediaProjection; private ImageReader mImageReader; private DisplayMetrics mMetrics; public static void setCaptureParams(int resultCode, Intent data) { sResultCode = resultCode; sCaptureData = data; } @Override public void onServiceConnected() { super.onServiceConnected(); // 初始化屏幕参数 mMetrics = getResources().getDisplayMetrics(); // 创建MediaProjection实例 MediaProjectionManager manager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); mMediaProjection = manager.getMediaProjection(sResultCode, sCaptureData); // 初始化ImageReader用于接收截图数据 mImageReader = ImageReader.newInstance(mMetrics.widthPixels, mMetrics.heightPixels, PixelFormat.RGBA_8888, 1); } // 对外提供的截图方法,可通过按钮点击触发 public void takeScreenshot() { if (mMediaProjection == null || mImageReader == null) { return; } // 创建虚拟显示器,将屏幕内容投射到ImageReader的Surface mMediaProjection.createVirtualDisplay("ScreenshotDisplay", mMetrics.widthPixels, mMetrics.heightPixels, mMetrics.densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null); // 监听截图图像可用事件 mImageReader.setOnImageAvailableListener(reader -> { try (Image image = reader.acquireLatestImage()) { if (image == null) return; // 将Image转换为Bitmap Image.Plane[] planes = image.getPlanes(); ByteBuffer buffer = planes[0].getBuffer(); int pixelStride = planes[0].getPixelStride(); int rowStride = planes[0].getRowStride(); int rowPadding = rowStride - pixelStride * mMetrics.widthPixels; Bitmap bitmap = Bitmap.createBitmap(mMetrics.widthPixels + rowPadding / pixelStride, mMetrics.heightPixels, Bitmap.Config.ARGB_8888); bitmap.copyPixelsFromBuffer(buffer); // 裁剪掉多余的padding bitmap = Bitmap.createBitmap(bitmap, 0, 0, mMetrics.widthPixels, mMetrics.heightPixels); // 保存或处理截图 saveScreenshot(bitmap); } }, null); } private void saveScreenshot(Bitmap bitmap) { // 示例:保存到应用私有目录 File screenshotFile = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "screenshot_" + System.currentTimeMillis() + ".png"); try (FileOutputStream fos = new FileOutputStream(screenshotFile)) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); } catch (IOException e) { e.printStackTrace(); } } @Override public void onAccessibilityEvent(AccessibilityEvent event) { // 可选:监听窗口事件,自动触发截图 } @Override public void onInterrupt() { // 服务中断时清理资源 if (mMediaProjection != null) { mMediaProjection.stop(); mMediaProjection = null; } if (mImageReader != null) { mImageReader.close(); mImageReader = null; } } }
4. 引导用户开启辅助功能服务
在APP中添加引导逻辑,跳转到系统辅助功能设置页面:
private void openAccessibilitySettings() { Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); startActivity(intent); }
注意事项
- Android 10及以上版本,保存截图到公共目录需要
WRITE_EXTERNAL_STORAGE权限,或使用MediaStore API进行存储。 - 必须确保AccessibilityService已启用且MediaProjection权限已获取,才能调用
takeScreenshot方法。 - 服务销毁时需及时清理MediaProjection和ImageReader资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Toby
相关产品推荐
相关产品推荐

