如何在 Android 中读取 NFC“标签”

问题描述 投票:0回答:1

查看了那里很少的文档,包括相当稀疏的文档和我能找到的几个代码示例,我实现了以下 Activity,该 Activity 应该从另一台安装了 应用程序的 Android 设备中获取简单的文本消息它允许通过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)

        // Inizializzazione del NfcAdapter
        nfcAdapter = NfcAdapter.getDefaultAdapter(this)


        // Verifica se il dispositivo supporta l'NFC
        if (nfcAdapter == null) {
            Log.w(TAG, "NFC non supportato!")
            // Il dispositivo non supporta l'NFC
            binding.nfcStatusText.text = "No NFC on this device."
        } else {
            // Imposta il click listener per il pulsante NFC
            binding.nfcButton.setOnClickListener {
                // Avvia l'attivazione dell'NFC
                enableNfc()
            }
        }
    }

    private fun enableNfc() {
        Log.w(TAG, "Abilito l'NFC...", )
        // Controlla se l'NFC è abilitato sul dispositivo
        if (!nfcAdapter?.isEnabled!!) {
            // Se l'NFC è disabilitato, mostra un messaggio all'utente per attivarlo
            binding.nfcStatusText.text = "Turn On NFC"
        } else {
            // L'NFC è già abilitato, attende il rilevamento del dispositivo NFC
            binding.nfcStatusText.text = "Searching..."
        }
    }

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

        // also reading NFC message from here in case this activity is already started in order
        // not to start another instance of this activity
        receiveMessageFromDevice(intent)
    }

    override fun onResume() {
        super.onResume()

        // foreground dispatch should be enabled here, as onResume is the guaranteed place where app
        // is in the foreground
        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_NDEF_DISCOVERED == 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"
            }
        }
    }


    // Foreground dispatch holds the highest priority for capturing NFC intents
    // then go activities with these intent filters:
    // 1) ACTION_NDEF_DISCOVERED
    // 2) ACTION_TECH_DISCOVERED
    // 3) ACTION_TAG_DISCOVERED

    // always try to match the one with the highest priority, cause ACTION_TAG_DISCOVERED is the most
    // general case and might be intercepted by some other apps installed on your device as well

    // When several apps can match the same intent Android OS will bring up an app chooser dialog
    // which is undesirable, because user will most likely have to move his device from the tag or another
    // NFC device thus breaking a connection, as it's a short range

    private fun enableForegroundDispatch(activity: AppCompatActivity, adapter: NfcAdapter?) {

        // here we are setting up receiving activity for a foreground dispatch
        // thus if activity is already started it will take precedence over any other activity or app
        // with the same intent filters

        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)//ACTION_NDEF_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)
    }
}

问题是我在第二个 Android 设备上安装的用于写入该设备的应用程序给了我一个错误,并且不允许我写入该设备。

我不明白我的代码有什么问题,我还在清单中添加了以下权限并声明了以下意图过滤器:

<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>
android kotlin nfc
1个回答
0
投票

问题是您不了解 NFC 的工作原理,NFC 硬件有多种工作模式,并且您试图获得两种不兼容的模式来相互通信。

更多详细信息这里

基本上,当一台设备需要处于读卡器/写入器模式而另一台设备处于主机卡模拟模式时,您的两台设备都处于读卡器/写入器模式。

我会查看 https://github.com/underwindfall/NFCAndroid,因为这是一个示例应用程序,可将其中一台设备切换为 HCE 模式。

© www.soinside.com 2019 - 2024. All rights reserved.