You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android NFC连接后是否需延迟?多检测问题求助

NFC Type A卡Android应用问题排查

我开发了一款通过APDU连接NFC Type A卡的Android应用,调试模式下添加断点时能成功连接卡片并发送Select指令,但真机安装运行时应用崩溃。在连接标签后、选择小程序前加入Thread.sleep(2000)延迟(1500ms仍崩溃)后问题解决,想了解该延迟是否必要及原因;此外每次触碰NFC卡时,Android会多次发出检测提示音,求解决办法。


MainActivity.java

package nfcapp;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.NfcA;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

import com.google.common.primitives.Bytes;

import java.io.IOException;
import java.lang.reflect.Array;

public class MainActivity extends AppCompatActivity {

    byte[] resp;
    private NfcAdapter nfcAdapter;
    static final byte[] APPLET_AID = {(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06};
    static final byte[] APPLET_PIN = {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04};
    static final byte[] APDU_SELECT = {(byte) 0x00, (byte) 0xA4, (byte) 0x04, (byte) 0x00, (byte) 0x00};
    TextView tv_status;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_status = findViewById(R.id.tv_status);
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter == null) {
            Toast.makeText(this, "NFC is not supported", Toast.LENGTH_LONG).show();
            finish();
        } else if (!nfcAdapter.isEnabled()) {
            Toast.makeText(this, "Turn on device NFC", Toast.LENGTH_LONG).show();
        }
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        Intent intent = new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE);
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        nfcAdapter.disableForegroundDispatch(this);
    }
    
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if ( NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction()) ) {
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            if (NfcA.get(tag) != null) {
                NfcA nfcaTag = NfcA.get(tag);
                try {
                    nfcaTag = SCConnect(nfcaTag);
                    if (nfcaTag == null) {
                        finish();
                    }
                    tv_status.append("Connected To NFC Card Successfully!\n");

                    Thread.sleep(2000);
                    
                    resp = SCSelectApplet(nfcaTag, APPLET_AID);
                    tv_status.append("SCSelectApplet: " + byteArrayToHexString(resp) + "\n");

                } catch (IOException e) {
                    tv_status.append("IOException : "+ e.getMessage().toString() + "\n");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            } else {
                Toast.makeText(this, "Unsupported tag technology", Toast.LENGTH_LONG).show();
            }
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        }
    }

    private NfcA SCConnect(NfcA nfcA) throws IOException {
        nfcA.connect();
        if (!nfcA.isConnected()) {
            return null;
        }
        return nfcA;
    }
    
    private static byte[] SCSelectApplet(NfcA nfcA, byte[] AID) throws IOException {
        if(!nfcA.isConnected()) {
            return null;
        }
        byte[] APDU = new byte[13];
        System.arraycopy(APDU_SELECT,0,APDU,0,5);
        if (AID.length != 0) {
            Array.setByte(APDU,4,(byte)AID.length);
            System.arraycopy(AID,0,APDU,5,AID.length);
        }
        byte[] resp = nfcA.transceive(APDU);
        return resp;
    }

    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
    public static String byteArrayToHexString(byte[] bytes) {
        if (bytes == null) return null;
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-feature
        android:name="android.hardware.nfc"
        android:required="true" />

    <uses-permission android:name="android.permission.NFC" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/Theme.NFCApp"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTask"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_status"
        android:layout_width="400dp"
        android:layout_height="400dp"
        android:layout_marginTop="100dp"
        android:layout_marginStart="5dp"
        android:textSize="18dp"
        android:justificationMode="inter_word"
        android:hint="Status" />

</LinearLayout>

内容的提问来源于stack exchange,提问作者MJay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:34:59