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

Android Kotlin自定义NFC扫描应用如何阻止其他NFC应用启动?

解决方案:在应用使用期间控制NFC相关行为

核心思路:抢占NFC前台调度

Android系统中,检测到NFC标签时会优先将处理权交给前台调度的应用,而非默认系统应用。你可以通过注册前台调度器,在应用处于前台时拦截NFC标签的Intent,阻止其他NFC应用(包括系统级的Nfc Service)触发。

具体实现步骤(Kotlin)

  1. 添加权限与Manifest配置
    在AndroidManifest.xml中声明NFC权限、特性,并配置Activity的Intent过滤器:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />

<activity
    android:name=".MainActivity"
    ...>
    <!-- 拦截NDEF格式标签的Intent -->
    <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技术类型的标签 -->
    <intent-filter>
        <action android:name="android.nfc.action.TECH_DISCOVERED" />
    </intent-filter>
    <!-- 指定支持的NFC技术列表 -->
    <meta-data
        android:name="android.nfc.action.TECH_DISCOVERED"
        android:resource="@xml/nfc_tech_filter" />
</activity>

创建res/xml/nfc_tech_filter.xml文件定义支持的NFC技术:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.Ndef</tech>
        <tech>android.nfc.tech.NdefFormatable</tech>
        <!-- 添加你需要支持的其他NFC技术,比如MifareClassic等 -->
    </tech-list>
</resources>
  1. 在Activity中实现前台调度逻辑
    在Activity的生命周期方法中注册/注销前台调度,确保仅在应用前台时拦截NFC:
class MainActivity : AppCompatActivity() {
    private lateinit var nfcAdapter: NfcAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // 初始化NFC适配器,检查设备是否支持NFC
        nfcAdapter = NfcAdapter.getDefaultAdapter(this) ?: run {
            Toast.makeText(this, "设备不支持NFC", Toast.LENGTH_SHORT).show()
            finish()
            return
        }
    }

    override fun onResume() {
        super.onResume()
        // 创建PendingIntent,确保NFC Intent能回到当前Activity
        val pendingIntent = PendingIntent.getActivity(
            this,
            0,
            Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
            PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
        )
        // 配置要拦截的Intent过滤器数组
        val intentFilters = arrayOf(
            IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED).apply {
                addCategory(Intent.CATEGORY_DEFAULT)
                try {
                    addDataType("text/plain")
                } catch (e: IntentFilter.MalformedMimeTypeException) {
                    throw RuntimeException("无效的MIME类型", e)
                }
            },
            IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)
        )
        // 配置支持的NFC技术数组
        val techLists = arrayOf(
            arrayOf(Ndef::class.java.name, NdefFormatable::class.java.name)
        )
        // 启用前台调度,拦截NFC Intent
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, techLists)
    }

    override fun onPause() {
        super.onPause()
        // 注销前台调度,恢复系统默认NFC处理逻辑
        nfcAdapter.disableForegroundDispatch(this)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        intent?.let {
            // 在这里处理扫描到的NFC标签数据
            when (it.action) {
                NfcAdapter.ACTION_NDEF_DISCOVERED, NfcAdapter.ACTION_TECH_DISCOVERED -> {
                    handleNfcData(it)
                }
            }
        }
    }

    private fun handleNfcData(intent: Intent) {
        // 实现你的NFC数据解析与业务逻辑
        val tag = intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)
        // 示例:读取NDEF标签内容
        tag?.let {
            val ndef = Ndef.get(it)
            ndef?.connect()
            val ndefMessage = ndef?.ndefMessage
            ndef?.close()
            ndefMessage?.records?.firstOrNull()?.let { record ->
                val content = String(record.payload, Charsets.UTF_8)
                Toast.makeText(this, "扫描到内容:$content", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

原理说明

启用前台调度后,Android系统会将NFC标签的Intent优先发送到你的前台应用,跳过系统默认的Nfc Service及其他后台NFC应用。只有当应用退到后台(onPause()触发后),系统才会恢复默认的NFC处理流程。

注意事项

  • 前台调度仅在应用可见前台状态下生效,后台应用无法拦截NFC Intent
  • 必须确保Intent过滤器和技术列表与你实际扫描的NFC标签类型匹配,否则无法触发拦截
  • Android 12及以上版本中,PendingIntent需要添加FLAG_MUTABLE或FLAG_IMMUTABLE,根据业务场景选择

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:07:35