I want to read NFC tag data only while I press the button on Android.

Asked 2 years ago, Updated 2 years ago, 434 views

On Android, there is a button on the screen, and I want to read NFC tags only while I press that button

I'm trying to do it with the code below, but when I put the NFC card close while I was pressing the button, the display didn't change and it didn't work.
Apparently, the onNewIntent does not occur even if the NFC tag is nearby.
Why?

"Now Reading Atag" appears when you press the read button, so OnTouch seems to have been supplemented.

I'm trying to run it on Android 10 (API 29) on Pixel 3 (Felica card compatible for Japanese model)

Update

I explicitly specified the techlist for enableForegroundDispatch, but it didn't work.

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)
        )

Update2

As Kouki.W said, it seemed difficult to realize with enableForegroundDispatch, so I changed it to enableReaderMode, but it still doesn't work.

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_Bor
                            NfcAdapter.FLAG_READER_NFC_BARCODE or
                            NfcAdapter.FLAG_READER_NFC_For
                            NfcAdapter.FLAG_READER_NFC_V
                            ),
                    null)

Update2 End

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:supportRtl="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 pendingintent —PendingIntent?= null
    varnfc_adapt —NfcAdapter ?= null
    variFilter:IntentFilter?= null
    vartview —TextView?= null
    var read_button —Button?=null // Button to press when loading
    var delete_button —Button?=null//Press button to erase TextView (tview) contents
    @SuppressLint ("ClickableViewAccessibility")
    override fun onCreate (savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tview=findViewById(R.id.textView) // TextView for display
        nfc_adapt = NfcAdapter.getDefaultAdapter (applicationContext)
        pendingIntent=PendingIntent.getActivity(this,0,Intent(this,javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),0
        )
        iFilter=IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)
        valiFilters=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!!.enableForegroundDispatches(this,pendintent,iFilters,null)
                    return false
                }
                MotionEvent.ACTION_UP->{
                    nfc_adapt!!.disableForegroundDispatches(this)
                    US>tview!!.text="
                    return false
                }
            }
            return false
        })

        // Delete contents of TextView

        delete_button!!.setOnClickListener{
            US>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)
        valaction —String?=intent.action
        if(action.equals(NfcAdapter.ACTION_TECH_DISCOVERED)){
            varnfc_tag_array=intent.getParcelableArrayExtra(NfcAdapter.EXTRA_TAG)
            if(nfc_tag_array==null){
                tvview?.setBackgroundColor(Color.YELLOW)
                tview?.setTextColor(Color.rgb(0,0,0))
                tvview?.text="read a tag but does not contain tag data"
                return
            }
            valt=nfc_tag_array[0]as Tag?
            if(t==null){
                tview!!.text="Read a tag but it a null"
            } else{
                tview!!.text=t.toString()// Display TAG contents (not data) as a string
            }
            tview!!.setBackgroundColor(Color.YELLOW)
            tview!!.setTextColor(Color.rgb(0,0,0))
            nfc_adapt!!.disableForegroundDispatches(this)
            read_button!!.isEnabled=false//Disable the read button once you read it so that you can read it again when delete_button is pressed
            delete_button!!.isEnabled=true


        }
        else{
            // nothing to do
        }
    }

}

android kotlin

2022-09-30 21:51

1 Answers

Hello, I saw/confirmed the code you gave me on the old device (Android 4.1.2/API Level 16).

I understand that enableForegrondDipatch does not work well, but when I check this document, it is as follows:

This method must be called from the main thread, and only when the activity is in the foreground (resumed).

This method is used to react to events on the NFC card with the foreground app as a top priority.(Of course, NFC scans other apps and services in the OS, so it cannot be stopped.)Therefore, the correct usage is to start with onResume in the lifecycle event and stop with onPause.In fact, if you implement it that way, it works fine for us.

If you want to react temporarily, such as only when you press a button, why don't you consider another implementation, such as launching read activity/fragments with a button, reading them, and then returning them to the previous page?

With thread relationships, you may be able to move if you work hard, but it seems like a less recommended way.

https://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc?hl=ja#foreground-dispatch

https://developer.android.com/reference/android/nfc/NfcAdapter#enableForegroundDispatch(android.app.Activity,%20android.app.PendingIntent,%20android.content.IntentFilter[], %20java.lang.String[][])

We received a comment saying that NfcAdapter.enableReadMode (implemented from Android 4.4) was able to be read by NFC Activity from a time other than onResume.

https://qiita.com/zaburo/items/6a34dfd8f87d7ffba56a


2022-09-30 21:51

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.