NFC Detection doesn't work using NfcManager in Flutter/Dart - flutter

first time posting here. Am quite new to flutter.
Currently making an app that uses NFC to allow user login, however I'm unable to show the data of the NFC/print it out so I can use it. I want to be able to print out the code on it that is '0248FCF2255E81', but I can only get the metadata and it doesn't seem to be inside that.
RaisedButton(
onPressed: () async {
bool isAvailable =
await NfcManager.instance.isAvailable();
// Start Session
if (isAvailable) {
NfcManager.instance.startSession(
onDiscovered: (NfcTag tag) async {
Ndef ndef1 = Ndef.from(tag);
if (ndef1 == null) {
print('Tag is not compatible with NDEF');
return;
} else {
print(await ndef1.read());
}
},
);
} else {
print("NFC Manager is not available");
}
},
child: Text('Open NFC Manager'),
color: Colors.green[300],
),
When I click the button, it opens the NfcManager, and I should be able to get the data from the NFC tag. However, when I hover my phone over the NFC Tag, I get this error
NoSuchMethodError (NoSuchMethodError: The method 'forEach' was called on null. Receiver: null Tried calling: forEach(Closure: (dynamic, dynamic) => Null))
I tried other packages like nfc_in_flutter, but that didn't work for me when trying to fork their project
I also tried flutter_nfc_reader, which did give me the metadata of the NFC tag, but not the data I wanted.
Same thing with nfc_manager, when I hover over the tag after the error pops up, I can see the metadata of the NFC tag as well, but not see the string I wanted to see.
Hope I can find some help here, thanks!
edit: The package I'm using is https://pub.dev/packages/nfc_manager

tried nfc_in_flutter again and it worked, using
NDEFMessage message = await NFC.readNDEF(once: true).first;
print("payload: ${message.tag.id}");

Related

problem with launching whatsapp to send a message with flutter url_launcher

this is the function to send an WhatsApp message (or just launch the WhatsApp with the message)
in the Cipher.dart
void sendCodeByWhatsApp(
String phone,
String message,
) async {
String url() {
if (Platform.isAndroid) {
return "https://wa.me/$phone/?text=$message";
} else {
return "https://api.whatsapp.com/send?phone=$phone=$message";
}
}
if (await canLaunchUrl(Uri.parse(url()))) {
await launchUrl(Uri.parse(url()));
} else {
throw 'Could not launch ${url()}';
}
}
and here I use it:
ElevatedButton(
child: const Icon(Icons.whatsapp, color: Colors.white,),
onPressed: (){
Cipher().sendCodeByWhatsApp(encrypt.encrypt, phone.text);
},
),
when adding a number and message, just open a page with WhatsApp logo, tells me:
we couldn't find the page you were looking for
Refer to this to get how to use the link properly link
There may also be an error if the number includes the country code like
+1 0123456789
Will give an error. The phone should not include the country code.
after doing some search, finally found the solution:
same code above, but the URL should be like this:
"whatsapp://send?phone=$phone&text=${Uri.parse(message)}";
for android, and it is working like a charm...
Change the ? to & and it will open the WhatsApp page in the browser for you
"https://wa.me/$phone/&text=$message";

Basic QR code scanner in flutter + qr_code_scanner returning results repeated

I am building a QR scanner to help organize a collection. Basic data about the items is encoded into a json string then into a QR code. The generation of such labels programatically was successful. The next phase was to create a simple visor in flutter. The chosen library was qr_code_scanner. My simple app was to be a scanner which when detecting a valid QR code (one containing a json string describing the required structures) would redirect into another screen where data was displayed. The scanner detects the QR codes, the objects are parsed and a widget containing another scaffold is pushed. This is mostly what I want however an issue was detected: when a valid QR was detected the app would push the data display screen multiple times, sometimes as many as 9, thus breaking backward navigation.
The method responsible of handling the event is named "onQRViewCreated" (like in the example).
void onQRViewCreated(QRViewController controller){
setState(() => this.controller = controller);
controller.scannedDataStream.listen(
(qrData) {
setState(
() {
barcode = qrData;
if (barcode?.format == BarcodeFormat.qrcode) {
try {
Item item = Item.fromJSon(
jsonDecode(barcode?.code ?? "")
);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ItemDisplay(
key: const Key("item"),
item: item
)
)
);
}
on FormatException {
Fluttertoast.showToast(msg: "Invalid QR Code!");
}
on Exception {
Fluttertoast.showToast(msg: "Error!");
}
}
}
);
}
);
}
I would like to be able to push the ItemDisplay only once but I don't know how to do it.
Thank you in advance
Put await controller.pauseCamera(); before the Navigator.push
I would suggest to use mobile_scanner package, which is a newer version from the same author. When creating MobileScanner widget of this package, there is an option allowDuplicates, which you can set to false to avoid this behaviour.

