diff --git a/autonfc/build.properties b/autonfc/build.properties index a521f22..0a7f7ca 100644 --- a/autonfc/build.properties +++ b/autonfc/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Fri Mar 13 08:58:09 GMT 2026 +#Sat Mar 14 05:43:18 GMT 2026 stageCount=0 libraryProject= baseVersion=15.11 publishVersion=15.0.0 -buildCount=1 +buildCount=3 baseBetaVersion=15.0.1 diff --git a/autonfc/src/main/AndroidManifest.xml b/autonfc/src/main/AndroidManifest.xml index 4cc3738..1f3327c 100644 --- a/autonfc/src/main/AndroidManifest.xml +++ b/autonfc/src/main/AndroidManifest.xml @@ -3,6 +3,16 @@ xmlns:android="http://schemas.android.com/apk/res/android" package="cc.winboll.studio.autonfc"> + + + + + + + + + + + + + + + + + + + + + + - - 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 2d80c55..68e9fa2 100644 --- a/autonfc/src/main/java/cc/winboll/studio/autonfc/MainActivity.java +++ b/autonfc/src/main/java/cc/winboll/studio/autonfc/MainActivity.java @@ -5,6 +5,9 @@ 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.NFCInterfaceActivity; public class MainActivity extends AppCompatActivity { @@ -28,4 +31,8 @@ public class MainActivity extends AppCompatActivity { super.onResume(); mLogView.start(); } + + public void onNFCInterfaceActivity(View view) { + startActivity(new Intent(this, NFCInterfaceActivity.class)); + } } 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 new file mode 100644 index 0000000..58ab68f --- /dev/null +++ b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NFCInterfaceActivity.java @@ -0,0 +1,248 @@ +package cc.winboll.studio.autonfc.nfc; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.Intent; +import android.content.IntentFilter; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.NfcManager; +import android.nfc.Tag; +import android.nfc.tech.Ndef; +import android.nfc.tech.NdefFormatable; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.io.IOException; +import java.nio.charset.Charset; +import cc.winboll.studio.autonfc.R; +/** + * @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; + + // 调试UI + private TextView tvStatus; + private TextView tvData; + private Button btnWrite; + + // 当前标签 + private Tag mCurrentTag; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_nfc_interface); + + tvStatus = findViewById(R.id.tv_nfc_status); + tvData = findViewById(R.id.tv_nfc_data); + btnWrite = findViewById(R.id.btn_write_nfc); + + initNfc(); + + btnWrite.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + writeNfc("Test NFC Data Java7"); + } + }); + } + + private void initNfc() { + NfcManager manager = (NfcManager) getSystemService(NFC_SERVICE); + mNfcAdapter = manager.getDefaultAdapter(); + + if (mNfcAdapter == null) { + showToast("设备不支持NFC"); + return; + } + + 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(); + } + + mIntentFilters = new IntentFilter[]{filter}; + mTechLists = new String[][]{{Ndef.class.getName()}, {NdefFormatable.class.getName()}}; + } + + @Override + protected void onResume() { + super.onResume(); + // 静态启动监听 + NfcStateMonitor.startMonitor(); + enableForeground(); + } + + @Override + protected void onPause() { + super.onPause(); + // 静态停止监听 + NfcStateMonitor.stopMonitor(); + disableForeground(); + } + + private void enableForeground() { + if (mNfcAdapter != null) { + mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, mIntentFilters, mTechLists); + } + } + + private void disableForeground() { + if (mNfcAdapter != null) { + mNfcAdapter.disableForegroundDispatch(this); + } + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + String action = intent.getAction(); + + if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action) + || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) + || NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { + + // 通知接口:已连接 + NfcStateMonitor.notifyNfcConnected(); + updateUiStatus("卡片已靠近"); + + mCurrentTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + readNfc(intent); + } + } + + // ========== 公开读取方法 ========== + public void readNfc(Intent intent) { + if (intent == null) { + NfcStateMonitor.notifyReadFail("intent null"); + return; + } + + Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + if (tag == null) { + NfcStateMonitor.notifyReadFail("tag null"); + 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) { + String data = new String(records[0].getPayload(), Charset.forName("UTF-8")); + NfcStateMonitor.notifyReadSuccess(data); + updateUiData(data); + } + ndef.close(); + } catch (Exception e) { + NfcStateMonitor.notifyReadFail(e.getMessage()); + } + } + + // ========== 公开写入方法 ========== + public boolean writeNfc(String text) { + if (mCurrentTag == null) { + NfcStateMonitor.notifyWriteFail("未检测到标签"); + updateUiStatus("请先靠近卡片"); + 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(); + NfcStateMonitor.notifyWriteSuccess(); + updateUiStatus("写入成功"); + updateUiData(text); + return true; + } + } else { + NdefFormatable f = NdefFormatable.get(mCurrentTag); + if (f != null) { + f.connect(); + f.format(msg); + f.close(); + NfcStateMonitor.notifyWriteSuccess(); + updateUiStatus("格式化并写入成功"); + return true; + } + } + } catch (Exception e) { + NfcStateMonitor.notifyWriteFail(e.getMessage()); + updateUiStatus("写入失败:" + e.getMessage()); + } + return false; + } + + private NdefRecord createTextRecord(String text) { + byte[] lang = "en".getBytes(Charset.forName("UTF-8")); + byte[] txt = text.getBytes(Charset.forName("UTF-8")); + byte[] payload = new byte[1 + lang.length + txt.length]; + payload[0] = (byte) lang.length; + System.arraycopy(lang, 0, payload, 1, lang.length); + System.arraycopy(txt, 0, payload, 1 + lang.length, txt.length); + return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload); + } + + private void updateUiStatus(final String s) { + runOnUiThread(new Runnable() { + @Override + public void run() { + tvStatus.setText("状态:" + s); + } + }); + } + + private void updateUiData(final String s) { + runOnUiThread(new Runnable() { + @Override + public void run() { + tvData.setText(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/java/cc/winboll/studio/autonfc/nfc/NfcStateMonitor.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NfcStateMonitor.java new file mode 100644 index 0000000..f808a41 --- /dev/null +++ b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/NfcStateMonitor.java @@ -0,0 +1,110 @@ +package cc.winboll.studio.autonfc.nfc; + +import android.nfc.NfcAdapter; +import java.util.HashMap; +import java.util.Map; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/03/14 13:34 + */ +public class NfcStateMonitor { + + // 保存所有监听实例 + private static Map sListenerMap = new HashMap<>(); + + // 全局 NFC 状态标记 + private static boolean sIsRunning = false; + + // ============= 公开静态:启动监听 ============= + public static void startMonitor() { + if (sIsRunning) return; + + // 初始化 Map + sListenerMap = new HashMap<>(); + sIsRunning = true; + + // 回调所有监听器:监控已启动 + notifyMonitorStarted(); + } + + // ============= 公开静态:停止监听 ============= + public static void stopMonitor() { + if (!sIsRunning) return; + + sIsRunning = false; + + // 清空所有监听器 + if (sListenerMap != null) { + sListenerMap.clear(); + sListenerMap = null; + } + } + + // ============= 公开静态:注册监听 ============= + public static void registerListener(String key, OnNfcStateListener listener) { + if (!sIsRunning || listener == null) return; + sListenerMap.put(key, listener); + } + + // ============= 公开静态:移除监听 ============= + public static void unregisterListener(String key) { + if (!sIsRunning || key == null) return; + sListenerMap.remove(key); + } + + // ============= 下面是内部回调分发 ============= + public static void notifyNfcConnected() { + if (!sIsRunning) return; + for (OnNfcStateListener l : sListenerMap.values()) { + l.onNfcConnected(); + } + } + + public static void notifyNfcDisconnected() { + if (!sIsRunning) return; + for (OnNfcStateListener l : sListenerMap.values()) { + l.onNfcDisconnected(); + } + } + + public static void notifyReadSuccess(String data) { + if (!sIsRunning) return; + for (OnNfcStateListener l : sListenerMap.values()) { + l.onNfcReadSuccess(data); + } + } + + public static void notifyReadFail(String error) { + if (!sIsRunning) return; + for (OnNfcStateListener l : sListenerMap.values()) { + l.onNfcReadFail(error); + } + } + + public static void notifyWriteSuccess() { + if (!sIsRunning) return; + for (OnNfcStateListener l : sListenerMap.values()) { + l.onNfcWriteSuccess(); + } + } + + public static void notifyWriteFail(String error) { + if (!sIsRunning) return; + for (OnNfcStateListener l : sListenerMap.values()) { + l.onNfcWriteFail(error); + } + } + + private static void notifyMonitorStarted() { + if (!sIsRunning) return; + for (OnNfcStateListener l : sListenerMap.values()) { + l.onNfcConnected(); // 仅示意启动 + } + } + + public static boolean isMonitorRunning() { + return sIsRunning; + } +} + diff --git a/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/OnNfcStateListener.java b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/OnNfcStateListener.java new file mode 100644 index 0000000..2742a9a --- /dev/null +++ b/autonfc/src/main/java/cc/winboll/studio/autonfc/nfc/OnNfcStateListener.java @@ -0,0 +1,25 @@ +package cc.winboll.studio.autonfc.nfc; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/03/14 13:33 + */ +public interface OnNfcStateListener { + // NFC 已连接(卡片靠近) + void onNfcConnected(); + + // NFC 已断开(卡片移开) + void onNfcDisconnected(); + + // 读取成功 + void onNfcReadSuccess(String data); + + // 读取失败 + void onNfcReadFail(String error); + + // 写入成功 + void onNfcWriteSuccess(); + + // 写入失败 + void onNfcWriteFail(String error); +} diff --git a/autonfc/src/main/res/layout/activity_main.xml b/autonfc/src/main/res/layout/activity_main.xml index 12fdc32..772e6e4 100644 --- a/autonfc/src/main/res/layout/activity_main.xml +++ b/autonfc/src/main/res/layout/activity_main.xml @@ -26,11 +26,11 @@ android:layout_weight="1.0" android:gravity="center_vertical|center_horizontal"> - + android:text="NFC Interface Activity" + android:onClick="onNFCInterfaceActivity"/> diff --git a/autonfc/src/main/res/layout/activity_nfc_interface.xml b/autonfc/src/main/res/layout/activity_nfc_interface.xml new file mode 100644 index 0000000..bd22481 --- /dev/null +++ b/autonfc/src/main/res/layout/activity_nfc_interface.xml @@ -0,0 +1,34 @@ + + + + + +