提问人:Antonio 提问时间:11/2/2023 更新时间:11/2/2023 访问量:57
如何在 Android 中读取 NFC“TAG”
How to read an NFC 'TAG' in Android
问:
查看那里的少量文档,包括相当稀疏的文档和我能找到的几个代码示例,我实现了以下 Activity,该活动应该从另一台安装了允许通过 NFC 发短信的应用程序的 Android 设备上获取一条简单的短信。
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>
答:
1赞
Andrew
11/2/2023
#1
问题是你不了解NFC是如何工作的,NFC硬件有多种工作模式,你正试图让两种不兼容的模式相互通信。
基本上,当一台设备需要处于读/写模式,而另一台设备需要处于主机卡仿真模式时,两台设备都处于读/写模式。
我会 https://github.com/underwindfall/NFCAndroid 结帐,因为这是一个示例应用程序,用于将其中一个设备切换到 HCE 模式。
评论