You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Android三星设备NFC标签读取控制:仅允许按钮触发读取

解决Android应用仅在主动点击按钮时读取NFC标签的问题

核心思路

通过**动态注册/注销NFC前台调度(Foreground Dispatch)**实现精准控制:只有用户点击按钮后,才让当前Activity优先接管NFC标签的处理权;其他状态下,系统不会将NFC事件分发给你的应用,也就不会唤起第三方应用。

具体实现步骤

  1. 移除Manifest中的NFC静态Intent Filter
    首先确保你的AndroidManifest.xml中没有注册NFC相关的<intent-filter>,避免系统默认将NFC标签事件分发给你的应用。保留NFC权限即可:

    <uses-permission android:name="android.permission.NFC" />
    <uses-feature android:name="android.hardware.nfc" android:required="true" />
    
  2. 在目标Activity中实现动态调度控制
    以读取NFC标签的Activity为例:

    public class NfcReaderActivity extends AppCompatActivity {
        private NfcAdapter mNfcAdapter;
        private PendingIntent mPendingIntent;
        private IntentFilter[] mIntentFilters;
        private String[][] mTechLists;
        // 标记是否处于可读取状态
        private boolean isReadMode = false;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_nfc_reader);
    
            mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
            if (mNfcAdapter == null) {
                Toast.makeText(this, "设备不支持NFC", Toast.LENGTH_SHORT).show();
                finish();
                return;
            }
    
            // 初始化PendingIntent,用于接收NFC事件
            mPendingIntent = PendingIntent.getActivity(
                    this,
                    0,
                    new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
                    PendingIntent.FLAG_MUTABLE
            );
    
            // 定义要过滤的NFC intent类型(根据需求调整)
            IntentFilter ndefFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
            try {
                ndefFilter.addDataType("text/plain");
            } catch (IntentFilter.MalformedMimeTypeException e) {
                throw new RuntimeException("MIME类型设置错误", e);
            }
            mIntentFilters = new IntentFilter[]{ndefFilter};
    
            // 定义支持的NFC技术类型(根据需求调整)
            mTechLists = new String[][]{new String[]{Ndef.class.getName()}};
    
            // 读取按钮点击事件
            Button readBtn = findViewById(R.id.btn_read_nfc);
            readBtn.setOnClickListener(v -> {
                if (!mNfcAdapter.isEnabled()) {
                    startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
                    return;
                }
                // 进入可读取状态,注册前台调度
                isReadMode = true;
                mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, mIntentFilters, mTechLists);
                Toast.makeText(this, "请触碰NFC标签", Toast.LENGTH_SHORT).show();
            });
        }
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            if (isReadMode && NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
                // 处理NFC标签数据
                processNfcTag(intent);
                // 处理完成后退出读取状态,注销前台调度
                isReadMode = false;
                mNfcAdapter.disableForegroundDispatch(this);
            }
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            // 页面暂停时务必注销调度,避免后台仍接收NFC事件
            if (mNfcAdapter != null) {
                mNfcAdapter.disableForegroundDispatch(this);
            }
            isReadMode = false;
        }
    
        private void processNfcTag(Intent intent) {
            // 实现NFC标签读取逻辑
            Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            if (rawMessages != null) {
                NdefMessage message = (NdefMessage) rawMessages[0];
                NdefRecord record = message.getRecords()[0];
                String tagContent = new String(record.getPayload());
                Toast.makeText(this, "读取到标签内容:" + tagContent, Toast.LENGTH_LONG).show();
            }
        }
    }
    
  3. 关键说明

    • 前台调度的作用:调用enableForegroundDispatch后,当前Activity会优先接收NFC标签的Intent,系统不会再将该事件分发给其他应用,避免唤起第三方应用。
    • 状态标记isReadMode:确保只有在用户主动点击按钮后,才处理NFC事件,避免误触发。
    • onPause中注销调度:必须在页面暂停时注销,否则应用退到后台后仍可能拦截NFC事件,影响其他应用正常使用。

三星设备注意事项

部分三星设备的系统NFC设置可能有“默认应用”选项,但通过上述代码动态控制前台调度的方式,已经可以覆盖系统的默认行为,无需额外调整系统设置。

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

火山引擎 最新活动