From a18057e0953e2c685027fefd25c63c2c14ec69a5 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Mon, 16 Mar 2026 10:33:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E8=B0=83=E6=95=B4NFC?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E6=9E=84=E9=80=A0=E4=B8=BA=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=8A=A0=E7=AE=A1=E7=90=86=E7=AA=97=E5=8F=A3=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9=E8=B0=83=E8=AF=95=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- autonfc/build.properties | 4 +- autonfc/src/main/AndroidManifest.xml | 15 +- .../winboll/studio/autonfc/MainActivity.java | 62 ++- .../studio/autonfc/models/NfcTermuxCmd.java | 14 + .../autonfc/nfc/AutoNFCBootReceiver.java | 28 ++ .../studio/autonfc/nfc/AutoNFCService.java | 162 ++++++++ .../autonfc/nfc/NFCInterfaceActivity.java | 378 ++++++++---------- autonfc/src/main/res/layout/activity_main.xml | 13 - autonfc/src/main/res/menu/main_menu.xml | 12 + 9 files changed, 443 insertions(+), 245 deletions(-) create mode 100644 autonfc/src/main/java/cc/winboll/studio/autonfc/models/NfcTermuxCmd.java create mode 100644 autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCBootReceiver.java create mode 100644 autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCService.java create mode 100644 autonfc/src/main/res/menu/main_menu.xml diff --git a/autonfc/build.properties b/autonfc/build.properties index 1717c74..b843769 100644 --- a/autonfc/build.properties +++ b/autonfc/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sat Mar 14 06:09:03 GMT 2026 +#Mon Mar 16 02:31:00 GMT 2026 stageCount=0 libraryProject= baseVersion=15.11 publishVersion=15.0.0 -buildCount=6 +buildCount=12 baseBetaVersion=15.0.1 diff --git a/autonfc/src/main/AndroidManifest.xml b/autonfc/src/main/AndroidManifest.xml index 1f3327c..0c93ecd 100644 --- a/autonfc/src/main/AndroidManifest.xml +++ b/autonfc/src/main/AndroidManifest.xml @@ -8,6 +8,8 @@ + + + + + + + + + + - diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/MainActivity.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/MainActivity.java index 68e9fa2..077489c 100644 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/MainActivity.java +++ b/autonfc/src/main/java/cc/winboll/studio/autonfc/MainActivity.java @@ -1,38 +1,70 @@ package cc.winboll.studio.autonfc; +import android.content.Intent; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; -import cc.winboll.studio.libappbase.LogView; -import cc.winboll.studio.libappbase.ToastUtils; -import android.view.View; -import android.content.Intent; +import cc.winboll.studio.autonfc.nfc.AutoNFCService; import cc.winboll.studio.autonfc.nfc.NFCInterfaceActivity; +import cc.winboll.studio.libappbase.LogActivity; +import cc.winboll.studio.libappbase.ToastUtils; public class MainActivity extends AppCompatActivity { - LogView mLogView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar); - setSupportActionBar(toolbar); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); - mLogView = findViewById(R.id.logview); - - ToastUtils.show("onCreate"); + } @Override protected void onResume() { super.onResume(); - mLogView.start(); } - - public void onNFCInterfaceActivity(View view) { - startActivity(new Intent(this, NFCInterfaceActivity.class)); - } + + // 加载菜单 + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.main_menu, menu); + return true; + } + + // 菜单点击 + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + + if (id == R.id.menu_start_service) { + startService(new Intent(this, AutoNFCService.class)); + ToastUtils.show("NFC服务已启动"); + return true; + } + + if (id == R.id.menu_stop_service) { + stopService(new Intent(this, AutoNFCService.class)); + ToastUtils.show("NFC服务已停止"); + return true; + } + + if (id == R.id.menu_log) { + LogActivity.startLogActivity(this); + return true; + } + + return super.onOptionsItemSelected(item); + } + + public void onNFCInterfaceActivity(View view) { + startActivity(new Intent(this, NFCInterfaceActivity.class)); + } } + diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/models/NfcTermuxCmd.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/models/NfcTermuxCmd.java new file mode 100644 index 0000000..92ccf8b --- /dev/null +++ b/autonfc/src/main/java/cc/winboll/studio/autonfc/models/NfcTermuxCmd.java @@ -0,0 +1,14 @@ +package cc.winboll.studio.autonfc.models; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/03/16 09:38 + */ +public class NfcTermuxCmd { + public String script; // 要执行的预制脚本名(如 auth.sh) + public String[] args; // 脚本参数 + public String workDir; // 工作目录 + public boolean background; // 是否后台执行 + public String resultDir; // 结果输出目录(可为 null) +} + diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCBootReceiver.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCBootReceiver.java new file mode 100644 index 0000000..3ea86c5 --- /dev/null +++ b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCBootReceiver.java @@ -0,0 +1,28 @@ +package cc.winboll.studio.autonfc.nfc; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import cc.winboll.studio.libappbase.LogUtils; +/* + * 源码说明与描述: + * 开机自启动广播接收器,用于开机自动启动 NFC 监听服务 + * + * 作者:豆包&ZhanGSKen + * 创建时间:2026-03-16 16:10:00 + * 最后编辑时间:2026-03-16 18:20:00 + */ +public class AutoNFCBootReceiver extends BroadcastReceiver { + + private static final String TAG = "AutoNFCBootReceiver"; + + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { + LogUtils.d(TAG, "开机完成,启动 AutoNFC 监听服务"); + Intent service = new Intent(context, AutoNFCService.class); + context.startService(service); + } + } +} + diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCService.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCService.java new file mode 100644 index 0000000..b84f43c --- /dev/null +++ b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/AutoNFCService.java @@ -0,0 +1,162 @@ +package cc.winboll.studio.autonfc.nfc; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.IBinder; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.Ndef; +import android.widget.Toast; +import cc.winboll.studio.autonfc.R; +import cc.winboll.studio.libappbase.LogUtils; +import java.nio.charset.Charset; + +/* + * 源码说明与描述: + * NFC 后台监听服务(正规保活版) + * 保活方式:前台服务 + START_STICKY + 任务销毁重启 + 开机自启 + * + * 作者:豆包&ZhanGSKen + * 创建时间:2026-03-16 16:10:00 + * 最后编辑时间:2026-03-16 18:20:00 + */ + +public class AutoNFCService extends Service { + + public static final String TAG = "AutoNFCService"; + private static final int NOTIFICATION_ID = 0x1001; + private static final String CHANNEL_ID = "AUTO_NFC_SERVICE_CHANNEL"; + + @Override + public void onCreate() { + super.onCreate(); + LogUtils.d(TAG, "onCreate"); + startForeground(NOTIFICATION_ID, buildNotification()); + } + + private Notification buildNotification() { + NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel( + CHANNEL_ID, + "AutoNFC 后台监听", + NotificationManager.IMPORTANCE_LOW + ); + channel.setSound(null, null); + channel.setVibrationPattern(null); + nm.createNotificationChannel(channel); + } + + Intent intent = new Intent(this, NFCInterfaceActivity.class); + PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + + return new Notification.Builder(this) + .setChannelId(CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher) + .setContentTitle("AutoNFC 运行中") + .setContentText("NFC 卡片监听已启动") + .setContentIntent(pi) + .setSound(null) + .setVibrate(null) + .build(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + LogUtils.d(TAG, "onStartCommand"); + if (intent != null) { + handleNfcIntent(intent); + } + return START_STICKY; + } + + public void handleNfcIntent(Intent intent) { + String action = intent.getAction(); + if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action) + || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) + || NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { + + LogUtils.d(TAG, "NFC 卡片已靠近"); + Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + parseNdefData(tag); + } + } + + private void parseNdefData(Tag tag) { + if (tag == null) { + showToast("标签为空"); + return; + } + + Ndef ndef = Ndef.get(tag); + if (ndef == null) { + showToast("不支持NDEF格式"); + return; + } + + try { + ndef.connect(); + NdefMessage msg = ndef.getNdefMessage(); + if (msg == null) { + ndef.close(); + showToast("未读取到NDEF数据"); + return; + } + + NdefRecord[] records = msg.getRecords(); + if (records != null && records.length > 0) { + byte[] payload = records[0].getPayload(); + if (payload.length > 0) { + int langLen = payload[0] & 0x3F; + int start = 1 + langLen; + if (start < payload.length) { + String data = new String(payload, start, payload.length - start, Charset.forName("UTF-8")); + LogUtils.d(TAG, "读取数据:" + data); + // 只弹出Toast显示内容 + showToast("NFC数据:" + data); + } + } + } + ndef.close(); + } catch (Exception e) { + LogUtils.e(TAG, "解析失败", e); + showToast("读取失败:" + e.getMessage()); + } + } + + /** + * 弹出Toast + */ + private void showToast(final String msg) { + Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onTaskRemoved(Intent rootIntent) { + super.onTaskRemoved(rootIntent); + LogUtils.d(TAG, "任务被移除,重启服务"); + Intent intent = new Intent(getApplicationContext(), AutoNFCService.class); + startService(intent); + } + + @Override + public void onDestroy() { + super.onDestroy(); + LogUtils.d(TAG, "onDestroy"); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } +} + diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NFCInterfaceActivity.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NFCInterfaceActivity.java index 274f35b..17a5959 100644 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NFCInterfaceActivity.java +++ b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NFCInterfaceActivity.java @@ -1,3 +1,10 @@ +/* + - 源码说明与描述: + - NFC 调试界面,负责前台分发、UI 交互、写入控制 + - 作者:豆包&ZhanGSKenzhangsken@qq.com + - 创建时间:2026-03-16 10:00:00 + - 最后编辑时间:2026-03-16 18:59:00 + */ package cc.winboll.studio.autonfc.nfc; import android.app.Activity; @@ -18,266 +25,209 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import cc.winboll.studio.autonfc.R; +import cc.winboll.studio.libappbase.LogUtils; import java.nio.charset.Charset; -/** - * @Author 豆包&ZhanGSKen - * @Date 2026/03/14 13:35 - */ public class NFCInterfaceActivity extends Activity { - private NfcAdapter mNfcAdapter; - private PendingIntent mPendingIntent; - private IntentFilter[] mIntentFilters; - private String[][] mTechLists; +// ========================= 常量定义 ========================= + private static final String TAG = "NFCInterfaceActivity"; - private TextView tvStatus; - private TextView tvData; - private EditText etWriteContent; - private Button btnReadNfc; - private Button btnWriteNfc; +// ========================= 成员属性 ========================= + private NfcAdapter mNfcAdapter; + private PendingIntent mPendingIntent; + private IntentFilter[] mIntentFilters; + private String[][] mTechLists; - private Tag mCurrentTag; - private boolean mIsWaitForRead = false; + private TextView tvStatus; + private TextView tvData; + private EditText etWriteContent; + private Button btnReadNfc; + private Button btnWriteNfc; - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_nfc_interface); + private Tag mCurrentTag; - tvStatus = findViewById(R.id.tv_nfc_status); - tvData = findViewById(R.id.tv_nfc_data); - etWriteContent = findViewById(R.id.et_write_content); - btnReadNfc = findViewById(R.id.btn_read_nfc); - btnWriteNfc = findViewById(R.id.btn_write_nfc); +// ========================= 生命周期 ========================= + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LogUtils.d(TAG, "onCreate() 调用,savedInstanceState: " + (savedInstanceState != null ? "非空" : "空")); + setContentView(R.layout.activity_nfc_interface); - initNFC(); + tvStatus = (TextView) findViewById(R.id.tv_nfc_status); + tvData = (TextView) findViewById(R.id.tv_nfc_data); + etWriteContent = (EditText) findViewById(R.id.et_write_content); + btnReadNfc = (Button) findViewById(R.id.btn_read_nfc); + btnWriteNfc = (Button) findViewById(R.id.btn_write_nfc); - btnReadNfc.setOnClickListener(new View.OnClickListener() { + initNFC(); + startAutoNFCService(); + + btnReadNfc.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - startWaitForRead(); + LogUtils.d(TAG, "btnReadNfc 点击,进入等待读卡模式"); + updateStatus("等待卡片靠近..."); } }); - btnWriteNfc.setOnClickListener(new View.OnClickListener() { + btnWriteNfc.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String content = etWriteContent.getText().toString().trim(); + LogUtils.d(TAG, "btnWriteNfc 点击,待写入内容: " + content); writeNfc(content); } }); - } + } - private void initNFC() { - NfcManager manager = (NfcManager) getSystemService(NFC_SERVICE); - mNfcAdapter = manager.getDefaultAdapter(); +// ========================= 初始化 ========================= + private void initNFC() { + LogUtils.d(TAG, "initNFC() 开始初始化 NFC 配置"); + NfcManager manager = (NfcManager) getSystemService(NFC_SERVICE); + mNfcAdapter = manager.getDefaultAdapter(); - if (mNfcAdapter == null) { - updateStatus("设备不支持NFC"); - return; - } + if (mNfcAdapter == null) { + LogUtils.e(TAG, "initNFC() 设备不支持 NFC"); + updateStatus("设备不支持NFC"); + return; + } - Intent intent = new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - mPendingIntent = PendingIntent.getActivity(this, 0, intent, 0); + Intent intent = new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + mPendingIntent = PendingIntent.getActivity(this, 0, intent, 0); - IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); - try { - filter.addDataType("*/*"); - } catch (IntentFilter.MalformedMimeTypeException e) { - e.printStackTrace(); - } + IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); + try { + filter.addDataType("/"); + } catch (IntentFilter.MalformedMimeTypeException e) { + LogUtils.e(TAG, "initNFC() 过滤器异常: " + e.getMessage(), e); + } - mIntentFilters = new IntentFilter[]{filter}; - mTechLists = new String[][]{{Ndef.class.getName()}, {NdefFormatable.class.getName()}}; - updateStatus("NFC初始化完成"); - } + mIntentFilters = new IntentFilter[] { filter }; + mTechLists = new String[][] { + { Ndef.class.getName() }, + { NdefFormatable.class.getName() } + }; + LogUtils.d(TAG, "initNFC() 完成 NFC 前台分发配置"); + updateStatus("NFC 初始化完成"); + } - public void startWaitForRead() { - mIsWaitForRead = true; - updateStatus("请靠近NFC卡片进行读取"); - showToast("请靠近卡片"); - } + private void startAutoNFCService() { + LogUtils.d(TAG, "startAutoNFCService() 启动后台监听服务"); + Intent service = new Intent(this, AutoNFCService.class); + startService(service); + } - @Override - protected void onResume() { - super.onResume(); - NfcStateMonitor.startMonitor(); - if (mNfcAdapter != null) { - mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, mIntentFilters, mTechLists); - } - } +// ========================= 生命周期回调 ========================= + @Override + protected void onResume() { + super.onResume(); + LogUtils.d(TAG, "onResume() 启用前台分发"); + if (mNfcAdapter != null) { + mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, mIntentFilters, mTechLists); + } + } - @Override - protected void onPause() { - super.onPause(); - NfcStateMonitor.stopMonitor(); - if (mNfcAdapter != null) { - mNfcAdapter.disableForegroundDispatch(this); - } - } + @Override + protected void onPause() { + super.onPause(); + LogUtils.d(TAG, "onPause() 关闭前台分发"); + if (mNfcAdapter != null) { + mNfcAdapter.disableForegroundDispatch(this); + } + } - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - String action = intent.getAction(); + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + LogUtils.d(TAG, "onNewIntent() 收到 NFC 卡片意图: " + intent.getAction()); + mCurrentTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action) - || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) - || NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { + Intent serviceIntent = new Intent(this, AutoNFCService.class); + serviceIntent.putExtras(intent); + startService(serviceIntent); - NfcStateMonitor.notifyNfcConnected(); - updateStatus("卡片已靠近"); - mCurrentTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + updateStatus("卡片已靠近,数据解析中..."); + } - if (mIsWaitForRead) { - mIsWaitForRead = false; - readNfcData(intent); - } - } - } +// ========================= 写入逻辑 ========================= + public boolean writeNfc(String text) { + LogUtils.d(TAG, "writeNfc() 写入文本: " + text); + if (mCurrentTag == null) { + LogUtils.w(TAG, "writeNfc() 未检测到卡片,无法写入"); + updateStatus("请先靠近卡片"); + return false; + } + if (text.isEmpty()) { + LogUtils.w(TAG, "writeNfc() 写入内容为空"); + updateStatus("输入内容不能为空"); + return false; + } - public void readNfcData(Intent intent) { - if (intent == null) { - NfcStateMonitor.notifyReadFail("Intent为空"); - return; - } + NdefRecord record = createTextRecord(text); + NdefMessage msg = new NdefMessage(new NdefRecord[] { record }); - Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - if (tag == null) { - NfcStateMonitor.notifyReadFail("标签为空"); - return; - } - - Ndef ndef = Ndef.get(tag); - if (ndef == null) { - NfcStateMonitor.notifyReadFail("不支持NDEF"); - return; - } - - try { - ndef.connect(); - NdefMessage msg = ndef.getNdefMessage(); - if (msg == null) { - NfcStateMonitor.notifyReadFail("空标签"); - ndef.close(); - return; - } - - NdefRecord[] records = msg.getRecords(); - if (records != null && records.length > 0) { -// byte[] payload = records[0].getPayload(); -// String data = new String(payload, 1, payload.length - 1, Charset.forName("UTF-8")); -// updateData(data); -// updateStatus("读取成功"); -// NfcStateMonitor.notifyReadSuccess(data); - byte[] payload = records[0].getPayload(); - if (payload.length > 0) { - int langCodeLength = payload[0] & 0x3F; // 标准NDEF Text格式,语言码长度存在第0字节的低6位 - int textStartIndex = 1 + langCodeLength; - if (textStartIndex < payload.length) { - String data = new String(payload, textStartIndex, payload.length - textStartIndex, Charset.forName("UTF-8")); - updateData(data); - updateStatus("读取成功"); - NfcStateMonitor.notifyReadSuccess(data); - } else { - NfcStateMonitor.notifyReadFail("标签数据为空"); - updateStatus("标签数据为空"); - } - } else { - NfcStateMonitor.notifyReadFail("标签 payload 为空"); - updateStatus("标签 payload 为空"); + try { + Ndef ndef = Ndef.get(mCurrentTag); + if (ndef != null) { + ndef.connect(); + if (ndef.isWritable()) { + ndef.writeNdefMessage(msg); + ndef.close(); + LogUtils.i(TAG, "writeNfc() 写入成功"); + updateStatus("写入成功"); + updateData(text); + NfcStateMonitor.notifyWriteSuccess(); + return true; } - - } - ndef.close(); - } catch (Exception e) { - NfcStateMonitor.notifyReadFail(e.getMessage()); - updateStatus("读取失败:" + e.getMessage()); - } - } + } else { + NdefFormatable f = NdefFormatable.get(mCurrentTag); + if (f != null) { + f.connect(); + f.format(msg); + f.close(); + LogUtils.i(TAG, "writeNfc() 格式化并写入成功"); + updateStatus("格式化并写入成功"); + NfcStateMonitor.notifyWriteSuccess(); + return true; + } + } + } catch (Exception e) { + LogUtils.e(TAG, "writeNfc() 写入异常: " + e.getMessage(), e); + updateStatus("写入失败:" + e.getMessage()); + NfcStateMonitor.notifyWriteFail(e.getMessage()); + } + return false; + } - public boolean writeNfc(String text) { - if (mCurrentTag == null) { - NfcStateMonitor.notifyWriteFail("未检测到卡片"); - updateStatus("请先靠近卡片"); - return false; - } +// ========================= NDEF 构造 ========================= + private NdefRecord createTextRecord(String text) { + LogUtils.d(TAG, "createTextRecord() 构造 NDEF 文本记录"); + byte[] langBytes = "en".getBytes(Charset.forName("UTF-8")); + byte[] textBytes = text.getBytes(Charset.forName("UTF-8")); + byte[] payload = new byte[1 + langBytes.length + textBytes.length]; + payload[0] = (byte) langBytes.length; + System.arraycopy(langBytes, 0, payload, 1, langBytes.length); + System.arraycopy(textBytes, 0, payload, 1 + langBytes.length, textBytes.length); + return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload); + } - if (text.isEmpty()) { - NfcStateMonitor.notifyWriteFail("输入内容不能为空"); - updateStatus("请输入写入内容"); - return false; - } - - NdefRecord record = createTextRecord(text); - NdefMessage msg = new NdefMessage(new NdefRecord[]{record}); - - try { - Ndef ndef = Ndef.get(mCurrentTag); - if (ndef != null) { - ndef.connect(); - if (ndef.isWritable()) { - ndef.writeNdefMessage(msg); - ndef.close(); - updateStatus("写入成功"); - updateData(text); - NfcStateMonitor.notifyWriteSuccess(); - return true; - } - } else { - NdefFormatable formatable = NdefFormatable.get(mCurrentTag); - if (formatable != null) { - formatable.connect(); - formatable.format(msg); - formatable.close(); - updateStatus("格式化并写入成功"); - NfcStateMonitor.notifyWriteSuccess(); - return true; - } - } - } catch (Exception e) { - NfcStateMonitor.notifyWriteFail(e.getMessage()); - updateStatus("写入失败:" + e.getMessage()); - } - return false; - } - - private NdefRecord createTextRecord(String text) { - byte[] langBytes = "en".getBytes(Charset.forName("UTF-8")); - byte[] textBytes = text.getBytes(Charset.forName("UTF-8")); - byte[] payload = new byte[1 + langBytes.length + textBytes.length]; - payload[0] = (byte) langBytes.length; - System.arraycopy(langBytes, 0, payload, 1, langBytes.length); - System.arraycopy(textBytes, 0, payload, 1 + langBytes.length, textBytes.length); - return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload); - } - - private void updateStatus(final String s) { - runOnUiThread(new Runnable() { +// ========================= UI 更新 ========================= + private void updateStatus(final String s) { + runOnUiThread(new Runnable() { @Override public void run() { tvStatus.setText("状态:" + s); } }); - } + } - private void updateData(final String s) { - runOnUiThread(new Runnable() { + private void updateData(final String s) { + runOnUiThread(new Runnable() { @Override public void run() { - tvData.setText("读取/写入内容:\n" + s); + tvData.setText("内容:\n" + s); } }); - } - - private void showToast(final String s) { - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(NFCInterfaceActivity.this, s, Toast.LENGTH_SHORT).show(); - } - }); - } + } } - diff --git a/autonfc/src/main/res/layout/activity_main.xml b/autonfc/src/main/res/layout/activity_main.xml index 772e6e4..a6032d0 100644 --- a/autonfc/src/main/res/layout/activity_main.xml +++ b/autonfc/src/main/res/layout/activity_main.xml @@ -34,18 +34,5 @@ - - - - - - diff --git a/autonfc/src/main/res/menu/main_menu.xml b/autonfc/src/main/res/menu/main_menu.xml new file mode 100644 index 0000000..fb973c9 --- /dev/null +++ b/autonfc/src/main/res/menu/main_menu.xml @@ -0,0 +1,12 @@ + + + + + +