android-pendingintent - 通过 RUN_COMMAND_SERVICE 意图从 Termux 接收结果
问题描述
我开发了一个 android 应用程序来向 Termux 发送一个意图并让它运行一个特定的任务。我已经设法做到了,使用以下代码:
public void downloadWithReponse() {
Intent intent = new Intent();
intent.setClassName("com.termux", "com.termux.app.RunCommandService");
intent.setAction("com.termux.RUN_COMMAND");
intent.putExtra("com.termux.RUN_COMMAND_PATH", "/data/data/com.termux/files/usr/bin/touch");
intent.putExtra("com.termux.RUN_COMMAND_ARGUMENTS", new String[]{"/sdcard/test.txt"});
intent.putExtra("com.termux.RUN_COMMAND_BACKGROUND", true);
intent.putExtra(TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE.EXTRA_SESSION_ACTION, "0");
intent.putExtra(TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE.EXTRA_COMMAND_LABEL, "touch command");
intent.putExtra(TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE.EXTRA_COMMAND_DESCRIPTION, "Runs the touch command to show processes using the most resources.");
// Create the intent for the IntentService class that should be sent the result by TermuxService
Intent pluginResultsServiceIntent = new Intent(MainActivity.this, PluginResultsService.class);
// Generate a unique execution id for this execution command
int executionId = PluginResultsService.getNextExecutionId();
// Optional put an extra that uniquely identifies the command internally for your app.
// This can be an Intent extra as well with more extras instead of just an int.
pluginResultsServiceIntent.putExtra(PluginResultsService.EXTRA_EXECUTION_ID, executionId);
// Create the PendingIntent that will be used by TermuxService to send result of
// commands back to the IntentService
// Note that the requestCode (currently executionId) must be unique for each pending
// intent, even if extras are different, otherwise only the result of only the first
// execution will be returned since pending intent will be cancelled by android
// after the first result has been sent back via the pending intent and termux
// will not be able to send more.
PendingIntent pendingIntent = PendingIntent.getService(MainActivity.this, executionId, pluginResultsServiceIntent, PendingIntent.FLAG_ONE_SHOT);
intent.putExtra(TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT, pendingIntent);
try {
// Send command intent for execution
Log.d("Termux", "Sending execution command with id " + executionId);
//startService(intent);
startForegroundService(intent);
} catch (Exception e) {
Log.e("Termux", "Failed to start execution command with id " + executionId + ": " + e.getMessage());
}
}
使用类 PluginResultsService:
public class PluginResultsService extends IntentService {
public static final String EXTRA_EXECUTION_ID = "execution_id";
private static int EXECUTION_ID = 1000;
public static final String PLUGIN_SERVICE_LABEL = "PluginResultsService";
private static final String LOG_TAG = "PluginResultsService";
public PluginResultsService(){
super(PLUGIN_SERVICE_LABEL);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
if (intent == null) return;
Log.d(LOG_TAG, PLUGIN_SERVICE_LABEL + " received execution result");
final Bundle resultBundle = intent.getBundleExtra(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE);
if (resultBundle == null) {
Log.e(LOG_TAG, "The intent does not contain the result bundle at the \"" + TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE + "\" key.");
return;
}
final int executionId = intent.getIntExtra(EXTRA_EXECUTION_ID, 0);
Log.d(LOG_TAG, "Execution id " + executionId + " result:\n" +
"stdout:\n```\n" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT, "") + "\n```\n" +
"stdout_original_length: `" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH) + "`\n" +
"stderr:\n```\n" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDERR, "") + "\n```\n" +
"stderr_original_length: `" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH) + "`\n" +
"exitCode: `" + resultBundle.getInt(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE) + "`\n" +
"errCode: `" + resultBundle.getInt(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_ERR) + "`\n" +
"errmsg: `" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG, "") + "`");
}
public static synchronized int getNextExecutionId() {
return EXECUTION_ID++;
}
}
上面的代码运行良好。可以看到sdcard目录下创建的文件,用logcat可以看到adb中的日志。
我的问题是我似乎无法在我的 Android 应用程序中找到从 Termux 获得响应的方法,以查看命令是否已执行,或者是否失败等。我尝试从我的应用程序中读取 logcat,但它需要系统授权,所以这对我来说是不行的。
你知道我如何使用意图来做到这一点吗?
编辑:
我已经解决了这个问题:我的 Termux 版本太旧,不支持意图结果......
但是,我现在有另一个问题,即只有在命令完全完成后才能获得命令的结果。例如,如果我的命令是下载命令,我将在 100% 下载后获取所有 ETA 和 % 下载的消息。
有任何想法吗?
解决方案
推荐阅读
- r - 在 R 中 - 使用百分比回报计算向量中的值
- javascript - 为什么我的 React App 有 index.pack.js 的语法错误?
- database - 如何将云firestore中的单个文档字段保存到flutter中的局部变量中?
- r - R编程中的街道地址图绘制
- vb.net - 将字符串转换为双精度并添加总计
- javascript - 如何在 FabricJS 的父对象的中心创建对象棒?
- android - VSCode 中的 Flutter beta 热重载适用于 Web,但不适用于 iOS 和 Android(适用于 Android Studio)
- php - CRUD delete using modal form
- python-3.x - 在某些条件下验证用户名和密码
- c# - 有没有办法将 .Net TimeZoneInfo 转换为 Java ZonedDateTime?