PAYATHON 2026

Termux RunCommandService 回调的结果 Bundle 为什么为空?

数据阿明

结论:结果回调需要可变的 PendingIntent

所给代码中的 PendingIntent.FLAG_IMMUTABLE 会阻止 Termux 发送回调时补入结果数据。应移除该标志,并在 Android 12(API 31)及以上使用 PendingIntent.FLAG_MUTABLE。

Android 文档说明,设置 FLAG_IMMUTABLE 后,调用方通过 send() 传入、用于补充原始 Intent 的数据会被忽略。这可以解释当前现象:预先设置的 execution_id 仍然存在,后来加入的结果 Bundle 却没有进入回调。PendingIntent 官方说明

修改 PendingIntent 的创建代码

在 TermuxUtils.java 中添加:

import android.os.Build;

将创建回调 Intent 和 PendingIntent 的部分替换为:

int execId = TermuxPluginResultsService.getNextExecutionId();

Intent pluginResultsService =
        new Intent(context, TermuxPluginResultsService.class);
pluginResultsService.putExtra(
        TermuxPluginResultsService.EXTRA_EXECUTION_ID,
        execId
);

int flags = PendingIntent.FLAG_ONE_SHOT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    flags |= PendingIntent.FLAG_MUTABLE;
}

PendingIntent pendingIntent = PendingIntent.getService(
        context,
        execId,
        pluginResultsService,
        flags
);

intent.putExtra(
        TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT,
        pendingIntent
);

context.startForegroundService(intent);

要引用 Build.VERSION_CODES.S 和 FLAG_MUTABLE,compileSdk 需要至少为 31。API 30 及以下在未设置 FLAG_IMMUTABLE 时默认允许修改;API 31 及以上则通过上述分支显式设置可变性。不要同时设置 FLAG_MUTABLE 和 FLAG_IMMUTABLE。PendingIntent 可变性说明

保留原来的显式组件 new Intent(context, TermuxPluginResultsService.class),使回调继续指向指定服务。

保留结果 Bundle 的读取方式

现有读取方式符合 Termux 文档:通过请求中的 EXTRA_PENDING_INTENT 指定回调,再从回调 Intent 的 EXTRA_PLUGIN_RESULT_BUNDLE 中读取结果。EXTRA_BACKGROUND 为 true 时,该 Bundle 提供 stdout、stderr 和 exit code。Termux 结果回传说明

先保留现有读取逻辑,用简单命令验证:

TermuxUtils.exec(this, "echo HelloWorld");

验证时依次检查:

  1. onHandleIntent 是否被调用。
  2. EXTRA_PLUGIN_RESULT_BUNDLE 是否存在。
  3. stdout 是否包含 HelloWorld。
  4. exitCode 是否为 0。

这些是正常执行时的预期结果,并非当前设备上已经验证过的日志。stderr 可以为空,不能仅凭它为空判断回传失败。

问题中额外添加的 RUN_COMMAND_RETURN_STDOUT、return_stdout 等键不属于该文档列出的结果回传参数,可以移除。修复重点是回调 PendingIntent 的可变性。

为什么迁移 AndroidX 后才出现

现有材料不足以认定 AndroidX 本身导致了故障。当前代码显式设置了 FLAG_IMMUTABLE,这与回调需要补入结果数据的要求冲突。

可以对比迁移前后的 PendingIntent 创建代码,以及同步调整过的 SDK 配置。如果迁移期间新增了 FLAG_IMMUTABLE,就能解释这次行为变化;仅凭迁移前后是否正常,无法确定是哪一项改动引起的。

修改后仍为空时检查什么

先确认实际运行的构建已使用修改后的代码,再重新发起一次命令请求。如果仍然失败,检查 Termux 版本和基础配置:结果回传要求 Termux >= 0.109;调用应用需要获授 com.termux.permission.RUN_COMMAND,Termux 的 ~/.termux/termux.properties 中需要设置 allow-external-apps=true。Termux 配置与版本要求

当前日志表明接收服务已经进入 onHandleIntent,应先排查回调数据为何未被补入。确认结果 Bundle 能正常收到后,再测试实际的 git 命令及其工作目录。

备注:内容仅供参考。