查看了那里很少的文档,包括相当稀疏的文档和我能找到的几个代码示例,我实现了以下 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>
问题是您不了解 NFC 的工作原理,NFC 硬件有多种工作模式,并且您试图获得两种不兼容的模式来相互通信。
更多详细信息这里
基本上,当一台设备需要处于读卡器/写入器模式而另一台设备处于主机卡模拟模式时,您的两台设备都处于读卡器/写入器模式。
我会查看 https://github.com/underwindfall/NFCAndroid,因为这是一个示例应用程序,可将其中一台设备切换为 HCE 模式。