flutter-nfc-manager
flutter-nfc-manager copied to clipboard
iOS Channel sent a message from native to Flutter on a non-platform thread
Hi,
I have noticed there is a log line the first time I try to scan a tag in an IOS device.
[VERBOSE-2:shell.cc(1004)] The 'plugins.flutter.io/nfc_manager' channel sent a message from native to Flutter on a non-platform thread. Platform channel messages must be sent on the platform thread. Failure to do so may result in data loss or crashes, and must be fixed in the plugin or application code creating that channel. See https://docs.flutter.dev/platform-integration/platform-channels#channels-and-platform-threading for more information.
This looks like something that should be addressed to avoid app crashes?
Here is a self-contained example. I made it stateful to make sure I was not leaving a session open. The first time the NFC library is used after start will show the line above in the debug console.
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:nfc_manager/nfc_manager.dart';
class GetNFC extends StatefulWidget {
const GetNFC({super.key});
@override
State<StatefulWidget> createState() {
return GetNFCState();
}
}
class GetNFCState extends State<GetNFC> {
bool sessionOpen = false;
bool success = false;
String? value;
@override
void dispose() {
if (sessionOpen) {
NfcManager.instance.stopSession();
}
super.dispose();
}
String logNFCError(var error) {
String logLine =
'NFC Error: message ${error.message} type ${error.type} detrails ${error.details}';
log(logLine);
return logLine;
}
@override
Widget build(BuildContext context) {
if (value != null) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(value!),
ElevatedButton(
onPressed: () {
setState(() {
value = null;
sessionOpen = false;
success = false;
});
},
child: const Text('Restart'))
],
);
}
return FutureBuilder<bool>(
future: NfcManager.instance.isAvailable(),
builder: (context, nfcAvailableSnapShot) {
if (nfcAvailableSnapShot.hasData) {
if (nfcAvailableSnapShot.data == true) {
sessionOpen = false;
NfcManager.instance.startSession(
alertMessage: 'Scan the card now',
onDiscovered: (NfcTag tag) async {
try {
sessionOpen = true;
try {
Ndef? ndef = Ndef.from(tag);
final cachedMessage = ndef!.cachedMessage;
NdefRecord? record = cachedMessage!.records
.where((e) =>
e.typeNameFormat == NdefTypeNameFormat.nfcWellknown)
.firstOrNull;
if (record != null) {
final languageCodeLength = record.payload.first;
final textBytes =
record.payload.sublist(1 + languageCodeLength);
success = true;
NfcManager.instance.stopSession();
sessionOpen = false;
setState(() {
value = ascii.decode(textBytes);
});
}
} catch (e) {
if (sessionOpen) {
NfcManager.instance.stopSession();
}
setState(() {
value = logNFCError(e);
});
}
} catch (e) {
if (sessionOpen) {
NfcManager.instance.stopSession();
}
setState(() {
value = logNFCError(e);
});
}
},
onError: (error) async {
if (success) return;
if (sessionOpen) {
NfcManager.instance.stopSession();
}
setState(() {
value = logNFCError(error);
});
},
);
}
return const Text('Please tap the card on your phone');
} else {
return const CircularProgressIndicator();
}
},
);
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
static GlobalKey mtAppKey = GlobalKey();
@override
Widget build(BuildContext context) {
return MaterialApp(
key: MyApp.mtAppKey,
title: 'NfcTestApp',
theme: ThemeData(
useMaterial3: true,
),
home: const Scaffold(body: Center(child: GetNFC())));
}
}
Here is the output of my flutter --version:
Flutter 3.13.8 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 6c4930c4ac (6 days ago) • 2023-10-18 10:57:55 -0500
Engine • revision 767d8c75e8
Tools • Dart 3.1.4 • DevTools 2.25.0
Also, I can't say for certain this is related, but also sometimes I see the following messages show up in the debug logs, and some time after that I see an NfcErrorType.unknown after a second or so.
[CoreNFC] -[NFCHardwareManager queueReaderSession:sessionConfig:completionHandler:]:105 error=Error Domain=NFCError Code=203 "System resource unavailable"
[CoreNFC] -[NFCTagReaderSession beginSessionWithConfig:]:458 error:Error Domain=NFCError Code=203 "System resource unavailable" UserInfo={NSLocalizedDescription=System resource unavailable}, errorCode: 0xcb
I could not reproduce the previous two log entries reliably with the example (only the log line about the "non-related platform channel"), but if anyone has any pointers for me I would appreciate it.
Just wanted to provide an update. After using the profiling from XCode I noticed that in the case of my app I have Thermal State: serious after a while. So most likely the errors at the bottom are due to some performance error I have in my code.
That being said, the error about the non-platform thread is not related to my app and I expect it to be reproducible with any iOS device.
i have created a pull request to fix this problem.
i have created a pull request to fix this problem.
Hello, i am new on flutter. how can i use the plugin via github with your commit. I was adding the plugin to my project with pub.dev? Can you help how can i add the plugin ?
@okadan has merged it into the repository.
As long as @okadan has not published it to pub.dev, you can put the github project directly as dependency. Go to your pubspec.yaml and in dependencies you add:
flutter-nfc-manager:
git:
url: https://github.com/okadan/flutter-nfc-manager
branch: master
instead of
flutter-nfc-manager: ^3.3.0
Please double check the correct tab in the yaml-file in case you copy&paste it. I could only do it with whitespaces here. So better not copy&paste.
@okadan has merged it into the repository.
As long as @okadan has not published it to pub.dev, you can put the github project directly as dependency. Go to your pubspec.yaml and in dependencies you add:
flutter-nfc-manager: git: url: https://github.com/okadan/flutter-nfc-manager branch: masterinstead of
flutter-nfc-manager: ^3.3.0Please double check the correct tab in the yaml-file in case you copy&paste it. I could only do it with whitespaces here. So better not copy&paste.
Thank you for your quick response. #113 can you look at also this problem ?
Thank you for your quick response. #113 can you look at also this problem ?
as it is written in the documentation, this plugin requires iOS 13+ to function. So it won't work with iOS12 and iPhones 4-6. I think later models have been provided with iOS13+.
Thank you for your quick response. #113 can you look at also this problem ?
as it is written in the documentation, this plugin requires iOS 13+ to function. So it won't work with iOS12 and iPhones 4-6. I think later models have been provided with iOS13+.
So, can i ignore this framework for these devices? So, nfc is only one part of my project. So if the device which is before iOS13, it will not need nfc. Can i make something like that ?, I need this because i cant launch the app on iOS12 :/
Best way is to make your App available for Devices with iOS13+ only. The only way to "ignore" a framework on iOS12 is this:
In this case you can exclude it, but you will have to ensure that you are not calling the Package in your Dart Code on Devices below iOS13. As you are a beginner, i do not recommend to do this.