@@ -6,6 +6,7 @@ import android.nfc.NdefMessage
66import android.nfc.NdefRecord
77import android.nfc.NfcAdapter
88import android.nfc.NfcAdapter.*
9+ import android.nfc.Tag
910import android.nfc.tech.*
1011import android.os.Handler
1112import android.os.HandlerThread
@@ -24,6 +25,9 @@ import io.flutter.plugin.common.MethodCall
2425import io.flutter.plugin.common.MethodChannel
2526import io.flutter.plugin.common.MethodChannel.MethodCallHandler
2627import io.flutter.plugin.common.MethodChannel.Result
28+ import io.flutter.plugin.common.EventChannel
29+ import io.flutter.plugin.common.EventChannel.EventSink
30+ import io.flutter.plugin.common.EventChannel.StreamHandler
2731import org.json.JSONArray
2832import org.json.JSONObject
2933import java.io.IOException
@@ -45,6 +49,16 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
4549
4650 private lateinit var nfcHandlerThread: HandlerThread
4751 private lateinit var nfcHandler: Handler
52+ private lateinit var methodChannel: MethodChannel
53+ private lateinit var eventChannel: EventChannel
54+ private var eventSink: EventSink ? = null
55+
56+ public fun handleTag (tag : Tag ) {
57+ val result = parseTag(tag)
58+ Handler (Looper .getMainLooper()).post {
59+ eventSink?.success(result)
60+ }
61+ }
4862
4963 private fun TagTechnology.transceive (data : ByteArray , timeout : Int? ): ByteArray {
5064 if (timeout != null ) {
@@ -79,18 +93,178 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
7993 result.error(" 500" , " Failed to post job to NFC Handler thread." , null )
8094 }
8195 }
96+
97+ private fun parseTag (tag : Tag ): String {
98+ // common fields
99+ val type: String
100+ val id = tag.id.toHexString()
101+ val standard: String
102+ // ISO 14443 Type A
103+ var atqa = " "
104+ var sak = " "
105+ // ISO 14443 Type B
106+ var protocolInfo = " "
107+ var applicationData = " "
108+ // ISO 7816
109+ var historicalBytes = " "
110+ var hiLayerResponse = " "
111+ // NFC-F / Felica
112+ var manufacturer = " "
113+ var systemCode = " "
114+ // NFC-V
115+ var dsfId = " "
116+ // NDEF
117+ var ndefAvailable = false
118+ var ndefWritable = false
119+ var ndefCanMakeReadOnly = false
120+ var ndefCapacity = 0
121+ var ndefType = " "
122+
123+ if (tag.techList.contains(NfcA ::class .java.name)) {
124+ val aTag = NfcA .get(tag)
125+ atqa = aTag.atqa.toHexString()
126+ sak = byteArrayOf(aTag.sak.toByte()).toHexString()
127+ tagTechnology = aTag
128+ when {
129+ tag.techList.contains(IsoDep ::class .java.name) -> {
130+ standard = " ISO 14443-4 (Type A)"
131+ type = " iso7816"
132+ val isoDep = IsoDep .get(tag)
133+ tagTechnology = isoDep
134+ historicalBytes = isoDep.historicalBytes.toHexString()
135+ }
136+ tag.techList.contains(MifareClassic ::class .java.name) -> {
137+ standard = " ISO 14443-3 (Type A)"
138+ type = " mifare_classic"
139+ with (MifareClassic .get(tag)) {
140+ tagTechnology = this
141+ mifareInfo = MifareInfo (
142+ this .type,
143+ size,
144+ MifareClassic .BLOCK_SIZE ,
145+ blockCount,
146+ sectorCount
147+ )
148+ }
149+ }
150+ tag.techList.contains(MifareUltralight ::class .java.name) -> {
151+ standard = " ISO 14443-3 (Type A)"
152+ type = " mifare_ultralight"
153+ with (MifareUltralight .get(tag)) {
154+ tagTechnology = this
155+ mifareInfo = MifareInfo .fromUltralight(this .type)
156+ }
157+ }
158+ else -> {
159+ standard = " ISO 14443-3 (Type A)"
160+ type = " unknown"
161+ }
162+ }
163+ } else if (tag.techList.contains(NfcB ::class .java.name)) {
164+ val bTag = NfcB .get(tag)
165+ protocolInfo = bTag.protocolInfo.toHexString()
166+ applicationData = bTag.applicationData.toHexString()
167+ if (tag.techList.contains(IsoDep ::class .java.name)) {
168+ type = " iso7816"
169+ standard = " ISO 14443-4 (Type B)"
170+ val isoDep = IsoDep .get(tag)
171+ tagTechnology = isoDep
172+ hiLayerResponse = isoDep.hiLayerResponse.toHexString()
173+ } else {
174+ type = " unknown"
175+ standard = " ISO 14443-3 (Type B)"
176+ tagTechnology = bTag
177+ }
178+ } else if (tag.techList.contains(NfcF ::class .java.name)) {
179+ standard = " ISO 18092 (FeliCa)"
180+ type = " iso18092"
181+ val fTag = NfcF .get(tag)
182+ manufacturer = fTag.manufacturer.toHexString()
183+ systemCode = fTag.systemCode.toHexString()
184+ tagTechnology = fTag
185+ } else if (tag.techList.contains(NfcV ::class .java.name)) {
186+ standard = " ISO 15693"
187+ type = " iso15693"
188+ val vTag = NfcV .get(tag)
189+ dsfId = vTag.dsfId.toHexString()
190+ tagTechnology = vTag
191+ } else {
192+ type = " unknown"
193+ standard = " unknown"
194+ }
195+
196+ // detect ndef
197+ if (tag.techList.contains(Ndef ::class .java.name)) {
198+ val ndefTag = Ndef .get(tag)
199+ ndefTechnology = ndefTag
200+ ndefAvailable = true
201+ ndefType = ndefTag.type
202+ ndefWritable = ndefTag.isWritable
203+ ndefCanMakeReadOnly = ndefTag.canMakeReadOnly()
204+ ndefCapacity = ndefTag.maxSize
205+ }
206+
207+ val jsonResult = JSONObject (mapOf (
208+ " type" to type,
209+ " id" to id,
210+ " standard" to standard,
211+ " atqa" to atqa,
212+ " sak" to sak,
213+ " historicalBytes" to historicalBytes,
214+ " protocolInfo" to protocolInfo,
215+ " applicationData" to applicationData,
216+ " hiLayerResponse" to hiLayerResponse,
217+ " manufacturer" to manufacturer,
218+ " systemCode" to systemCode,
219+ " dsfId" to dsfId,
220+ " ndefAvailable" to ndefAvailable,
221+ " ndefType" to ndefType,
222+ " ndefWritable" to ndefWritable,
223+ " ndefCanMakeReadOnly" to ndefCanMakeReadOnly,
224+ " ndefCapacity" to ndefCapacity,
225+ ))
226+
227+ if (mifareInfo != null ) {
228+ with (mifareInfo!! ) {
229+ jsonResult.put(" mifareInfo" , JSONObject (mapOf (
230+ " type" to typeStr,
231+ " size" to size,
232+ " blockSize" to blockSize,
233+ " blockCount" to blockCount,
234+ " sectorCount" to sectorCount
235+ )))
236+ }
237+ }
238+
239+ return jsonResult.toString()
240+ }
82241 }
83242
84243 override fun onAttachedToEngine (flutterPluginBinding : FlutterPlugin .FlutterPluginBinding ) {
85244 nfcHandlerThread = HandlerThread (" NfcHandlerThread" )
86245 nfcHandlerThread.start()
87246 nfcHandler = Handler (nfcHandlerThread.looper)
88247
89- val channel = MethodChannel (flutterPluginBinding.binaryMessenger, " flutter_nfc_kit" )
90- channel.setMethodCallHandler(this )
248+ methodChannel = MethodChannel (flutterPluginBinding.binaryMessenger, " flutter_nfc_kit/method" )
249+ methodChannel.setMethodCallHandler(this )
250+
251+ eventChannel = EventChannel (flutterPluginBinding.binaryMessenger, " flutter_nfc_kit/event" )
252+ eventChannel.setStreamHandler(object : EventChannel .StreamHandler {
253+ override fun onListen (arguments : Any? , events : EventChannel .EventSink ? ) {
254+ if (events != null ) {
255+ eventSink = events
256+ }
257+ }
258+
259+ override fun onCancel (arguments : Any? ) {
260+ // No need to do anything here
261+ }
262+ })
91263 }
92264
93265 override fun onDetachedFromEngine (binding : FlutterPlugin .FlutterPluginBinding ) {
266+ methodChannel.setMethodCallHandler(null )
267+ eventChannel.setStreamHandler(null )
94268 nfcHandlerThread.quitSafely()
95269 }
96270
@@ -418,148 +592,8 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
418592 val pollHandler = NfcAdapter .ReaderCallback { tag ->
419593 pollingTimeoutTask?.cancel()
420594
421- // common fields
422- val type: String
423- val id = tag.id.toHexString()
424- val standard: String
425- // ISO 14443 Type A
426- var atqa = " "
427- var sak = " "
428- // ISO 14443 Type B
429- var protocolInfo = " "
430- var applicationData = " "
431- // ISO 7816
432- var historicalBytes = " "
433- var hiLayerResponse = " "
434- // NFC-F / Felica
435- var manufacturer = " "
436- var systemCode = " "
437- // NFC-V
438- var dsfId = " "
439- // NDEF
440- var ndefAvailable = false
441- var ndefWritable = false
442- var ndefCanMakeReadOnly = false
443- var ndefCapacity = 0
444- var ndefType = " "
445-
446- if (tag.techList.contains(NfcA ::class .java.name)) {
447- val aTag = NfcA .get(tag)
448- atqa = aTag.atqa.toHexString()
449- sak = byteArrayOf(aTag.sak.toByte()).toHexString()
450- tagTechnology = aTag
451- when {
452- tag.techList.contains(IsoDep ::class .java.name) -> {
453- standard = " ISO 14443-4 (Type A)"
454- type = " iso7816"
455- val isoDep = IsoDep .get(tag)
456- tagTechnology = isoDep
457- historicalBytes = isoDep.historicalBytes.toHexString()
458- }
459- tag.techList.contains(MifareClassic ::class .java.name) -> {
460- standard = " ISO 14443-3 (Type A)"
461- type = " mifare_classic"
462- with (MifareClassic .get(tag)) {
463- tagTechnology = this
464- mifareInfo = MifareInfo (
465- this .type,
466- size,
467- MifareClassic .BLOCK_SIZE ,
468- blockCount,
469- sectorCount
470- )
471- }
472- }
473- tag.techList.contains(MifareUltralight ::class .java.name) -> {
474- standard = " ISO 14443-3 (Type A)"
475- type = " mifare_ultralight"
476- with (MifareUltralight .get(tag)) {
477- tagTechnology = this
478- mifareInfo = MifareInfo .fromUltralight(this .type)
479- }
480- }
481- else -> {
482- standard = " ISO 14443-3 (Type A)"
483- type = " unknown"
484- }
485- }
486- } else if (tag.techList.contains(NfcB ::class .java.name)) {
487- val bTag = NfcB .get(tag)
488- protocolInfo = bTag.protocolInfo.toHexString()
489- applicationData = bTag.applicationData.toHexString()
490- if (tag.techList.contains(IsoDep ::class .java.name)) {
491- type = " iso7816"
492- standard = " ISO 14443-4 (Type B)"
493- val isoDep = IsoDep .get(tag)
494- tagTechnology = isoDep
495- hiLayerResponse = isoDep.hiLayerResponse.toHexString()
496- } else {
497- type = " unknown"
498- standard = " ISO 14443-3 (Type B)"
499- tagTechnology = bTag
500- }
501- } else if (tag.techList.contains(NfcF ::class .java.name)) {
502- standard = " ISO 18092 (FeliCa)"
503- type = " iso18092"
504- val fTag = NfcF .get(tag)
505- manufacturer = fTag.manufacturer.toHexString()
506- systemCode = fTag.systemCode.toHexString()
507- tagTechnology = fTag
508- } else if (tag.techList.contains(NfcV ::class .java.name)) {
509- standard = " ISO 15693"
510- type = " iso15693"
511- val vTag = NfcV .get(tag)
512- dsfId = vTag.dsfId.toHexString()
513- tagTechnology = vTag
514- } else {
515- type = " unknown"
516- standard = " unknown"
517- }
518-
519- // detect ndef
520- if (tag.techList.contains(Ndef ::class .java.name)) {
521- val ndefTag = Ndef .get(tag)
522- ndefTechnology = ndefTag
523- ndefAvailable = true
524- ndefType = ndefTag.type
525- ndefWritable = ndefTag.isWritable
526- ndefCanMakeReadOnly = ndefTag.canMakeReadOnly()
527- ndefCapacity = ndefTag.maxSize
528- }
529-
530- val jsonResult = JSONObject (mapOf (
531- " type" to type,
532- " id" to id,
533- " standard" to standard,
534- " atqa" to atqa,
535- " sak" to sak,
536- " historicalBytes" to historicalBytes,
537- " protocolInfo" to protocolInfo,
538- " applicationData" to applicationData,
539- " hiLayerResponse" to hiLayerResponse,
540- " manufacturer" to manufacturer,
541- " systemCode" to systemCode,
542- " dsfId" to dsfId,
543- " ndefAvailable" to ndefAvailable,
544- " ndefType" to ndefType,
545- " ndefWritable" to ndefWritable,
546- " ndefCanMakeReadOnly" to ndefCanMakeReadOnly,
547- " ndefCapacity" to ndefCapacity,
548- ))
549-
550- if (mifareInfo != null ) {
551- with (mifareInfo!! ) {
552- jsonResult.put(" mifareInfo" , JSONObject (mapOf (
553- " type" to typeStr,
554- " size" to size,
555- " blockSize" to blockSize,
556- " blockCount" to blockCount,
557- " sectorCount" to sectorCount
558- )))
559- }
560- }
561-
562- result.success(jsonResult.toString())
595+ val jsonResult = parseTag(tag)
596+ result.success(jsonResult)
563597 }
564598
565599 nfcAdapter.enableReaderMode(activity.get(), pollHandler, technologies, null )
0 commit comments