Search code examples
androidnfcandroid-4.4-kitkatndef

Is NFC NDEF supported on Kitkat?


I am trying to read NFC NDEF Messages using a MobiPrint Device running on KitKat.

I followed the instructions in the Docs, but I can't seem to get it to work on Kitkat.

AndroidManifest.xml:

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

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.NFC" />

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

    <application
        android:name=".App"
        android:allowBackup="true"
        android:fullBackupContent="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Pos">
        <activity
            android:name=".ui.views.main.MainActivity"
            android:theme="@style/Theme.Pos.NoActionBar">
            <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" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>
        </activity>
    </application>
</manifest>

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    private var adapter: NfcAdapter? = null
    private var pendingIntent: PendingIntent? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        adapter = NfcAdapter.getDefaultAdapter(this)

        pendingIntent = PendingIntent.getActivity(this, 0,
            Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
    }

    override fun onResume() {
        super.onResume()
        adapter?.enableForegroundDispatch(this, pendingIntent, null, null)
    }

    override fun onPause() {
        super.onPause()
        adapter?.disableForegroundDispatch(this)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)

        val rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
        Log.d("NFC_NDEF_MESSAGES", rawMessages.toString())
        Log.d("NFC_NDEF_ACTION", intent.action.toString())
    }
}

Logcat Messages

MobiPrint Device with Kitkat:

NFC_NDEF_MESSAGES: null NFC_NDEF_ACTION: android.nfc.action.TAG_DISCOVERED

S7 Active with Marshmallow:

NFC_NDEF_MESSAGES: [Landroid.os.Parcelable;@6405e69 NFC_NDEF_ACTION: android.nfc.action.NDEF_DISCOVERED

Is NDEF not supported on Kitkat?


Solution

  • The NXP MIFARE Classic series of NFC Cards do not conform to the NFC Forum standards (the specification pre-dates the NFC Standards)

    Thus some hardware does not support the NXP MIFARE Classic series of NFC Cards and if you look at the Android docs https://developer.android.com/reference/android/nfc/tech/MifareClassic

    Implementation of this class on a Android NFC device is optional. If it is not implemented, then MifareClassic will never be enumerated in Tag#getTechList. If it is enumerated, then all MifareClassic I/O operations will be supported, and Ndef#MIFARE_CLASSIC NDEF tags will also be supported. In either case, NfcA will also be enumerated on the tag, because all MIFARE Classic tags are also NfcA.

    So support for this type of card is Optional in Android and as it says if it is supported then the higher level NDEF protocol will be support on top of it (but as in your case it is not supported at the MifareClassic level then NDEF won't be supported on top)

    This is probably why you are getting the android.nfc.action.TAG_DISCOVERED message as this comes from the low level NfcA which is a low very protocol which MifareClassic has in common with other NFC Specification cards.

    Solution to get the MobiPrint Device to read NFC tag is use buy different NFC Tags unfortunately, this is nothing to do with the Android Version (Even some later Android hardware won't read them), I Suggest using an NFC Forum specification type Tag. A close match is the NXP TAG 216 card (NFC Forum Type 2) or the NXP Desfire (NFC Forum Type 4)