Search code examples
androidkotlinandroid-intentnfc

Android Kotlin: NFC Tag not reading by the app


I've recently created an NFC tag reader app, but unfortunately, my app doesn't seem to recognize it but it was detected by the system (mobile) software and redirect to the inbuild NFC scanner. I've double-checked my code and connections and seem look corrected as I follows the official documentation, but I'm still facing this issue.

Issue: App not detect the NFC callback at onNewIntent(), it redirect to the in-build feature. Works fine with other (downloaded) apps.

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.NFC" />
    <uses-feature
        android:name="android.hardware.nfc"
        android:required="true" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.NFCApp"
        tools:targetApi="31">
        <activity
            android:name=".AnotherActivity"
            android:exported="false" />

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                <data android:mimeType="text/plain" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />
        </activity>
    </application>

</manifest>

nfc_tech_filter.xml at <project-root>/res/xml:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.Ndef</tech>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.NfcB</tech>
    </tech-list>
</resources>

MainActivity:

class MainActivity : AppCompatActivity() {
    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)
        nfcAdapter = NfcAdapter.getDefaultAdapter(this)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        Log.d("CHKI", "NEW NFC DETECTED")

        if (intent?.action == NfcAdapter.ACTION_NDEF_DISCOVERED) {
            Log.d("CHKI", "ACTION_NDEF_DISCOVERED")
        }

        if (intent?.action == NfcAdapter.ACTION_TECH_DISCOVERED) {
            Log.d("CHKI", "ACTION_TECH_DISCOVERED")
        }
    }
}

Has anyone else encountered a similar problem, and if so, what steps did you take to resolve it? Any insights or suggestions would be greatly appreciated! Thanks in advance.


Solution

  • Just added onResume & onPause and now NFC is working fine with my existing code. These methods are used to enable and disable the foreground dispatch system.

    Here is the code:

    class MainActivity : AppCompatActivity() {
        private lateinit var binding: ActivityMainBinding
        private var nfcAdapter: NfcAdapter? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            // existing code
        }
    
        override fun onNewIntent(intent: Intent?) {
            super.onNewIntent(intent)
            // existing code
        }
    
        // Added new
        override fun onResume() {
            super.onResume()
            val pendingIntent = PendingIntent.getActivity(
                this,
                0,
                Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
                PendingIntent.FLAG_MUTABLE
            )
            nfcAdapter?.enableForegroundDispatch(this, pendingIntent, null, null)
        }
    
        // Added new
        override fun onPause() {
            super.onPause()
            nfcAdapter?.disableForegroundDispatch(this)
        }
    }