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

Android设备NFC TAG读取实现问题:跨设备写入失败排查

NFC设备间文本传输失败排查

问题背景

实现了一个Android Activity,用于接收另一安装了指定NFC短信应用的设备发送的纯文本消息,已添加Manifest权限和Intent过滤器,但对方设备写入应用报错,无法完成NFC写入。

实现代码

const val MIME_TEXT_PLAIN = "text/plain"

class MainActivity : AppCompatActivity() {

    private val TAG = MainActivity::class.java.simpleName
    private lateinit var binding: ActivityMainBinding
    private var nfcAdapter: NfcAdapter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // 初始化NfcAdapter
        nfcAdapter = NfcAdapter.getDefaultAdapter(this)

        // 检查设备是否支持NFC
        if (nfcAdapter == null) {
            Log.w(TAG, "NFC non supportato!")
            binding.nfcStatusText.text = "No NFC on this device."
        } else {
            // 设置NFC按钮点击监听
            binding.nfcButton.setOnClickListener {
                enableNfc()
            }
        }
    }

    private fun enableNfc() {
        Log.w(TAG, "Abilito l'NFC...")
        // 检查NFC是否启用
        if (!nfcAdapter?.isEnabled!!) {
            binding.nfcStatusText.text = "Turn On NFC"
        } else {
            binding.nfcStatusText.text = "Searching..."
        }
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        receiveMessageFromDevice(intent)
    }

    override fun onResume() {
        super.onResume()
        enableForegroundDispatch(this, this.nfcAdapter)
        receiveMessageFromDevice(intent)
    }

    override fun onPause() {
        super.onPause()
        disableForegroundDispatch(this, this.nfcAdapter)
    }

    private fun receiveMessageFromDevice(intent: Intent) {
        val action = intent.action
        if (NfcAdapter.ACTION_TAG_DISCOVERED == action || NfcAdapter.ACTION_TECH_DISCOVERED == action || NfcAdapter.ACTION_NDEF_DISCOVERED == action) {

            val ndefMessage = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
            Log.d(TAG, "Parcelables data: $ndefMessage")

            if (!ndefMessage.isNullOrEmpty()) {
                val ndefRecord = (ndefMessage[0] as NdefMessage).records[0]
                val message = ndefRecord.payload.decodeToString()
                binding.nfcStatusText.text = "Message from tag NFC: $message"
            } else {
                binding.nfcStatusText.text = "No message on tag NFC"
            }
        }
    }

    private fun enableForegroundDispatch(activity: AppCompatActivity, adapter: NfcAdapter?) {
        val intent = Intent(this, javaClass)
        intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP

        val pendingIntent = PendingIntent.getActivity(
            this, 0, intent,
            PendingIntent.FLAG_IMMUTABLE
        )

        val filters = arrayOfNulls<IntentFilter>(1)
        val techList = arrayOf<Array<String>>()

        filters[0] = IntentFilter()
        with(filters[0]) {
            this?.addAction(NfcAdapter.ACTION_TAG_DISCOVERED)
            this?.addCategory(Intent.CATEGORY_DEFAULT)
            try {
                this?.addDataType(MIME_TEXT_PLAIN)
            } catch (ex: IntentFilter.MalformedMimeTypeException) {
                throw RuntimeException("Check your MIME type")
            }
        }

        adapter?.enableForegroundDispatch(activity, pendingIntent, filters, techList)
    }

    private fun disableForegroundDispatch(activity: AppCompatActivity, adapter: NfcAdapter?) {
        adapter?.disableForegroundDispatch(activity)
    }
}

Manifest配置

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

 <intent-filter>
            <action android:name="android.nfc.action.NDEF_DISCOVERED" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
 </intent-filter>

问题排查及修复方案

  • Foreground Dispatch过滤器不匹配
    enableForegroundDispatch中,ACTION_TAG_DISCOVERED不支持MIME类型过滤,只有ACTION_NDEF_DISCOVERED才会匹配text/plain类型。修改过滤器配置:

    with(filters[0]) {
        this?.addAction(NfcAdapter.ACTION_NDEF_DISCOVERED)
        this?.addCategory(Intent.CATEGORY_DEFAULT)
        try {
            this?.addDataType(MIME_TEXT_PLAIN)
        } catch (ex: IntentFilter.MalformedMimeTypeException) {
            throw RuntimeException("Check your MIME type")
        }
    }
    
  • 未启用设备间传输支持
    设备间NFC传输依赖Android Beam(Android 10及以下)或系统内置的分享功能,需补充配置:

    1. 在Manifest中添加NFC功能声明:
      <uses-feature android:name="android.hardware.nfc" android:required="true" />
      
    2. Android 10及以下需启用Foreground Ndef Push:
      if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
          nfcAdapter?.enableForegroundNdefPush(this, NdefMessage(NdefRecord.createMime(MIME_TEXT_PLAIN, ByteArray(0))))
      }
      
      Android 11+需使用NfcAdapter.setNdefPushMessageCallback替代。
  • onResume中错误读取Intent
    onResume中的intent是Activity启动Intent,不是NFC触发的Intent,删除该行代码:

    // receiveMessageFromDevice(intent) 移除这行
    
  • NDEF文本记录解析不规范
    NDEF文本Payload包含状态字节和语言编码,直接解码会出错,替换解析逻辑:

    private fun parseNdefTextRecord(record: NdefRecord): String {
        if (record.tnf != NdefRecord.TNF_WELL_KNOWN || !Arrays.equals(record.type, NdefRecord.RTD_TEXT)) {
            return ""
        }
        val payload = record.payload
        val languageCodeLength = payload[0].toInt() and 0x1F
        return String(payload, languageCodeLength + 1, payload.size - languageCodeLength - 1, Charsets.UTF_8)
    }
    

    在receiveMessageFromDevice中调用:

    val message = parseNdefTextRecord(ndefRecord)
    
  • Manifest补充设备间传输过滤器
    添加TECH_DISCOVERED过滤器确保识别设备连接:

    <intent-filter>
        <action android:name="android.nfc.action.TECH_DISCOVERED" />
    </intent-filter>
    <meta-data
        android:name="android.nfc.action.TECH_DISCOVERED"
        android:resource="@xml/nfc_tech_filter" />
    

    在res/xml目录创建nfc_tech_filter.xml:

    <resources>
        <tech-list>
            <tech>android.nfc.tech.Ndef</tech>
            <tech>android.nfc.tech.NdefFormatable</tech>
        </tech-list>
    </resources>
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 07:15:54