Flutter and working with native code

PurplePlane
3 min readMay 11, 2022

--

Flutter and reading the card data with NFC

How to fix the shortcomings in native libraries while working with Flutter, using NFC as an example.

In most cases when working with flutter, the developer doesn’t have to interact with the native code at all (Java/Kotlin and ObjectiveC/Swift), as the flutter’s toolbox is quite rich. But in some cases, you simply can’t do what you need without it. The most popular example is working with phone sensors.

Let’s work through this problem: imagine that you have to read the card data using NFC. We chose the plugin, in our case it was nfc_manager 3.1.0, which will allow us to do such things, but the needed card number doesn’t get returned to the android because of it. What do you do? We have recently encountered such a problem and now we will tell you how to solve it

To solve this problem, you need to perform several steps. First you need to copy the library’s code into your project. It should look like this:

A word of advice: if there are several of these packages, it is better to put them in a separate folder at the same nesting level and call it “packages”, for example.

Then we need to localize the moment, in which the reading of the bank card number is not happening. To start the reading from flutter, the “startSession” method is being called, which, in turn, calls the native method “Nfc#startSession”. Inside it, everything is set up fairly simply:

adapter.enableReaderMode(activity, {val handle = UUID.randomUUID().toString()tags[handle] = itactivity.runOnUiThread { channel.invokeMethod("onDiscovered", getTagMap(it).toMutableMap().apply { put("handle", handle) }) }}, getFlags(call.argument<List<String>>("pollingOptions")!!), null)

Now we need to slightly modify the current code, so that we would be able to send the card number to flutter.

To do this, at first we need to import a corresponding native library into the build.grade file:

implementation ‘com.github.devnied.emvnfccard:library:3.0.1’

Then we need to make an implementation for the interface from this library IProvider, which transfers commands to the card. The needed implementation looks like this:

class Provider : IProvider {
private var mTagCom: IsoDep? = null
@Throws(CommunicationException::class)
override fun transceive(pCommand: ByteArray): ByteArray {
val response: ByteArray = try {
// send command to emv card
mTagCom!!.transceive(pCommand)
} catch (e: IOException) {
throw CommunicationException(e.message)
}
return response
}
override fun getAt(): ByteArray {
// For NFC-A
return mTagCom!!.historicalBytes
// For NFC-B
// return mTagCom.getHiLayerResponse();
}
fun setmTagCom(mTagCom: IsoDep?) {
this.mTagCom = mTagCom
}
}

Then we will edit the code itself before sending the data to flutter in “onDiscovered”.

To read the card data, we need to add the interface implementation, created above, as well as config and parser. Now the code looks something like this:

val provider: IProvider = Provider()(provider as Provider).setmTagCom(IsoDep.get(it))
val config: EmvTemplate.Config = EmvTemplate.Config()
.setContactLess(true) // Enable contact less reading (default: true)
.setReadAllAids(true) // Read all aids in card (default: true)
.setReadTransactions(true) // Read all transactions (default: true)
.setReadCplc(false) // Read and extract CPCLC data (default: false)
.setRemoveDefaultParsers(false) // Remove default parsers for GeldKarte and EmvCard (default: false)
.setReadAt(true) // Read and extract ATR/ATS and description
val parser = EmvTemplate.Builder() //
.setProvider(provider) // Define provider
.setConfig(config) // Define config
//.setTerminal(terminal) (optional) you can define a custom terminal implementation to create APDU
.build()

Then we need to connect to the card and read the needed data:

val mIsoDep = IsoDep.get(it)
mIsoDep.connect()
val card = parser.readEmvCard()

And then we will finally send the needed data to flutter, by adding to map the received card data:

activity.runOnUiThread {
channel.invokeMethod("onDiscovered", getTagMap(it).toMutableMap().apply {
put("handle", handle)
put("cardNumber", card.cardNumber)
put("holderFirstName", card.holderFirstname)
put("holderLastName", card.holderLastname)
put("type", card.type.getName())
})
}

Now we can receive the card data using NFC.

--

--