NFC标签读取异常求助:ACTION_TAG_DISCOVERED判断始终返回false
解决NFC标签读取时
ACTION_TAG_DISCOVERED始终返回false的问题 看起来你遇到了Android NFC intent匹配的典型坑——ACTION_TAG_DISCOVERED是系统分发NFC意图的最低优先级选项,只有当没有其他应用匹配到更具体的ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED时,才会触发它。结合你的场景,我来一步步帮你排查和修正:
一、先补全Manifest的核心配置
首先确保你的AndroidManifest.xml里包含了必要的权限、特性声明和覆盖全场景的intent-filter:
1. 声明NFC权限与硬件特性
在<manifest>标签下添加:
<uses-permission android:name="android.permission.NFC" /> <uses-feature android:name="android.hardware.nfc" android:required="true" />
2. 配置覆盖所有NFC触发场景的intent-filter
只注册ACTION_TAG_DISCOVERED远远不够,建议同时注册三种NFC意图,确保能捕获所有类型的标签:
<activity android:name=".MainActivity" android:launchMode="singleTop"> <!-- 必须设置singleTop避免重复创建Activity --> <!-- 捕获带NDEF数据的标签 --> <intent-filter> <action android:name="android.nfc.action.NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <!-- 如果标签有特定MIME类型(比如文本),可添加此行,否则去掉 --> <data android:mimeType="text/plain" /> </intent-filter> <!-- 捕获特定NFC技术的标签(比如Mifare系列) --> <intent-filter> <action android:name="android.nfc.action.TECH_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <!-- 兜底捕获所有未被匹配的标签 --> <intent-filter> <action android:name="android.nfc.action.TAG_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <!-- 为TECH_DISCOVERED指定支持的NFC技术列表 --> <meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" /> </activity>
3. 创建NFC技术过滤文件
在res/xml目录下新建nfc_tech_filter.xml,添加你需要支持的NFC技术(覆盖常见的Mifare卡类型):
<resources xmlns:android="http://schemas.android.com/apk/res/android"> <tech-list> <tech>android.nfc.tech.MifareClassic</tech> <tech>android.nfc.tech.MifareUltralight</tech> <tech>android.nfc.tech.Ndef</tech> <tech>android.nfc.tech.NdefFormatable</tech> </tech-list> </resources>
二、修正Activity里的NFC逻辑
你的代码大概率只在onCreate里处理了意图,但NFC意图通常会发送到已启动的Activity实例(因为设置了singleTop),所以必须在onNewIntent里也处理意图,同时开启前台调度确保优先捕获:
public class MainActivity extends AppCompatActivity { private NfcAdapter nfcAdapter; private TextView textViewInfo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textViewInfo = findViewById(R.id.textViewInfo); // 初始化NFC适配器 nfcAdapter = NfcAdapter.getDefaultAdapter(this); if (nfcAdapter == null) { textViewInfo.setText("设备不支持NFC"); return; } if (!nfcAdapter.isEnabled()) { textViewInfo.setText("请先开启NFC功能"); // 可跳转至NFC设置页面 startActivity(new Intent(Settings.ACTION_NFC_SETTINGS)); } // 处理启动时的NFC意图 handleNfcIntent(getIntent()); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // 处理后续的NFC意图(关键!) handleNfcIntent(intent); } @Override protected void onResume() { super.onResume(); // 开启前台调度,确保APP在前台时优先捕获NFC意图 if (nfcAdapter != null) { IntentFilter[] intentFiltersArray = new IntentFilter[]{ new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED), new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED), new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) }; String[][] techListsArray = new String[][]{ new String[]{MifareClassic.class.getName()}, new String[]{MifareUltralight.class.getName()}, new String[]{Ndef.class.getName()} }; nfcAdapter.enableForegroundDispatch(this, PendingIntent.getActivity( this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE), intentFiltersArray, techListsArray); } } @Override protected void onPause() { super.onPause(); // 关闭前台调度 if (nfcAdapter != null) { nfcAdapter.disableForegroundDispatch(this); } } private void handleNfcIntent(Intent intent) { String action = intent.getAction(); // 同时判断三种NFC意图,确保不会遗漏 if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action) || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) || NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); if (tag != null) { // 这里处理标签读取逻辑,示例为读取Mifare Classic卡 readMifareClassicTag(tag); } } } private void readMifareClassicTag(Tag tag) { MifareClassic mifareClassic = MifareClassic.get(tag); if (mifareClassic == null) { textViewInfo.setText("不是Mifare Classic卡"); return; } try { mifareClassic.connect(); // 示例:读取扇区0的块0(默认密钥为FFFFFFFFFFFF,若卡片修改过密钥需替换) boolean auth = mifareClassic.authenticateSectorWithKeyA(0, MifareClassic.KEY_DEFAULT); if (auth) { byte[] data = mifareClassic.readBlock(0); textViewInfo.setText("读取到数据:" + new String(data, StandardCharsets.UTF_8)); } else { textViewInfo.setText("扇区认证失败"); } mifareClassic.close(); } catch (IOException e) { e.printStackTrace(); textViewInfo.setText("读取失败:" + e.getMessage()); } } }
三、关键注意事项
- 前台调度的必要性:在
onResume里开启enableForegroundDispatch,可以让你的APP在前台时优先捕获NFC意图,避免被其他应用拦截。 - 意图的处理时机:必须在
onNewIntent里处理后续的NFC意图,因为singleTop模式下,新的意图会发送到已存在的Activity实例。 - Mifare卡的密钥问题:Mifare Classic卡的每个扇区都有密钥,默认密钥是
FFFFFFFFFFFF,但如果卡片被修改过密钥,需要使用对应密钥才能读取。
按照以上步骤修改后,应该就能解决ACTION_TAG_DISCOVERED始终返回false的问题,成功读取NFC标签并展示数据了。
内容的提问来源于stack exchange,提问作者t00n
相关产品推荐
相关产品推荐

