From 4955d1bd81288af37c5ba44b82a65f12b227e498 Mon Sep 17 00:00:00 2001 From: Wouter Ensink <46427708+w-ensink@users.noreply.github.com> Date: Mon, 29 Dec 2025 10:21:43 +0100 Subject: [PATCH 1/2] fix android timeout bug --- .../flutter_nfc_kit/FlutterNfcKitPlugin.kt | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt b/android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt index e54c4c3..5e719fc 100644 --- a/android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt +++ b/android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt @@ -8,6 +8,7 @@ import android.nfc.NfcAdapter import android.nfc.NfcAdapter.* import android.nfc.Tag import android.nfc.tech.* +import android.os.Bundle import android.os.Handler import android.os.HandlerThread import android.os.Looper @@ -86,13 +87,13 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { Log.e(TAG, "$desc error", ex) val excMessage = ex.localizedMessage when (ex) { - is IOException -> result?.error("500", "Communication error", excMessage) - is SecurityException -> result?.error("503", "Tag already removed", excMessage) - is FormatException -> result?.error("400", "NDEF format error", excMessage) - is InvocationTargetException -> result?.error("500", "Communication error", excMessage) - is IllegalArgumentException -> result?.error("400", "Command format error", excMessage) - is NoSuchMethodException -> result?.error("405", "Transceive not supported for this type of card", excMessage) - else -> result?.error("500", "Unhandled error", excMessage) + is IOException -> result.error("500", "Communication error", excMessage) + is SecurityException -> result.error("503", "Tag already removed", excMessage) + is FormatException -> result.error("400", "NDEF format error", excMessage) + is InvocationTargetException -> result.error("500", "Communication error", excMessage) + is IllegalArgumentException -> result.error("400", "Command format error", excMessage) + is NoSuchMethodException -> result.error("405", "Transceive not supported for this type of card", excMessage) + else -> result.error("500", "Unhandled error", excMessage) } } } @@ -141,7 +142,7 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { tagTechnology = isoDep // historicalBytes() may return null but is wrongly typed as ByteArray! // https://developer.android.com/reference/kotlin/android/nfc/tech/IsoDep#gethistoricalbytes - historicalBytes = (isoDep.historicalBytes as ByteArray?)?.toHexString() ?: "" + historicalBytes = isoDep.historicalBytes?.toHexString() ?: "" } tag.techList.contains(MifareClassic::class.java.name) -> { standard = "ISO 14443-3 (Type A)" @@ -604,7 +605,12 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { result.success(jsonResult) } - nfcAdapter.enableReaderMode(activity.get(), pollHandler, technologies, null) + // The EXTRA_READER_PRESENCE_CHECK_DELAY is for fixing an obscure bug with + // some Android versions like LineageOS 17.1 that caused the PACE authentication to fail. + // See https://github.com/privacybydesign/vcmrtd/issues/91 for more info. + val options = Bundle() + options.putInt(EXTRA_READER_PRESENCE_CHECK_DELAY, 2000) + nfcAdapter.enableReaderMode(activity.get(), pollHandler, technologies, options) } private class MethodResultWrapper(result: Result) : Result { From bb6fb63c857cb223f7f58f4e2a78165a4f0b07ab Mon Sep 17 00:00:00 2001 From: Wouter Ensink <46427708+w-ensink@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:33:13 +0100 Subject: [PATCH 2/2] add extra_reader_presence_check_delay to poll function in dart --- .../im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt | 14 +++++++------- lib/flutter_nfc_kit.dart | 4 ++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt b/android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt index 5e719fc..4b502b8 100644 --- a/android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt +++ b/android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt @@ -330,8 +330,10 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { val timeout = call.argument("timeout")!! // technology and option bits are set in Dart code val technologies = call.argument("technologies")!! + val extraPresenceDelay = call.argument("extra_reader_presence_check_delay") + runOnNfcThread(result, "Poll") { - pollTag(nfcAdapter, result, timeout, technologies) + pollTag(nfcAdapter, result, timeout, technologies, extraPresenceDelay) } } @@ -584,8 +586,7 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { override fun onDetachedFromActivityForConfigChanges() {} - private fun pollTag(nfcAdapter: NfcAdapter, result: Result, timeout: Int, technologies: Int) { - + private fun pollTag(nfcAdapter: NfcAdapter, result: Result, timeout: Int, technologies: Int, extraReaderPresenceCheckDelay: Int?) { pollingTimeoutTask = Timer().schedule(timeout.toLong()) { try { if (activity.get() != null) { @@ -605,11 +606,10 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { result.success(jsonResult) } - // The EXTRA_READER_PRESENCE_CHECK_DELAY is for fixing an obscure bug with - // some Android versions like LineageOS 17.1 that caused the PACE authentication to fail. - // See https://github.com/privacybydesign/vcmrtd/issues/91 for more info. val options = Bundle() - options.putInt(EXTRA_READER_PRESENCE_CHECK_DELAY, 2000) + if (extraReaderPresenceCheckDelay != null) { + options.putInt(EXTRA_READER_PRESENCE_CHECK_DELAY, extraReaderPresenceCheckDelay) + } nfcAdapter.enableReaderMode(activity.get(), pollHandler, technologies, options) } diff --git a/lib/flutter_nfc_kit.dart b/lib/flutter_nfc_kit.dart index 1df0778..dcef523 100644 --- a/lib/flutter_nfc_kit.dart +++ b/lib/flutter_nfc_kit.dart @@ -337,6 +337,7 @@ class FlutterNfcKit { bool readIso18092 = false, bool readIso15693 = true, bool probeWebUSBMagic = false, + Duration? extraReaderPresenceCheckDelay, }) async { // use a bitmask for compact representation int technologies = 0x0; @@ -354,6 +355,9 @@ class FlutterNfcKit { 'iosMultipleTagMessage': iosMultipleTagMessage, 'technologies': technologies, 'probeWebUSBMagic': probeWebUSBMagic, + if (extraReaderPresenceCheckDelay != null) + "extra_reader_presence_check_delay": + extraReaderPresenceCheckDelay.inMilliseconds, }); return NFCTag.fromJson(jsonDecode(data)); }