flutter_reactive_ble - how to check if device is connected before subscribing

I'm using this plugin to try to develop an app that uses a Bluetooth module.
GitHub https://github.com/PhilipsHue/flutter_reactive_ble/
I'm trying to modify what the example included in the source code, so that onTap of the list of devices, would connect and subscribeToCharacteristic.
but, it seems that the connectToDevice() method is declared as a stream,
and putting "await" before the method call won't really fit my criteria (on a device connected, then subscribeToCharacteristic)
how do I achieve this?
what I currently have in device_list.dart
(device) => ListTile(
title: Text(device.name),
subtitle: Text("${device.id}\nRSSI: ${device.rssi}"),
leading: const BluetoothIcon(),
onTap: () async {
widget.stopScan();
await widget.deviceConn.connect(device.id);
//call to subscribeToCharacteristic(characteristic);
});
await only works in case the method returns a future. You should listen to the stream and when the stream emits a the connected state you execute the subscribe call. For example:
_ble.connectToDevice(id: deviceId).listen(
(update) {
if(update.connectionState == DeviceConnectionState.connected){
// execute subscribe
}
},

Firebase Cloud Messaging onLaunch callback

My app structure is a little bit mess, but I have to add this patch first and then I'll restructure the entire logic. The thing is I first check if there's a firebase user, then if there is one I use StreamBuilder to get the current user profile from Firestore, then I have the _firebaseMessaging.configure method because onLaunch and onResume I use this callback:
void _navigateToGestorResevas(Map<String, dynamic> message, User currentUser) {
Navigator.push(context,
MaterialPageRoute(builder: (context) =>
GestorScreen(user: currentUser)));
}
Because I need to send the User to this screen where he fetch the message from firebase.
onResume this works fine, but onLaunch it goes to the screen and fetch the data but there are like 20 seconds where there are some kind of glitch. It switch like 20-30 times between two states where I have and no have snapshot data in this _initState func:
final snapshot = await _dbRef.child('mensajes').child(widget.user.id).once();
if (snapshot.value != null) {
setState(() {
hayMensajes = true;
});
final data = snapshot.value;
for (var entry in data.entries) {
Message message = Message.fromJson(entry.value);
setState(() {
message.add(message);
});
}
} else {
setState(() {
hayMensajes = false;
});
}
Anyone have an idea what am I doing wrong?
If I am not mistaken, there are some active issues about FCM onLaunch callback with flutter. Some of them are still not fixed. One of the problems most people had to face was that onLaunch callback being called multiple times. I don't know why it happened, but as in your case, you can possibly get rid of the issue by some temporary fixes.
If the same screen is getting pushed over and over again, and glitching, you can pop the stack until it reaches the one you meant to open and set a condition to push navigator only if the new route is different from the old one. Using the named routes,
Navigator.popUntil(context, ModalRoute.withName(routeName));
if (ModalRoute.of(context).settings.name != routeName) {
Navigator.pushNamed(context, routeName);
}
I am not sure if that was the problem you asked, but I hope at least my answer helps somehow.

Is there a way to scan barcodes in Flutter?

Basically, I'm making an app that scans a QR code to connect to a server. Then, the app will scan the barcode of products and take pictures of the item and send them to the server. My question is the following :
Is there a Flutter plugin to scan QR codes and barcodes that doesn't enter in conflict with image_picker?
Here's what I found so far.
barcode_scan. Works well until you add a dependency on camera or image_picker. Issue.
BarcodeScannerPlugin
. An issue is open, which have the same problem as the previous plugin.
flutter_qrcode_reader, deprecated. Apparently, it doesn't build.
flutterZebraEmdk is an empty project without a README.md.
flutter_qr_mobile_vision, doesn't support barcodes. Issue.
I appreciate any help you can provide. Thanks!
Update
The issue with barcode_scan was resolved. I ended up using this one since it's faster than the accepted answer and its issues got resolved rather quickly. Be aware that its behaviour on iOS is modified by Apple, so you might get different results with checksum numbers or something.
I've previously had a similar problem, and after searching as you did I didn't find a whole lot. I decided that the best approach would be to write a plugin myself... so shameless plug for my plugin here =D, not that I benefit from anyone else using it at all.
You can see it here. However, I haven't had time to document it, test it all that extensively, or publish it properly on Pub. So your mileage may vary. It should however work on android 4.4+ (and maybe below), and iOS devices that flutter supports. I also haven't tested it in conjunction with the Camera plugin but I don't see why it would have a problem with it.
It takes a different approach than most of the other qr code plugins; instead of making an android or iOS window, doing the scan, then returning to flutter, it uses flutter's texture rendering capabilities to have the camera render directly into flutter.
A few more things to consider are that it uses the Google Mobile Vision SDK with the applicable licensing and capabilities that comes along with that (and requires a recent version of Play Services on Android); and that it currently only supports the most basic extraction of information from barcode scans - I only needed the raw text out so that's all I did.
To use it, add this to your pubspec.yaml:
dependencies:
qr_mobile_vision: '^0.0.7'
And implement as follows:
import 'package:qr_mobile_vision/QrCamera.dart';
...
new Container(
constraints: new BoxConstraints.loose(
new Size(cameraSize, cameraSize)),
child: new QrCamera(
qrCodeCallback: (code) {
print(code);
}
),
)
I do plan on finishing documentation/testing/etc eventually, but you're welcome to try it out in the meantime. If you decide to use it and need a feature it doesn't support I may be able to help implement it... but PRs are welcome and encouraged!
UPDATE: this does include Barcode support now. You can pass in which types of QR code / Barcode you want to support when you instantiate QrCamera. It defaults to all, which takes more processing so if you're after a certain type it's recommended that you pass it in.
I'm working on something currently as a companion to my QR generation plugin (https://github.com/lukef/qr.flutter) but I don't have a specific timeline, unfortunately.
My plan is to use the Texture object and hookup a camera (or fork / use the camera plugin) and then use the Google Vision API (https://developers.google.com/vision/android/barcodes-overview).
It should be decently trivial, I just need to find the time. Either way, that was the plan if you want to do it :)
You can use an open source SDK (e.g., ZXing) or a commercial SDK (e.g., Dynamsoft Barcode Reader SDK) in your Flutter project. Implementing the barcode scanning function is easy.
I have written an article - Flutter Programming with Android AAR File, sharing how to scan QR code in a flutter project. The source code is also available on GitHub.
Java code
private String onGetBarcode(String json) {
String filename;
try {
JSONObject message = new JSONObject(json);
filename = message.getString("filename");
} catch (JSONException e) {
Log.e(TAG, "JSON exception", e);
return null;
}
String locationProvider;
String barcodeResult = "No barcode detected";
File file = new File(filename);
if (!file.exists()) {
barcodeResult = "No file exists: " + file.toString();
Toast.makeText(BarcodeReaderActivity.this, barcodeResult, Toast.LENGTH_LONG).show();
return null;
}
else {
Bitmap bitmap = BitmapFactory.decodeFile(file.toString());
BarcodeReader reader = new BarcodeReader("license");
ReadResult result = reader.readSingle(bitmap, Barcode.QR_CODE);
Barcode[] all = result.barcodes;
if (all != null && all.length == 1) {
barcodeResult = all[0].displayValue;
}
else {
barcodeResult = "no barcode found: " + file.toString();
}
bitmap.recycle();
}
JSONObject reply = new JSONObject();
try {
if (barcodeResult != null) {
reply.put("result", barcodeResult);
} else {
reply.put("result", "No barcode detected");
}
} catch (JSONException e) {
Log.e(TAG, "JSON exception", e);
return null;
}
return reply.toString();
}
Dart code
#override
Widget build(BuildContext context) {
if (_isExisted) {
return new Material(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Text('Barcode Reader'),
new Input(
labelText: 'Please input the image path',
value: new InputValue(text: _filename),
onChanged: onTextChanged,
autofocus: true,
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new RaisedButton(
child: new Text('Read'),
onPressed: _getBarcode
),
new RaisedButton(
child: new Text('Reset'),
onPressed: _resetResult
),
]
),
new Image.file(new File(_filename)),
new Text('$_result'),
]
)
)
);
}
else {
return new Material(
child: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Text('Barcode Reader'),
new Input(
labelText: 'Please input the image path',
onChanged: onTextChanged,
autofocus: true,
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new RaisedButton(
child: new Text('Read'),
onPressed: _getBarcode
),
new RaisedButton(
child: new Text('Reset'),
onPressed: _resetResult
),
]
),
new Text('$_result'),
]
)
)
);
}
}
Future<Null> _readBarcode() async {
final Map<String, String> message = <String, String>{'filename':_filename};
final Map<String, dynamic> reply = await HostMessages.sendJSON('getBarcode', message);
// If the widget was removed from the tree while the message was in flight,
// we want to discard the reply rather than calling setState to update our
// non-existent appearance.
if (!mounted)
return;
setState(() {
_result = reply['result'].toString();
});
}
Screenshot
So take a little bit of time and do it yourself :)
I used qr_scan. The issue was I created my flutter with objective c. I had to delete iOS and change it.
To do that delete the ios folder from the project and create it with swift.
To create use is command flutter create -i swift . dont forget the . in the end cause it took me a couple of hours to figure that out
According with my researchs there are good options for that:
flutter_barcode_scanner (reader)
barcode_scan (reader)
qr_flutter (thats is for create QR codes)
1st: barcode_scan will works as a wrapper for two commonly used iOS and Android libraries.
(iOS: https://github.com/mikebuss/MTBBarcodeScanner, Android: https://github.com/dm77/barcodescanner)
They are in version 3 already and seems like the all the major bugs were resolved.
dependencies:
barcode_scan: ^3.0.1
Here the feature list:
[x] Scan 2D barcodes
[x] Scan QR codes
[x] Control the flash while scanning
[x] Permission handling
The main warn is about https://github.com/dm77/barcodescanner that's no longer maintained.
The 2nd option is flutter_barcode_scanner thats also works for both android and ios.
https://pub.dev/packages/flutter_barcode_scanner
For android is just put the pubdev dependency and play, for iOS the only things you need to do is: 1: set minimum deployment target to 11, 2: set Swift version to 5 and 3: ask the permission to use the camera. May the flutter-bardode-scanner is best option since it will depends on just a pubdev dependency without the need of 3rd party project (no longer maintained).
When it's needed to create QR code there is: QR.Flutter also works for ios and android.
Features:
[x] Built on QR - Dart
[x] Automatic QR code version/type detection or manual entry
[x] Supports QR code versions 1 - 40
[x] Error correction / redundancy
[x] Configurable output size, padding, background and foreground colors
[x] Supports image overlays
[x] Export to image data to save to file or use in memory
[x] No internet connection required
Both of them have the best reputation on pub.dev for this propose. So may you need to give a try and check which of them will fill your project needs.
Updating the answer: To read barcode from image gallery there is an alternative package called qr_code_tools. The image could be get from ImagePicker and then decoded to data through QrCodeToolsPlugin.decodeFrom
Getting the image from galley:
ImagePicker.pickImage(source: ImageSource.gallery));
Decoding the image to data:
import 'package:qr_code_tools/qr_code_tools.dart';
String _data;
Future decode(String file) async {
String data = await QrCodeToolsPlugin.decodeFrom(file);
setState(() {
_data = data;
});
}