ProcessBuilder执行adb广播命令与终端输出不一致问题
问题:ProcessBuilder执行adb广播命令时参数解析异常,输出与终端不符
问题现象
终端执行以下adb广播命令时,输出正常:
adb shell am broadcast -p com.sample -a sample.action -e "extra" "bla bla"
正确输出:
Broadcasting: Intent { act=sample.action flg=0x400000 pkg=com.sample (has extras) } Broadcast completed: result=0
但通过ProcessBuilder执行相同逻辑的命令时,输出异常,Intent被错误解析为默认的启动意图:
Broadcasting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x400000 pkg= -p } Broadcast completed: result=0
核心原因
问题出在命令参数的拆分方式和字符串拼接的引号处理上:
- 错误的参数拆分逻辑:你用
"\\s".toRegex().split(this)按空格拆分整串命令字符串,这种方式会无视引号的存在,把所有空格都当成参数分隔符。比如终端里的-e "extra" "bla bla"会被拆成["-e", "\"extra\"", "\"bla", "bla\""],导致adb收到的参数完全混乱,无法正确解析广播意图。 - 多余的引号包裹:构建cmd字符串时,你给payload添加了额外的单引号和双引号(
"'${payload...}'"),这些引号会被当成参数的一部分传递给adb,进一步干扰参数解析。
另外需要注意:ProcessBuilder的参数列表是直接传递给目标程序的,不会像shell那样自动解析引号和空格,所以整串命令拆分的方式从根本上就不适合ProcessBuilder的参数传递逻辑。
解决方案
放弃字符串拼接+空格拆分的方式,直接给ProcessBuilder传递独立的参数列表,每个参数作为列表的一个元素,不需要额外添加引号。
修改后的代码示例
1. 重构runCommand函数,支持参数列表
private fun List<String>.runCommand(workingDir: File = File("."), timeoutAmount: Long = 60, timeoutUnit: TimeUnit = TimeUnit.SECONDS): String? { return try { runCatching { ProcessBuilder(this) .directory(workingDir) .redirectOutput(ProcessBuilder.Redirect.PIPE) .redirectError(ProcessBuilder.Redirect.PIPE) .start() .also { it.waitFor(timeoutAmount, timeoutUnit) } .inputStream.bufferedReader().readText() }.onFailure { it.printStackTrace() }.getOrThrow() } catch (e: Exception) { e.message } }
2. 构建正确的参数列表
val extraFlag = if (emulator) "-e" else "-d" val cmdArgs = listOf( "adb", "shell", "am", "broadcast", "-p", applicationId, "-a", action, extraFlag, "extra", payload.replace("\\s".toRegex(), "") ) // 执行命令 cmdArgs.runCommand()
为什么这样能解决问题
- 每个参数都是独立的列表元素,ProcessBuilder会原封不动地传递给adb,不会出现参数被错误拆分的情况。
- 不需要额外添加引号,adb会直接识别参数的边界,正确解析广播意图的各个字段。
内容的提问来源于stack exchange,提问作者GuilhE
相关产品推荐
相关产品推荐

