基本实现NFC Build View 模块功能。

This commit is contained in:
2026-03-15 20:25:16 +08:00
parent 73c69bd665
commit 7713d6c460
3 changed files with 99 additions and 118 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sun Mar 15 11:38:00 GMT 2026 #Sun Mar 15 12:22:44 GMT 2026
stageCount=26 stageCount=26
libraryProject= libraryProject=
baseVersion=15.11 baseVersion=15.11
publishVersion=15.11.25 publishVersion=15.11.25
buildCount=10 buildCount=21
baseBetaVersion=15.11.26 baseBetaVersion=15.11.26

View File

@@ -293,7 +293,8 @@
<activity <activity
android:name=".termux.NfcTermuxBridgeActivity" android:name=".termux.NfcTermuxBridgeActivity"
android:exported="true"> android:exported="true"
android:launchMode="singleTop">
<intent-filter> <intent-filter>
<action android:name="cc.winboll.nfc.ACTION_EXEC_TERMUX" /> <action android:name="cc.winboll.nfc.ACTION_EXEC_TERMUX" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />

View File

@@ -1,222 +1,202 @@
/*
* 源码说明与描述:
* NFC 与 Termux 桥接活动,用于接收 NFC 传递的 JSON 指令并执行 Termux 脚本命令,
* 支持后台执行与终端窗口唤起两种模式,提供测试注入接口。
*
* 作者:豆包&ZhanGSKen<zhangsken@qq.com>
* 创建时间2025-03-15 14:00:00
* 最后编辑时间2026-03-15 15:22:00
*/
package cc.winboll.studio.winboll.termux; package cc.winboll.studio.winboll.termux;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View;
import android.widget.Toast; import android.widget.Toast;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.winboll.models.NfcTermuxCmd; import cc.winboll.studio.winboll.models.NfcTermuxCmd;
import com.google.gson.Gson; import com.google.gson.Gson;
public class NfcTermuxBridgeActivity extends Activity { public class NfcTermuxBridgeActivity extends Activity {
private static final String TAG = "NfcTermuxBridge"; // ========================= 常量与静态属性 =========================
private static final String ACTION_BUILD_VIEW = NfcTermuxBridgeActivity.class.getName() + ".ACTION_BUILD_VIEW"; public static final String TAG = "NfcTermuxBridgeActivity";
public static final String ACTION_BUILD_VIEW = NfcTermuxBridgeActivity.class.getName() + ".ACTION_BUILD_VIEW";
private static final Gson GSON = new Gson(); private static final Gson GSON = new Gson();
// ========================= 生命周期方法 =========================
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
handleNfcIntent(getIntent()); LogUtils.d(TAG, "onCreate() 调用savedInstanceState: " + (savedInstanceState != null ? "非空" : ""));
dispatchIntent(getIntent());
} }
@Override @Override
protected void onNewIntent(Intent intent) { protected void onNewIntent(Intent intent) {
super.onNewIntent(intent); super.onNewIntent(intent);
if (intent.getAction().equals(ACTION_BUILD_VIEW)) { LogUtils.d(TAG, "onNewIntent() 调用intent: " + (intent != null ? intent.toString() : "null"));
onOpenTermuxProjectBuildView(intent); if (intent != null) {
} else { LogUtils.d(TAG, "onNewIntent() action: " + intent.getAction());
handleNfcIntent(intent); LogUtils.d(TAG, "onNewIntent() data: " + intent.getDataString());
} LogUtils.d(TAG, "onNewIntent() extras: " + intent.getExtras());
LogUtils.d(TAG, "onNewIntent() flags: " + intent.getFlags());
LogUtils.d(TAG, "onNewIntent() component: " + intent.getComponent());
} else {
LogUtils.w(TAG, "onNewIntent() intent is null");
}
dispatchIntent(intent);
} }
// ========================= 统一 Intent 分发(合并去重) =========================
private void dispatchIntent(Intent intent) {
LogUtils.d(TAG, "dispatchIntent() 分发 intent");
if (intent == null) {
LogUtils.w(TAG, "dispatchIntent() intent is null");
return;
}
if (ACTION_BUILD_VIEW.equals(intent.getAction())) {
ToastUtils.show("ACTION_BUILD_VIEW 命中");
onOpenTermuxProjectBuildView(intent);
} else {
handleNfcIntent(intent);
}
}
// ========================= 核心业务方法 =========================
/** /**
* 处理 NFC 传递的 JSON 指令 * 处理 NFC 传递的 JSON 指令
*/ */
private void handleNfcIntent(Intent intent) { private void handleNfcIntent(Intent intent) {
if (intent == null) return; LogUtils.d(TAG, "handleNfcIntent() 调用");
if (intent == null) {
LogUtils.w(TAG, "handleNfcIntent() intent 为空");
return;
}
try { try {
String json = intent.getStringExtra(Intent.EXTRA_TEXT); String json = intent.getStringExtra(Intent.EXTRA_TEXT);
LogUtils.d(TAG, "handleNfcIntent() json: " + json);
// 1. 发布版逻辑:正常接收 NFC 传入的 JSON
if (json == null || json.isEmpty()) { if (json == null || json.isEmpty()) {
LogUtils.e(TAG, "NFC 指令为空"); LogUtils.e(TAG, "handleNfcIntent() 指令为空");
finish(); finish();
return; return;
} }
LogUtils.d(TAG, "接收 JSON" + json);
// 2. 解析指令
NfcTermuxCmd cmd = GSON.fromJson(json, NfcTermuxCmd.class); NfcTermuxCmd cmd = GSON.fromJson(json, NfcTermuxCmd.class);
LogUtils.d(TAG, "handleNfcIntent() cmd: " + cmd);
if (cmd.script == null || cmd.script.isEmpty()) { if (cmd.script == null || cmd.script.isEmpty()) {
LogUtils.e(TAG, "script 不能为空"); LogUtils.e(TAG, "handleNfcIntent() script 为空");
finish(); finish();
return; return;
} }
// 3. 拼接脚本路径
String scriptPath = "/data/data/com.termux/files/home/TermuxWorkSpaces/BashShells/AutoNFC/" + cmd.script; String scriptPath = "/data/data/com.termux/files/home/TermuxWorkSpaces/BashShells/AutoNFC/" + cmd.script;
LogUtils.d(TAG, "handleNfcIntent() 脚本路径: " + scriptPath);
// 4. 执行 Termux 命令
boolean success = TermuxCommandExecutor.executeCommand( boolean success = TermuxCommandExecutor.executeCommand(
this, this, scriptPath, cmd.args, cmd.workDir, cmd.background, cmd.resultDir
scriptPath,
cmd.args,
cmd.workDir,
cmd.background,
cmd.resultDir
); );
LogUtils.d(TAG, "handleNfcIntent() 执行结果: " + success);
// 5. 结果反馈
if (success) { if (success) {
Toast.makeText(this, "指令已发送" + cmd.script, Toast.LENGTH_SHORT).show(); Toast.makeText(this, "指令已发送: " + cmd.script, Toast.LENGTH_SHORT).show();
LogUtils.i(TAG, "执行成功" + scriptPath); LogUtils.i(TAG, "执行成功: " + scriptPath);
} else { } else {
Toast.makeText(this, "指令发送失败", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "指令发送失败", Toast.LENGTH_SHORT).show();
LogUtils.e(TAG, "执行失败"); LogUtils.e(TAG, "执行失败");
} }
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "处理异常:" + e.getMessage(), e); LogUtils.e(TAG, "handleNfcIntent() 异常: " + e.getMessage(), e);
Toast.makeText(this, "解析失败", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "解析失败", Toast.LENGTH_SHORT).show();
} finally { } finally {
finish(); finish();
} }
} }
/** /**
* 测试执行Gradle命令实时输出版唤起Termux窗口 * 唤起 Termux 窗口执行命令(实时输出版
*/ */
public void onOpenTermuxProjectBuildView(Intent intent) { public void onOpenTermuxProjectBuildView(Intent intent) {
try { LogUtils.d(TAG, "onOpenTermuxProjectBuildView() 调用");
try {
String json = intent.getStringExtra(Intent.EXTRA_TEXT); String json = intent.getStringExtra(Intent.EXTRA_TEXT);
LogUtils.d(TAG, "onOpenTermuxProjectBuildView() json: " + json);
// 1. 发布版逻辑:正常接收 NFC 传入的 JSON
if (json == null || json.isEmpty()) { if (json == null || json.isEmpty()) {
LogUtils.e(TAG, "NFC 指令为空"); LogUtils.e(TAG, "onOpenTermuxProjectBuildView() 指令为空");
finish(); finish();
return; return;
} }
LogUtils.d(TAG, "接收 JSON" + json);
// 2. 解析指令
NfcTermuxCmd cmd = GSON.fromJson(json, NfcTermuxCmd.class); NfcTermuxCmd cmd = GSON.fromJson(json, NfcTermuxCmd.class);
LogUtils.d(TAG, "onOpenTermuxProjectBuildView() cmd: " + cmd);
if (cmd.script == null || cmd.script.isEmpty()) { if (cmd.script == null || cmd.script.isEmpty()) {
LogUtils.e(TAG, "script 不能为空"); LogUtils.e(TAG, "onOpenTermuxProjectBuildView() script 为空");
finish(); finish();
return; return;
} }
// 3. 拼接脚本路径 StringBuilder targetCmd = new StringBuilder();
// String scriptPath = "/data/data/com.termux/files/home/TermuxWorkSpaces/BashShells/AutoNFC/" + cmd.script; String nfcScriptFolder = "/data/data/com.termux/files/home/TermuxWorkSpaces/BashShells/AutoNFC/";
// targetCmd.append("cd " + nfcScriptFolder + " && ");
// // 4. 执行 Termux 命令 targetCmd.append("stdbuf -o0 -e0 -i0 bash ").append(cmd.script).append(" ");
// boolean success = TermuxCommandExecutor.executeCommand( if (cmd.args != null) {
// this, for (String arg : cmd.args) {
// scriptPath, targetCmd.append(arg).append(" ");
// cmd.args, }
// cmd.workDir, }
// cmd.background, //targetCmd.append(" && echo '\n✅ 执行完成!' && echo '\n📌 项目: ").append(cmd.args != null && cmd.args.length > 0 ? cmd.args[0] : "").append("' && read -p '按回车关闭...'");
// cmd.resultDir
// );
// LogUtils.d(TAG, "onTestTermuxCMD() 按钮点击执行Gradle命令实时输出"); LogUtils.d(TAG, "onOpenTermuxProjectBuildView() 命令: " + targetCmd);
// //tvMessage.append("\n【测试执行Gradle命令实时输出】\n"); boolean cmdSuccess = TermuxCommandExecutor.executeTerminalCommand(this, targetCmd.toString());
// LogUtils.d(TAG, "onOpenTermuxProjectBuildView() 执行结果: " + cmdSuccess);
// // 1. 校验Termux是否安装
// if (!TermuxCommandExecutor.isTermuxInstalled(this)) {
// LogUtils.e(TAG, "onTestTermuxCMD() 错误未安装Termux应用");
// //tvMessage.append("错误未安装Termux应用包名com.termux\n");
// return;
// }
// 2. 定义核心路径确保路径与Termux中一致
// String gradleFullPath = "/data/data/com.termux/files/home/gradle/gradle-7.5.1/bin/gradle";
// String projectPath = TERMUX_HOME_PATH + "/"; // 项目目录
//
// 3. 构造命令核心用stdbuf禁用缓冲实现实时输出
String targetCmd = "";
// 步骤1进入项目目录不存在则创建
targetCmd += "cd " + cmd.workDir + " && ";
// 步骤2加载环境变量
targetCmd += "source ~/.bashrc && ";
// 步骤3显式配置PATH
//targetCmd += "export PATH=/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/home/gradle/gradle-7.5.1/bin:$PATH && ";
// 步骤4用stdbuf禁用stdout/stderr缓冲关键执行Gradle命令
// -o0stdout无缓冲-e0stderr无缓冲-i0stdin无缓冲
//targetCmd += "stdbuf -o0 -e0 -i0 " + gradleFullPath + " task --all | grep assemble && ";
//targetCmd += "stdbuf -o0 -e0 -i0 " + gradleFullPath + " -Pandroid.aapt2FromMavenOverride=/data/data/com.termux/files/home/android-sdk/build-tools/34.0.4/aapt2 assembleBetaDebug && ";
targetCmd += "stdbuf -o0 -e0 -i0 bash && ";
// 步骤5执行成功提示
targetCmd += "echo '\n✅ 命令执行完成!' && echo '\n📌 项目名称:" + cmd.args + "' && read -p '按回车键关闭终端...'";
// 4. 执行命令终端会话模式唤起Termux窗口
boolean cmdSuccess = TermuxCommandExecutor.executeTerminalCommand(this, targetCmd);
// 5. 结果反馈
if (cmdSuccess) { if (cmdSuccess) {
Toast.makeText(this, "指令已发送" + cmd.script + " " + cmd.args, Toast.LENGTH_SHORT).show(); Toast.makeText(this, "指令已发送: " + cmd.script + " " + (cmd.args != null && cmd.args.length > 0 ? cmd.args[0] : ""), Toast.LENGTH_SHORT).show();
LogUtils.i(TAG, "执行成功:" + cmd.script + " " + cmd.args);
} else { } else {
Toast.makeText(this, "指令发送失败", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "指令发送失败", Toast.LENGTH_SHORT).show();
LogUtils.e(TAG, "执行失败");
} }
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "处理异常:" + e.getMessage(), e); LogUtils.e(TAG, "onOpenTermuxProjectBuildView() 异常: " + e.getMessage(), e);
Toast.makeText(this, "解析失败", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "解析失败", Toast.LENGTH_SHORT).show();
} finally { } finally {
finish(); finish();
} }
} }
// =========================================================== // ========================= 公共静态测试方法 =========================
// 公共静态测试函数:外部可直接调用注入测试 JSON
// ===========================================================
public static void testCommand(Context context) { public static void testCommand(Context context) {
LogUtils.d(TAG, "testCommand()");
try { try {
// 测试用指令
String testJson = "{\"script\":\"BuildWinBoLLProject.sh\",\"args\":[\"DebugTemp\"],\"workDir\":null,\"background\":true,\"resultDir\":null}"; String testJson = "{\"script\":\"BuildWinBoLLProject.sh\",\"args\":[\"DebugTemp\"],\"workDir\":null,\"background\":true,\"resultDir\":null}";
Intent intent = new Intent(context, NfcTermuxBridgeActivity.class);
Intent testIntent = new Intent(context, NfcTermuxBridgeActivity.class); intent.putExtra(Intent.EXTRA_TEXT, testJson);
testIntent.putExtra(Intent.EXTRA_TEXT, testJson); context.startActivity(intent);
// 模拟跳转至自身 Activity
context.startActivity(testIntent);
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "测试指令注入失败:" + e.getMessage()); LogUtils.e(TAG, "testCommand() 失败: " + e.getMessage());
} }
} }
// ===========================================================
// 公共静态测试函数:外部可直接调用注入测试 JSON
// ===========================================================
public static void testViewCommand(Context context) { public static void testViewCommand(Context context) {
LogUtils.d(TAG, "testViewCommand()");
try { try {
// 测试用指令
String testJson = "{\"script\":\"BuildWinBoLLProjectView.sh\",\"args\":[\"DebugTemp\"],\"workDir\":null,\"background\":true,\"resultDir\":null}"; String testJson = "{\"script\":\"BuildWinBoLLProjectView.sh\",\"args\":[\"DebugTemp\"],\"workDir\":null,\"background\":true,\"resultDir\":null}";
Intent intent = new Intent(context, NfcTermuxBridgeActivity.class);
Intent testIntent = new Intent(context, NfcTermuxBridgeActivity.class); intent.setAction(ACTION_BUILD_VIEW);
testIntent.setAction(ACTION_BUILD_VIEW); intent.putExtra(Intent.EXTRA_TEXT, testJson);
testIntent.putExtra(Intent.EXTRA_TEXT, testJson); context.startActivity(intent);
// 模拟跳转至自身 Activity
context.startActivity(testIntent);
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "测试指令注入失败:" + e.getMessage()); LogUtils.e(TAG, "testViewCommand() 失败: " + e.getMessage());
} }
} }
} }