Skip to content

Commit 1824bad

Browse files
committed
add event support
1 parent ddea80c commit 1824bad

File tree

5 files changed

+226
-146
lines changed

5 files changed

+226
-146
lines changed

android/src/main/kotlin/im/nfc/flutter_nfc_kit/FlutterNfcKitPlugin.kt

+178-144
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.nfc.NdefMessage
66
import android.nfc.NdefRecord
77
import android.nfc.NfcAdapter
88
import android.nfc.NfcAdapter.*
9+
import android.nfc.Tag
910
import android.nfc.tech.*
1011
import android.os.Handler
1112
import android.os.HandlerThread
@@ -24,6 +25,9 @@ import io.flutter.plugin.common.MethodCall
2425
import io.flutter.plugin.common.MethodChannel
2526
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
2627
import 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
2731
import org.json.JSONArray
2832
import org.json.JSONObject
2933
import 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)

example/android/app/src/main/AndroidManifest.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
android:name="${applicationName}"
66
android:icon="@mipmap/ic_launcher">
77
<activity
8-
android:name="io.flutter.embedding.android.FlutterActivity"
8+
android:name=".MainActivity"
99
android:exported="true"
1010
android:launchMode="singleTop"
1111
android:theme="@style/LaunchTheme"

0 commit comments

Comments
 (0)