スタック・オーバーフロー Asked on November 22, 2021
Androidで画面上にボタンがあり、そのボタンを押している間だけNFCタグを読み込むようにしたいです
下記のコードで実現しようとしているのですが、ボタンを押している間にNFCカードを近づけても表示が変わらず、うまくいきません。
どうやらNFCタグが近くにあってもonNewIntentが発生しないようです。
なぜでしょうか?
読み取り用のボタンを押すと"Now Reading A tag"は表示されるのでOnTouchは補足できているようです。
Pixel3(日本モデルのためFelicaカード対応)上のAndroid 10 (API 29)で動かそうとしています
enableForegroundDispatchのtechlistを明示的に指定してみましたがうまく行きませんでした。
techlist = arrayOf(
arrayOf(android.nfc.tech.NfcA::class.java.name),
arrayOf(android.nfc.tech.NfcB::class.java.name),
arrayOf(android.nfc.tech.IsoDep::class.java.name),
arrayOf(android.nfc.tech.MifareClassic::class.java.name),
arrayOf(android.nfc.tech.NfcV::class.java.name),
arrayOf(android.nfc.tech.NfcF::class.java.name),
arrayOf(android.nfc.tech.NdefFormatable::class.java.name),
arrayOf(android.nfc.tech.MifareUltralight::class.java.name)
)
Kouki. WさんがおっしゃるようにenableForegroundDispatchでは実現が難しそうだったため、enableReaderModeに変えてみましたがやはりうまくできません。
nfc_adapt!!.enableReaderMode(this, {t ->
tview!!.text = t.toString()
tview!!.setBackgroundColor(Color.YELLOW)
tview!!.setTextColor(Color.rgb(0,0,0))
nfc_adapt!!.disableReaderMode(this)
read_button!!.isEnabled = false // disable read button until user push the delete button
delete_button!!.isEnabled = true
},(
NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK or
NfcAdapter.FLAG_READER_NFC_A or
NfcAdapter.FLAG_READER_NFC_B or
NfcAdapter.FLAG_READER_NFC_BARCODE or
NfcAdapter.FLAG_READER_NFC_F or
NfcAdapter.FLAG_READER_NFC_V
),
null)
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.youtube_dler">
<uses-permission android:name="android.permission.NFC"></uses-permission>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.kt:
class MainActivity : AppCompatActivity() {
var pendintent: PendingIntent? = null
var nfc_adapt: NfcAdapter? = null
var iFilter: IntentFilter? = null
var tview: TextView? = null
var read_button: Button? = null // 読み込むときに押すボタン
var delete_button: Button? = null // TextView(tview)の内容を消すときに押すボタン
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tview = findViewById(R.id.textView) // 表示用のTextView
nfc_adapt = NfcAdapter.getDefaultAdapter(applicationContext)
pendintent = PendingIntent.getActivity(this, 0, Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0
)
iFilter = IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)
val iFilters = arrayOf<IntentFilter>(iFilter!!)
read_button = findViewById(R.id.button)
delete_button = findViewById(R.id.button2)
delete_button!!.isEnabled = false
read_button!!.setOnTouchListener(fun(v: View, m: MotionEvent) : Boolean {
when (m.action) {
MotionEvent.ACTION_DOWN -> {
tview!!.setBackgroundColor(Color.rgb(0,0,0))
tview!!.setTextColor(Color.rgb(0, 255, 0))
tview!!.text = "Now Reading A Tag"
Log.d(null, "ACTION UPPED")
nfc_adapt!!.enableForegroundDispatch(this, pendintent,iFilters, null)
return false
}
MotionEvent.ACTION_UP -> {
nfc_adapt!!.disableForegroundDispatch(this)
tview!!.text = ""
return false
}
}
return false
})
// Delete contents of TextView
delete_button!!.setOnClickListener {
tview!!.text = ""
tview!!.setBackgroundColor(Color.rgb(0, 0, 0))
tview!!.setTextColor(Color.rgb(0, 255, 0))
read_button!!.isEnabled = true
it.isEnabled = false
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val action: String? = intent.action
if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
var nfc_tag_array = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_TAG)
if (nfc_tag_array == null) {
tview?.setBackgroundColor(Color.YELLOW)
tview?.setTextColor(Color.rgb(0,0,0))
tview?.text = "read a tag but does not contain tag data"
return
}
val t = nfc_tag_array[0] as Tag?
if (t == null) {
tview!!.text = "Read a tag but it a null"
} else {
tview!!.text = t.toString() // TAGの内容(データではない)を文字列で表示する
}
tview!!.setBackgroundColor(Color.YELLOW)
tview!!.setTextColor(Color.rgb(0,0,0))
nfc_adapt!!.disableForegroundDispatch(this)
read_button!!.isEnabled = false // 読んだら一旦読み込みボタンを無効にしてdelete_buttonが押されたら再度読み込みできるようにする
delete_button!!.isEnabled = true
}
else {
// nothing to do
}
}
}
こんにちは、少し古い端末(Android 4.1.2/API Level16)で頂いたコードを拝見/確認させていただきました。
enableForegrondDipatchがうまく動作しないとのことですが、こちらドキュメントを確認すると以下のようにあります。
This method must be called from the main thread, and only when the activity is in the foreground (resumed).
このメソッドですが、フォアグラウンドになっているアプリを最優先にしてNFCカードのイベントに反応させるために用います。(当然OS内の他のアプリやサービスもNFCはスキャンしてるのでスキャンを止めることはできません)。そのためライフサイクルイベント内のonResumeで開始、onPauseで停止という用法が正しいです。実際そのように実装した場合は当方では問題なく動作しています。
ボタンを押した時のみなど一時的に反応させたい理由があるのであれば、ボタンで読み取り用のアクティビティ/フラグメントを起動、読み取り後、前のページに戻すなど、別の実装方法を検討されてはいかがでしょうか?
スレッド関係で、頑張れば動かせる可能性はありますが、あまり推奨されないやりかたに思えます。
https://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc?hl=ja#foreground-dispatch
NfcAdapter.enableReadMode (Android 4.4から実装) を利用してonResume以外のタイミングからNFCのActivityによる読み取りが行えたとの旨コメントをいただきました。
Answered by Kouki.W on November 22, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP