nfcim / flutter_nfc_kit

Flutter plugin to provide NFC functionality on Android and iOS, including reading metadata, read & write NDEF records, and transceive layer 3 & 4 data with NFC tags / cards
https://pub.dev/packages/flutter_nfc_kit
MIT License
199 stars 116 forks source link

Read memory #35

Closed Mythar closed 3 years ago

Mythar commented 3 years ago

Hello, is it possible to read the memory of a card directly (not as a NDEF tag)? The point of reading the data directly, is to code the memory to avoid the annoying android NDEF tag dialog popup. The app: NFC Tools, has this options, and I need it :)

Harry-Chen commented 3 years ago

Sure. You may refer to the documentation of your tag and use proper commands (e.g. APDU in ISO14443) to read the memory.

Mythar commented 3 years ago

Can you give me an example please? :)

jiegec commented 3 years ago

You can refer to https://www.nxp.com/docs/en/application-note/AN1305.pdf for reading MIFARE Classic Tags.

Mythar commented 3 years ago

I need to read Mifare Ultralight EV1, iso14443A

jiegec commented 3 years ago

Possibly useful links for you:

https://www.nxp.com.cn/docs/en/application-note/AN11340.pdf

https://www.nxp.com.cn/docs/en/data-sheet/MF3ICDX21_41_81_SDS.pdf

https://stackoverflow.com/questions/42542610/authenticating-ultralight-ev1-with-pc-sc-reader

Mythar commented 3 years ago

Thx, trying to make sense of it all...

Mythar commented 3 years ago

Ok, got this far: FF B0 00 04 30 according to: https://tech.springcard.com/2014/reading-and-writing-data-in-a-mifare-ultralight-card-with-a-proxnroll/ Using the springcard encoder in my card printer, it reads the card as it should, in SHARED mode, not in DIRECT mode.

Test code:

NFCTag tag = await FlutterNfcKit.poll(
          timeout: Duration(seconds: 10),
          androidPlatformSound: false,
          androidCheckNDEF: widget.androidCheckNDEF,
          iosAlertMessage: widget.text
      );

      if (tag.type == NFCTagType.mifare_ultralight) {
        var result = await FlutterNfcKit.transceive("FFB0000430", timeout: Duration(seconds: 10)); // timeout is still Android-only, persist until next change
        print('READ:');
        print(result);
      }

I get this error:

E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): Transceive Error: FFB0000430 E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): android.nfc.TagLostException: Tag was lost. E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:48) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:154) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at android.nfc.tech.NfcA.transceive(NfcA.java:123) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at java.lang.reflect.Method.invoke(Native Method) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin$Companion.transceive(FlutterNfcKitPlugin.kt:48) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin$Companion.access$transceive(FlutterNfcKitPlugin.kt:32) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin.handleMethodCall(FlutterNfcKitPlugin.kt:131) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin.onMethodCall(FlutterNfcKitPlugin.kt:58) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at android.os.MessageQueue.nativePollOnce(Native Method) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at android.os.MessageQueue.next(MessageQueue.java:335) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at android.os.Looper.loop(Looper.java:206) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at android.app.ActivityThread.main(ActivityThread.java:8512) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at java.lang.reflect.Method.invoke(Native Method) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602) E/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130) W/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): Exception occurred when using MethodChannel.Result: java.lang.IllegalStateException: Reply already submitted W/im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin(13567): Will ignore all following usage of object: io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1@ece65a9

Mythar commented 3 years ago

No matter what i send in transceive, i keep getting a Transceive Error. Your code calls android.nfc.tech.NfcA.transceive, would it matter if changed to android.nfc.tech.MifareUltralight.transceive ? I know MifareUltralight tags are NfcA, so not sure if it would make a difference ?

jiegec commented 3 years ago

No matter what i send in transceive, i keep getting a Transceive Error. Your code calls android.nfc.tech.NfcA.transceive, would it matter if changed to android.nfc.tech.MifareUltralight.transceive ? I know MifareUltralight tags are NfcA, so not sure if it would make a difference ?

That's probably where the problem lies. You can try to call MifareUltralight instead in your application and see if it works.

Harry-Chen commented 3 years ago

See https://github.com/nfcim/flutter_nfc_kit/blob/a7e277ae4cb6ae8b492ad693607d5acb55d3245c/android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt#L319-L376

You may add tagTechnology = MifareUltralight.get(tag) after line 336 and see if it works.

Mythar commented 3 years ago

Tried it - not working.

However I came across this in: https://developer.android.com/reference/android/nfc/tech/MifareUltralight

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

Not sure what they mean by "implemented" ?

jiegec commented 3 years ago

It depends on your Android phone. If it is implemented by the card reader chip in your phone, it can be implemented in software.

Mythar commented 3 years ago

I know my phone can read the card, using the NFC Tools app (Tested on both Android phone and iPhone)

The exception thrown is: InvocationTargetException

I tested on my iPhone also, but get same-ish error:

[CoreNFC] 00000002 83cc41b0 -[NFCTagReaderSession transceive:tagUpdate:error:]:789 Error Domain=NFCError Code=100 "Tag connection lost" UserInfo={NSLocalizedDescription=Tag connection lost}

Mythar commented 3 years ago

I did some more digging and found that I cant read the whole mem in one go. Using:

var mem1 = await FlutterNfcKit.transceive("3004", timeout: Duration(seconds: 10)); // timeout is still Android-only, persist until next change
var mem2 = await FlutterNfcKit.transceive("3008", timeout: Duration(seconds: 10)); // timeout is still Android-only, persist until next change
var mem3 = await FlutterNfcKit.transceive("300C", timeout: Duration(seconds: 10)); // timeout is still Android-only, persist until next change

Works!

Harry-Chen commented 3 years ago

I know my phone can read the card, using the NFC Tools app (Tested on both Android phone and iPhone)

The exception thrown is: InvocationTargetException

I tested on my iPhone also, but get same-ish error:

[CoreNFC] 00000002 83cc41b0 -[NFCTagReaderSession transceive:tagUpdate:error:]:789 Error Domain=NFCError Code=100 "Tag connection lost" UserInfo={NSLocalizedDescription=Tag connection lost}

InvocationTargetException probably means your MifareUltralight class has no transceive method.