Problem with decoding JSON data from Pusher API in flutter - flutter

I am using Pusher API as real time database.
I can successfully connected and getting data in JSON format.
Problem: I couldn't decode it. I am using jsonDecode(); but that's not working as follow. Here is the screenshot of my code.
Anyone have solution? Any other way to decode it?
Future<void> _initPusher() async{
PusherClient pusher;
Channel channel;
pusher = new PusherClient(
"adb844af65547f4a67cf",
PusherOptions(
cluster: "mt1",
),
enableLogging: true,
);
channel = pusher.subscribe("my-channel-chat");
pusher.onConnectionError((error) {
print("error: ${error!.message}");
});
channel.bind('my-event-chat', (event) {
// print(event!.data.toString());
final data = jsonDecode(event!.data.toString());
print (data);
});
}

You will need to put a comma at the end of the line to make it valid JSON. Currently it is:
{
"sender":"you"
"message":"Something to say"
"time":"00.00"
}
Try with
{
"sender":"you",
"message":"Something to say",
"time":"00.00"
}
You can use services such as https://jsonlint.com/ to check whether your JSON is valid.

Related

Firebase Functions logs working, but Flutter returns null

I'm trying to display Firestore data in a Flutter app. To do that, I created a Firebase function like the following:
exports.getHouses = functions.https.onCall((data, context) => {
let pathBeginning = "users/";
console.log(data.userID);
let path = pathBeginning.concat(data.userID, "/houses");
let houses = [];
admin.firestore().collection(path).get().then(snapshot => {
console.log("COLECTION WHERE DOCUMENTS ARE RETREIVED:");
console.log(path);
snapshot.forEach(doc => {
let newHouse = {
"id": doc.id,
"address": doc.data().address
}
houses = houses.concat(newHouse);
});
console.log("THE FOLLOWING LOG SHOULD RETURN THE FULL LIST OF HOUSES:")
console.log(houses);
return houses;
}).catch(reason => {
response.send(reason);
});
});
I think this part works properly, because logs in Firebase look exactly as expected:
Firebase logs
The problem happens when I try to print this data in my Flutter app. To do so, I use the following code:
Future<void> listHouses() async {
var parameters = {
"userID": "1"
};
HttpsCallable getHouses = FirebaseFunctions.instance.httpsCallable("getHouses");
await getHouses.call(parameters).then((HttpsCallableResult response) {
print(response.data);
});
}
When called the funtion, it always returns null, even when Firebase log displays everything properly.
I would appreciate if anyone can help me solving this issue. Thank you in advance.
You're missing a return in front of your get() call. Without that, the Cloud Functions container doesn't know about the asynchronous get() operation and thus will/may terminate the function before loading the data completes.
To fix this, add return:
return admin.firestore().collection(path).get().then(snapshot => {
...
This is an extremely common problem within Cloud Functions and when dealing with asynchronous APIs in general, so I recommend taking a moment to read the Firebase documentation on terminating functions and watching the video series linked in there.

How to use Flutter Reactive BLE to send a UUID to a Bluetooth device and save response to string

I have been trying to figure out the Flutter Reactive BLE dart library. I have went through the Github example app and got when I want to work. I am wondering if there is an easier way to do what I am doing.
I have tried messing around with the readCharacterisitc but I have had no luck. I don't think I am connecting to the device properly.
final characteristic = QualifiedCharacteristic(serviceId: serviceUuid, characteristicId: characteristicUuid, deviceId: foundDeviceId);
final response = await flutterReactiveBle.readCharacteristic(characteristic);
The goal would be to have all relevant functions and variables to connect to the BLE device in one file so all I have to do is 1 line and get my response for my different UUIDs.
I am also very new to flutter and dart so if I am going about this wrong please let me know.
You will need to know the service UUIDs and characteristic UUIDs of that device.
First perform a scan and save the device id.
String? deviceId;
final flutterReactiveBle = FlutterReactiveBle();
flutterReactiveBle.scanForDevices(withServices: [serviceId], scanMode: ScanMode.lowLatency).listen((device) {
//save the device id to a variable
deviceId = device.id;
}, onError: () {
//code for handling error
});
Then use this device id to connect to that device.
You need to know the service ids and characteristic ids of that device.
flutterReactiveBle.connectToDevice(
id: deviceId,
servicesWithCharacteristicsToDiscover: {serviceId: [charId1, charId2]},
connectionTimeout: const Duration(seconds: 2),
).listen((connectionState) {
if (connectionState.connectionState == DeviceConnectionState.connected) {
// send the data
final characteristic = QualifiedCharacteristic(serviceId: serviceUuid,
characteristicId: charId1, deviceId: deviceId);
var response = await flutterReactiveBle.writeCharacteristicWithResponse(characteristic, value: [0x00]);
}
}, onError: (Object error) {
// Handle a possible error
});
Please note that in many cases, you will get the response on another characteristic UUID. So you will have to listen to that characteristic UUID to get the response.

image picker path for stripe readfilesync Flutter Web

I'm using the file_picker package for flutter https://pub.dev/packages/file_picker
I have read many times that because you can’t access paths on web browsers, you need to use the bytes property, e.g.
FilePickerResult result = await FilePicker.platform.pickFiles();
if(result != null) {
var path = print(result.files.single.path); // this will return null
var bytes = print(result.files.singe.bytes); // this will return a Uint8List of bytes
} else {
// User canceled the picker
}
But I have to upload the images my users select from their devices via the web (so for all types of devices) to my Stripe Connect API in order for them to have a validated identity_document when they register. The bytes Uint8List will throw an error from firebase, here is my code:
export const uploadIdentityFront = async (uid: any, identityFront: any) => {
const fp = fs.readFileSync(identityFront);
const frontIdentity = await stripe.files.create({
file: {
data: fp,
name: 'identityFront.jpg',
type: 'application/octet-stream',
},
purpose: 'identity_document',
});
await updateId(uid, { frontIdentityFileId: frontIdentity.id })
return frontIdentity;
}
The error thrown:
[firebase_functions/unknown] TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Array
I will need to send stripe an image document via the file system's readFileSync property in order to do this, but with Flutter Web not being able to print the path for the image chosen by the user, I am stuck on how to resolve this issue
I use this code to send bytes to my server, which uses stream to send. You can use http package to send streams.
var request = http.MultipartRequest(
'POST',
Uri.parse('_url'),
);
request.files.add(
http.MultipartFile.fromBytes(
'identityFront', //name of field which you receive in api
bytes, // bytes
filename: 'identityFront.jpg', // optional name
//contentType: content, optional media Type
));
request.fields.addEntries([
MapEntry('uid', 'uid_value_in_String_Type'),
]);
await request.send();
I finally solved it. For anyone trying to upload a file to Stripe via flutter web, don't create a fs.readFileSync in your backend server side code. Instead, remove it and upload a file like this:
export const uploadIdentityFront = async (uid: any, identityFront: any) => {
const frontIdentity = await stripe.files.create({
file: {
data: identityFront,
name: 'identityFront.jpg',
type: 'image/jpg',
},
purpose: 'identity_document',
});
await updateId(uid, { frontIdentityFileId: frontIdentity.id })
return frontIdentity;
}
This way, you can upload the file via the file_picker package and uploading it as a picker.file.first.bytes. But don't wrap it in a string - send it just like this as a callable function in firebase functions:
await uploadFrontPassport.call(
<dynamic, dynamic>{'identityFront':picked.files.first.bytes}
);

How to use List data returned from an API call

Im attempting to get back a list of data from an API call and send this list of data to a local sqlite database I've created for it. I'm getting an issue with the data being a type <List> and I'm not sure how to convert it to something usable. I'm just trying to assign that data from the api call to a variable so I can just simply send it to the sqlite database. Any advice is welcome! Thanks!
This is the code where I'm attempting to get that data from the API call and send it to the sqlite database.
if(user.success) {
Quarter quarters;
quarters = await getQuarters();
QuarterDBProvider.quarterDB.newQuarter(quarters);
}
This is where the API call is performed
Map data;
List<Quarter> quarterFromJson(String str) =>
List<Quarter>.from(json.decode(str).map((x) => Quarter.fromJson(x)));
Future<List<Quarter>> getQuarters() async {
final http.Response response = await http.get(
'https://myfakeapi/quarters',
);
if (response.statusCode < 400) {
return quarterFromJson(response.body);
} else {
throw Exception('Failed to get quarters');
}
}
the response from api is list and it is not String.
List<Quarter> _listQuarter= [];
var json = jsonDecode(response.body) as List<dynamic>;
json.forEach((element) {
_listQuarter.add( -do all your workaround- );
});
return _listQuarter;

How to parse an object variable in eventChannel callback method?

I am programming a flutter app, in which I have a callback from the native system containing some nfc information. I register the callback via the following line of code:
eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
The callback looks like this:
void _onEvent(Object event) {
//Receive Event
print("NFC Event received");
//Get the Payload
event['Payload']; //This does not work, it gives an error
}
But how can I parse out the data? I know it contains a field by the name Payload however, I cannot access it via event['Payload'].
I am very confused, I tried to cast it to another type like this: Map<String, String> eventMap = Map<String, String>.from(event); but that didnt work. Could someone please point out what I am doing wrong and how I can correctly extract the data?
Without too much information of native part, I suggest
you can reference this package or fork this https://github.com/akeblom/flutter-nfc-reader
directly
this repo fix some issue of pub.dev and work well in real device
the dart code you need reside in
https://github.com/akeblom/flutter-nfc-reader/blob/master/lib/flutter_nfc_reader.dart
void _onEvent(dynamic data) {
print("Event");
print(data);
}
Edit add more detail
akeblom has add Write NFC capability to IOS, so IOS part should work. please ue this fork https://github.com/akeblom/flutter-nfc-reader
For IOS MissingPluginException issue, I do not have IOS, I suggest you can ask akeblom
The data part you mentioned in comments if I do not misunderstand is line 77, please see describe below
In Android part.
https://github.com/akeblom/flutter-nfc-reader/blob/master/android/src/main/kotlin/it/matteocrippa/flutternfcreader/FlutterNfcReaderPlugin.kt
line 174, use kotlin mapOf returns a new read-only map with the specified contents and eventSink.success result to Dart
if (message != null) {
val data = mapOf(kId to id, kContent to message, kError to "", kStatus to "read")
eventSink?.success(data)
}
In https://github.com/akeblom/flutter-nfc-reader/blob/master/lib/flutter_nfc_reader.dart
line 22, with named constructor
factory NfcData.fromMap(Map data) {
NfcData result = NfcData(
id: data['nfcId'],
content: data['nfcContent'],
error: data['nfcError'],
statusMapper: data['nfcStatus'],
);
In line 77, NFC read start and _onEvent(dynamic data) get the data.
stream use this named constructor, and parse data, here with map((result)) transfer to NfcData
static Stream<NfcData> get read {
final resultStream = _channel
.invokeMethod('NfcRead')
.asStream()
.asyncExpand((_) => stream
.receiveBroadcastStream()
.map((result) => NfcData.fromMap(result)));
return resultStream;
In https://github.com/akeblom/flutter-nfc-reader/blob/master/example/lib/main.dart
line 33, response has transfered to NfCData, so example just use _nfcData = response;
FlutterNfcReader.read.listen((response) {
setState(() {
_nfcData = response;
});
});
The simplest way I found to parse an event to a Map is the following:
I encoded the variable to a String (but I use json.encode(event)instead of event.toString()as encode(event)returns a valid string.
Then I use this string to construct a map via json.decode. All of this is achieved with the flutter native library dart:convert. The complete code looks like this:
import 'dart:convert';
...
void _onEvent(dynamic event) {
//Receive Event
print("NFC Event received");
String str = json.encode(event);
Map eventMap = json.decode(str);
}
Have you tried event.toString()? It might return a string containing the field you are trying to get, from which you can easily parse the value.
You may also want to try:
Class<?> clazz = event.getClass();
Field payload= clazz.getField("Payload"); //Note, this can throw an exception if the field doesn't exist.
String fieldValue = payload.toString();
If it isn't returning what you want, you may need to make an interface for the object type, with a get method, or override the toString method to get return the Payload value.