Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update AGP and JAVA Version to make it compatible with Gradle 8.7 and Add support for Streaming #179

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/example-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
java-version: '21'
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
Expand Down
10 changes: 7 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ android {
compileSdkVersion 34

compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = '1.8'
}

sourceSets {
Expand All @@ -39,5 +43,5 @@ android {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$KotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-reflect:$KotlinVersion"
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.core:core-ktx:1.13.1'
}
2 changes: 1 addition & 1 deletion android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
AGPVersion=7.4.2
AGPVersion=8.5.1
KotlinVersion=1.9.23
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import io.flutter.Log
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
Expand All @@ -36,15 +37,17 @@ import kotlin.concurrent.schedule
class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {

companion object {
private val TAG_EVENT_CHANNEL = "tagEventChannel"
private val TAG = FlutterNfcKitPlugin::class.java.name
private var activity: WeakReference<Activity> = WeakReference(null)
private var pollingTimeoutTask: TimerTask? = null
private var tagTechnology: TagTechnology? = null
private var ndefTechnology: Ndef? = null
private var mifareInfo: MifareInfo? = null
var tagTechnology: TagTechnology? = null
var ndefTechnology: Ndef? = null
var mifareInfo: MifareInfo? = null

private lateinit var nfcHandlerThread: HandlerThread
private lateinit var nfcHandler: Handler
private lateinit var tagEventHandler: EventChannel

private fun TagTechnology.transceive(data: ByteArray, timeout: Int?): ByteArray {
if (timeout != null) {
Expand Down Expand Up @@ -88,6 +91,8 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {

val channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_nfc_kit")
channel.setMethodCallHandler(this)

tagEventHandler = EventChannel(flutterPluginBinding.binaryMessenger, TAG_EVENT_CHANNEL)
}

override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
Expand Down Expand Up @@ -385,6 +390,7 @@ class FlutterNfcKitPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = WeakReference(binding.activity)
tagEventHandler.setStreamHandler(TagEventHandler(activity))
}

override fun onDetachedFromActivity() {
Expand Down
199 changes: 199 additions & 0 deletions android/src/main/kotlin/im/nfc/flutter_nfc_kit/TagEventHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package im.nfc.flutter_nfc_kit

import android.app.Activity
import android.nfc.NfcAdapter
import android.nfc.NfcAdapter.getDefaultAdapter
import android.nfc.tech.IsoDep
import android.nfc.tech.MifareClassic
import android.nfc.tech.MifareUltralight
import android.nfc.tech.Ndef
import android.nfc.tech.NfcA
import android.nfc.tech.NfcB
import android.nfc.tech.NfcF
import android.nfc.tech.NfcV
import android.os.Handler
import android.os.Looper
import im.nfc.flutter_nfc_kit.ByteUtils.toHexString
import im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin.Companion.mifareInfo
import im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin.Companion.ndefTechnology
import im.nfc.flutter_nfc_kit.FlutterNfcKitPlugin.Companion.tagTechnology
import io.flutter.plugin.common.EventChannel
import org.json.JSONObject
import java.lang.ref.WeakReference


class TagEventHandler(activity: WeakReference<Activity>) : EventChannel.StreamHandler {
private var _activity: WeakReference<Activity> = activity
private val nfcAdapter: NfcAdapter = getDefaultAdapter(_activity.get())

private val uiThreadHandler: Handler = Handler(Looper.getMainLooper())

override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
val argsMap = arguments as? Map<*, *>
val technologies = argsMap!!["technologies"] as Int

val pollHandler = NfcAdapter.ReaderCallback { tag ->

// common fields
val type: String
val id = tag.id.toHexString()
val standard: String
// ISO 14443 Type A
var atqa = ""
var sak = ""
// ISO 14443 Type B
var protocolInfo = ""
var applicationData = ""
// ISO 7816
var historicalBytes = ""
var hiLayerResponse = ""
// NFC-F / Felica
var manufacturer = ""
var systemCode = ""
// NFC-V
var dsfId = ""
// NDEF
var ndefAvailable = false
var ndefWritable = false
var ndefCanMakeReadOnly = false
var ndefCapacity = 0
var ndefType = ""

if (tag.techList.contains(NfcA::class.java.name)) {
val aTag = NfcA.get(tag)
atqa = aTag.atqa.toHexString()
sak = byteArrayOf(aTag.sak.toByte()).toHexString()
tagTechnology = aTag
when {
tag.techList.contains(IsoDep::class.java.name) -> {
standard = "ISO 14443-4 (Type A)"
type = "iso7816"
val isoDep = IsoDep.get(tag)
tagTechnology = isoDep
historicalBytes = isoDep.historicalBytes.toHexString()
}

tag.techList.contains(MifareClassic::class.java.name) -> {
standard = "ISO 14443-3 (Type A)"
type = "mifare_classic"
with(MifareClassic.get(tag)) {
tagTechnology = this
mifareInfo = MifareInfo(
this.type,
size,
MifareClassic.BLOCK_SIZE,
blockCount,
sectorCount
)
}
}

tag.techList.contains(MifareUltralight::class.java.name) -> {
standard = "ISO 14443-3 (Type A)"
type = "mifare_ultralight"
with(MifareUltralight.get(tag)) {
tagTechnology = this
mifareInfo = MifareInfo.fromUltralight(this.type)
}
}

else -> {
standard = "ISO 14443-3 (Type A)"
type = "unknown"
}
}
} else if (tag.techList.contains(NfcB::class.java.name)) {
val bTag = NfcB.get(tag)
protocolInfo = bTag.protocolInfo.toHexString()
applicationData = bTag.applicationData.toHexString()
if (tag.techList.contains(IsoDep::class.java.name)) {
type = "iso7816"
standard = "ISO 14443-4 (Type B)"
val isoDep = IsoDep.get(tag)
tagTechnology = isoDep
hiLayerResponse = isoDep.hiLayerResponse.toHexString()
} else {
type = "unknown"
standard = "ISO 14443-3 (Type B)"
tagTechnology = bTag
}
} else if (tag.techList.contains(NfcF::class.java.name)) {
standard = "ISO 18092 (FeliCa)"
type = "iso18092"
val fTag = NfcF.get(tag)
manufacturer = fTag.manufacturer.toHexString()
systemCode = fTag.systemCode.toHexString()
tagTechnology = fTag
} else if (tag.techList.contains(NfcV::class.java.name)) {
standard = "ISO 15693"
type = "iso15693"
val vTag = NfcV.get(tag)
dsfId = vTag.dsfId.toHexString()
tagTechnology = vTag
} else {
type = "unknown"
standard = "unknown"
}

// detect ndef
if (tag.techList.contains(Ndef::class.java.name)) {
val ndefTag = Ndef.get(tag)
ndefTechnology = ndefTag
ndefAvailable = true
ndefType = ndefTag.type
ndefWritable = ndefTag.isWritable
ndefCanMakeReadOnly = ndefTag.canMakeReadOnly()
ndefCapacity = ndefTag.maxSize
}

val jsonResult = JSONObject(
mapOf(
"type" to type,
"id" to id,
"standard" to standard,
"atqa" to atqa,
"sak" to sak,
"historicalBytes" to historicalBytes,
"protocolInfo" to protocolInfo,
"applicationData" to applicationData,
"hiLayerResponse" to hiLayerResponse,
"manufacturer" to manufacturer,
"systemCode" to systemCode,
"dsfId" to dsfId,
"ndefAvailable" to ndefAvailable,
"ndefType" to ndefType,
"ndefWritable" to ndefWritable,
"ndefCanMakeReadOnly" to ndefCanMakeReadOnly,
"ndefCapacity" to ndefCapacity,
)
)

if (mifareInfo != null) {
with(mifareInfo!!) {
jsonResult.put(
"mifareInfo", JSONObject(
mapOf(
"type" to typeStr,
"size" to size,
"blockSize" to blockSize,
"blockCount" to blockCount,
"sectorCount" to sectorCount
)
)
)
}
}

uiThreadHandler.post {
events?.success(jsonResult.toString())
}
}

nfcAdapter.enableReaderMode(_activity.get(), pollHandler, technologies, null)
}

override fun onCancel(p0: Any?) {
nfcAdapter.disableReaderMode(_activity.get())
}

}
4 changes: 2 additions & 2 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ android {
compileSdkVersion 34

compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility JavaVersion.VERSION_1_8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't downgrade this again, as it will cause breakage downstream.
See: #127 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll give an update soon. Problem is I'm getting issue like Java Version 21 and Kotlin Version 17. I tried fixing it but the error didn't compile. Maybe I need to clean everything and try again.

Copy link
Contributor Author

@luckycreationsindia luckycreationsindia Jul 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the version back to 17 and it's working but automated checks are failing. I can build the app without issues but here Github Actions are failing without proper error.

targetCompatibility JavaVersion.VERSION_1_8
}

sourceSets {
Expand Down
2 changes: 1 addition & 1 deletion example/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
AGPVersion=7.4.2
AGPVersion=8.5.1
KotlinVersion=1.9.23
59 changes: 59 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
String? _result, _writeResult, _mifareResult;
late TabController _tabController;
List<ndef.NDEFRecord>? _records;
Stream<NFCTag>? _stream;
StreamSubscription<NFCTag>? _streamSubscription;

@override
void dispose() {
Expand Down Expand Up @@ -147,6 +149,63 @@ class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
child: Text('Start polling'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
try {
if(_stream != null) {
_streamSubscription?.cancel();
setState(() {
_stream = null;
});
return;
}
setState(() {
_stream = FlutterNfcKit.tags();
});
_streamSubscription = _stream!.listen((tag) {
_tag = tag;
_mifareResult = null;
if (tag.standard == "ISO 14443-4 (Type B)") {
FlutterNfcKit.transceive("00B0950000").then((result1) {
FlutterNfcKit.transceive(
"00A4040009A00000000386980701").then((result2) {
setState(() {
_result = '1: $result1\n2: $result2\n';
});
});
});
} else if (tag.type == NFCTagType.iso18092) {
FlutterNfcKit.transceive("060080080100").then((result1) {
setState(() {
_result = '1: $result1\n';
});
});
} else if (tag.ndefAvailable ?? false) {
FlutterNfcKit.readNDEFRecords().then((ndefRecords) {
var ndefString = '';
for (int i = 0; i < ndefRecords.length; i++) {
ndefString += '${i + 1}: ${ndefRecords[i]}\n';
}
setState(() {
_result = ndefString;
});
});
} else if (tag.type == NFCTagType.webusb) {
FlutterNfcKit.transceive(
"00A4040006D27600012401").then((r) {
print(r);
});
}
});
} catch (e) {
setState(() {
_result = 'error: $e';
});
}
},
child: Text(_stream != null ? 'Stop Streaming' : 'Start Streaming'),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: _tag != null
Expand Down
Loading
Loading