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

Android应用内调用screencap截图返回1生成0B文件解决方案

问题核心原因

screencap 进程返回码1、生成0B文件的根本原因不是存储权限不足,是普通第三方应用进程本身没有读取屏幕帧缓冲区的权限:

  1. 你声明的ACCESS_SUPERUSER仅为权限声明标记,不代表应用实际获取了Root授权,普通应用进程直接执行/system/bin/screencap会被SELinux规则拦截,根本拿不到屏幕画面数据。
  2. 从Android 10开始,系统进一步收紧了非特权进程对系统二进制和帧缓冲区的访问限制,就算申请了全文件访问权限,无Root/无系统签名的应用直接调用screencap必然执行失败。
可行解决方法

根据你的应用权限等级选对应方案即可:

  • Root环境下修正screencap调用逻辑
    你当前的代码是直接在应用自身进程启动screencap,没有走su提权流程,自然会被权限拦截。正确的提权调用代码参考:
    fun takeScreenShotWithRoot(badge:String){
        thread {
            val date = Date()
            val formatDate: CharSequence = DateFormat.format("ddMMyyyyhhmmss", date)
            val filename = "${badge}_${formatDate}"
            val targetDir = "${Environment.getExternalStorageDirectory()}/DCIM/Screenshots/"
            val targetPath = "$targetDir$filename.png"
            try {
                // 先提权获取su shell
                val suProcess = Runtime.getRuntime().exec("su")
                val shellOs = suProcess.outputStream
                // 先确保目标目录存在,再执行截图命令,最后退出su进程
                val commands = """
                    mkdir -p $targetDir
                    /system/bin/screencap -p $targetPath
                    exit
                  """.trimIndent()
                shellOs.write(commands.toByteArray())
                shellOs.flush()
                val exitCode = suProcess.waitFor()
                shellOs.close()
                if(exitCode == 0){
                    Log.d("ScreenshotHDL", "Screenshot saved to $targetPath")
                }else{
                    // 调试时记得读取错误流打印具体报错
                    val errorMsg = suProcess.errorStream.bufferedReader().readText()
                    Log.e("ScreenshotHDL", "Screenshot failed, error: $errorMsg")
                }
            }catch (e:Exception){
                Log.e("ScreenshotHDL", "Exec error: ${e.message}")
            }
        }
    }
    
    注意:该方案仅在设备已Root、用户给你的应用授予Root权限后生效。
  • 无Root环境下用官方MediaProjection API实现(Overlay应用推荐)
    这是Android 5.0+系统给普通第三方应用开放的唯一合法屏幕采集方式,不需要Root、不需要系统签名,只需要用户一次性授权即可使用:
    1. 通过MediaProjectionManager.createScreenCaptureIntent()创建授权请求Intent,启动后等待用户同意授权
    2. 拿到授权结果后获取MediaProjection实例,创建VirtualDisplay把屏幕内容投射到ImageReader的Surface上
    3. 从ImageReader中实时获取Image对象,转成Bitmap后通过MediaStore API存入公共截图目录即可
      该方案兼容性最好,不会被系统权限拦截,是目前普通截图类、悬浮窗类应用的主流实现方式。
  • 系统签名/预装应用场景
    如果你的应用是系统预装应用、持有平台签名,可以额外声明android.permission.READ_FRAME_BUFFER权限,声明后直接调用screencap即可正常执行,不需要Root提权。普通第三方应用无法获取该权限。
你当前代码的其他待修正点
  • 调试shell命令执行问题时,一定要读取进程的errorStream打印错误信息,你现在只读了标准输出流,看不到具体的权限拒绝、路径不存在等报错,会大幅增加调试成本。
  • 不要直接拼接shell命令字符串执行,路径包含空格、特殊字符时会出现命令解析错误,复杂命令建议用ProcessBuilder传参数数组的方式调用。
  • Android 10+分区存储机制下,不建议直接拼接/sdcard/硬编码路径写文件,优先使用MediaStore API访问公共目录,避免部分厂商ROM的路径访问限制。

内容的提问来源于stack exchange,提问作者Joan adonys

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:42:16