How to parse an object variable in eventChannel callback method? - flutter

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.

Related

Casting an object in Flutter/Dart returns _HashSet

I am having some problem in Flutter with casting a dynamic to a custom object. I receive JSON as response from a web service, which I store as an instance of my object in a class as dynamic together with some other meta information. When I try to cast that object to my desired class (e.g. LoginReply) I keep getting the following error message: Expected a value of type 'LoginReply', but got one of type '_HashSet<LoginReply>'
Here is my response class that stores the reply object:
class DioResponse {
String? error;
dynamic object;
DioResponse(this.error, this.object);
bool get isSuccessful => error == null || error!.isEmpty;
T get<T extends dynamic>() {
print("Object: $object");
return object.cast<T>();
}
}
I serialize the JSON response like this:
LoginReply _serializeResponse(Map<String, dynamic> json) {
LoginReply reply = LoginReply.fromJson(json);
if (!reply.header!.successful) {
errorMessage.value = "${reply.header!.errorCode}: ${reply.header!.errorMessage}";
return LoginReply();
}
AppConfig.persistString("token", reply.token!);
return reply;
}
And here is how I try to access the DioReponse.object / LoginReply:
DioResponse response = await handler.post(Globals.nodeAddress, ......);
if (response.isSuccessful) {
//LoginReply reply = response.get<LoginReply>();
print("Object: ${response.object}");
LoginReply reply = response.object as LoginReply;
The print output on the second last line prints: Object: {Instance of 'LoginReply'} which makes the whole error even harder to understand for me.
The problem was in the closure that was passed as parameter to the post function. So it really returned a Set. I pass a function to the DioHandler class that is called there and then it just works the way it should.

Cannot convert JSON into Objects

i All,
The Project: A handy utility for tickets at work to help sort and manage my tickets, built on top of our provider's API.
My Background: I'm like 19 hours total into dart and am almost done with my first bootcamp.
The GIST: I have started writing a provider for our helpdesk software's API. I am sending requests to the API successfully but I am utterly clueless on transforming the data into an actual map to generate ticket instances with.
What I'm trying to accomplish:
Fetch the data from the API
Convert that String into a MAP of json objects that I can iterate
through
Iterate through the JSON objects to create instances of ticket
objects with
build a list of those ticket objects and return it to requestor to
generate a widget list.
I could swear I've done everything reasonable to try and type cast this as a map but I think there is something I just don't understand. FWIW I think whatever it is I'm trying to do is accessing a Future not the actual data. and I think i might be confused or unclear about async/awaits but my understanding of the code I've written is that the actions are chained one to another so I shouldn't be "waiting" for anything or getting a future, I should just be getting a string.
Otherwise, Here's my code cleaned up, any advice or suggestions on working with the data in the print would be much appreciated.
class ticketingsoftwareAPIProvider {
// Object Properties
Client _client = Client();
final String _ApiKey = "YOUSHALLPASS!";
final String apiRoot = "https://api.ticketingsoftware.com";
final String agentId = '2675309';
getAgentTickets() async {
// Headers for our HTTP Request
Map<String, String> headers = {
'X-ticketingsoftware-Authorization': 'Bearer $_ApiKey',
'Accept': 'application/vnd.ticketingsoftware.v2.1+json',
'Content-Type': 'application/json'
};
await _client
.get(Uri.parse('$apiRoot/incidents.json?assigned_to=$agentId'))
.then((data) {
if (data.statusCode == 200) {
print(json.decode(data.body));
// CANT SEEM TO MAKE THIS A INTO A MAP TO GENERATE OBJECTS WITH.
}
});
}
}
} // END CLASS
I apologize for any missing information, I am new to dart and REALLY programming in general and am still learning the culture. please let me know if there is any additional information that might help.
My Solution ended up being:
List ticketJson = json.decode(data.body);
for (var ticket = 0; ticket < ticketJson.length; ticket++) {
thisAgentsTickets.add(incident.fromJson(ticketJson[ticket]));
return thisAgentsTickets;
I think I've been learning from a very out of date course.
You need fromJson method to convert it to an object. For example
if (data.statusCode == 200) {
return AgentTicket = AgentTicket.fromJson(data.body)
}
Use json_serializable package for easy way to create the method, or you can create it manually too.

Parse Server SDK - Include Object method doesn't work for fetching the whole object in flutter

I was using parse server sdk in my app for database.
I have three class in my Back4App Dashboard which are "_User", "Office", "Office_Members".
In Office_Members class it has following columns,
user_id (Pointer to _User)
office_id (Pointer to Office)
count
To fetch the data including Pointer to _User as well from Office_Members, I am using following code,
QueryBuilder<ParseObject> parseQuery = QueryBuilder<ParseObject>(ParseObject("Office_Members"))
..whereEqualTo("office_id", ParseResponse_OfficeObject)
..includeObject(["user_id "]);
ParseResponse apiResponse = await parseQuery.query();
Output :
Payload : [{"className":"Office_Members","objectId":"twpDY51PUK","createdAt":"2020-08-14T09:58:59.775Z","updatedAt":"2020-08-14T09:58:59.775Z","office_id":{"__type":"Pointer","className":"Office","objectId":"4dkfSMrwBI"},"user_id":{"__type":"Pointer","className":"_User","objectId":"Hx5xJ5ABxG"},"count":1}]
In my payload response i am not getting whole user_id pointer response.
So can anybody help me that what i might be doing wrong?
Thanks.
The data should be included.
The logging function simply does not print the data of pointers.
The data should be included. The print function not print the data of pointers.
You can print it out directly for testing purposes, E.g.
response.results[0].get('user_id').get('name')
Evaluation Expression E.g.
In your model u can access at same way, E.g
Call Model
if(response.success){
return response.results.map((p) => Example.fromParse(p)).toList();
} else {
throw ParseErrors.getDescription(response.error.code);
}
Model
import 'package:parse_server_sdk/parse_server_sdk.dart';
class Example {
Example({this.id, this.name});
Example.fromParse(ParseObject parseObject) :
id = parseObject.objectId,
name = parseObject.get('user_id').get('name');
final String id;
final String name ;
#override
String toString() {
return 'Example{id: $id, name: $name}';
}
}
Why not simply use cloud code ? I'm not to familiar with flutter but I can suggest you this alternative solution.
Write a function like this.
Parse.Cloud.define("fetchMemberAndUser", async (request) => {
//Pass in ParseResponse_OfficeObject ID as parameter
var objectId = request.params.id;
//Now do a simple get query
var query = new Parse.Query(Parse.Object.extend("Office_Members"));
//Using .includes to get the user profile object
query.include("user_id");
//This will return Office_Memebers Object along with user profile
return query.get(objectId,{useMasterKey:true});
}

Callback function issues in FB.API for Unity

I am using Unity 5.5.2f1 pro and facebook's SDK v 7.9.4
I have a script which after login (managed in a previous scene) sends an API request to FB asking for friends, name and email and sends that info as a POST to a php website.
code:
[Serializable]
public struct FBData {
public string first_name;
public string email;
public string friends;
public string id;}
public class UserManagement : MonoBehaviour {
string urlSaveUserData="some php website";
public Text testTxt;
FBData parsedData;
// Use this for initialization
void Start () {
//Check if it's the first time the user is opening the app.
if (UserInfo.FIRST_TIME) {
//update text (only used for testing, should be removed in production.)
testTxt.text = "Your user id is: " + UserInfo.ID;
//Perform FB.API call to get User Data.
getUserData ();
//Save in SQL table. (won't get here if line in getUserData() is active)
StartCoroutine ("saveUserData");
} else {
//do something else.
}
note: Since this is meant for iOS I have to test it on a device so I'm using text in the screen to display info (think of it as a badly implemented print statement).
The problem: In my callback function for FB.API I write in the text Gameobject (aka testTxt) the parsed information from the response which is saved in the Custom UserInfo clss. It display's correctly but the code gets stuck there. It doesn't continue to the next function. HOWEVER, if I delete/comment that line and don't display anything in the text field. The codes does continue to the POST function BUT the information from the API call is not passed, i.e my custom class is empty (leading me to believe the callback function is not called at all).
public void getUserData(){
string query = "me?fields=first_name,email,friends";
FB.API (query, HttpMethod.GET, Apicallback, new Dictionary<string, string> ());
}
private void Apicallback(IGraphResult result){
//Parse Graph response into a specific class created for this result.
parsedData = JsonUtility.FromJson<FBData>(result.RawResult);
//Pass each field into UserInfo class.
UserInfo.EMAIL = parsedData.email;
UserInfo.FRIENDS = parsedData.friends;
UserInfo.NAME = parsedData.first_name;
UserInfo.FACEBOOKID = parsedData.id;
/*problem area, if I comment line below, then previous information is apparently not stored. If left as is then testTxt displays correct information but code gets stuck there. */
testTxt.text = "This is the info from USerInfoInside the APICallback: " + UserInfo.EMAIL + UserInfo.FRIENDS + UserInfo.FACEBOOKID;
}
The function below is to send info to php website, is there for illustrative purposes:
code:
public IEnumerator saveUserData() {
//get user info (this information is EMPTY if line in getUserData() is commented.
parsedData.id = UserInfo.FACEBOOKID;
parsedData.friends = UserInfo.FRIENDS;
parsedData.first_name = UserInfo.NAME;
parsedData.email = UserInfo.EMAIL;
//translate data into json
string JsonBodyData = JsonUtility.ToJson (parsedData);
//Custom web request (POST method doesnt seem to work very well, documentation example sends empty form)
var w = new UnityWebRequest(urlSaveUserData, "POST");
byte[] bodyRaw = new System.Text.UTF8Encoding().GetBytes(JsonBodyData);
w.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
w.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
w.SetRequestHeader("Content-Type", "application/json");
yield return w.Send();
//work with received data...}
Im stuck here any help is appreciated. Thanks!
Be sure to use EscapeURL when using strings directly for JSON or HTTP POST and GET methods. The lack of this treatment tends to screw things over, particulary in iOS platforms.
From what I can see, this code
string query = "me?fields=first_name,email,friends";
should instead be escaped as
string query = WWW.EscapeURL("me?fields=first_name,email,friends");
so characters like "?" won't get encoded as an URL symbol.
I'm assuming you don't need to do that for your illustrative example, because UnityWebRequest already escapes your POST request strings internally, but I can't fully confirm that.

Debugging JSON in GWT (Cross Server)

How do I pass the jsonObj from the javascript code in getJson to the java code handleJsonResponse. If my syntax is correct, what do I do with a JavaScriptObject?
I know that the jsonObj contains valid data because alert(jsonObj.ResultSet.totalResultsAvailable) returns a large number :) --- but some how it's not getting passed correctly back into Java.
EDIT: I solved it... by passing in jsonObj.ResultSet.Result to the java function and working on it using a JSONArray.
Thanks.
public native static void getJson(int requestId, String url, MyClass handler) /*-{
alert(url);
var callback = "callback" + requestId;
var script = document.createElement("script");
script.setAttribute("src", url+callback);
script.setAttribute("type", "text/javascript");
window[callback] = function(jsonObj) { // jsonObj DOES contain data
handler.#com.michael.random.client.MyClass::handleJsonResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj);
window[callback + "done"] = true;
}
document.body.appendChild(script);
}-*/;
public void handleJsonResponse(JavaScriptObject jso) { // How to utilize JSO
if (jso == null) { // Now the code gets past here
Window.alert("Couldn't retrieve JSON");
return;
}
Window.alert(jso.toSource()); // Alerts 'null'
JSONArray array = new JSONArray(jso);
//Window.alert(""+array.size());
}
}
Not exactly sure how to fix this problem that I had, but I found a workaround. The javascript jsonObj is is multidimensional, and I didn't know how to manipulate the types in the java function. So instead, I passed jsonObj.ResultSet.Result to my function handler, and from there I was able to use get("string") on the JSONArray.
What is toSource() supposed to do? (The documentation I see for it just says "calls toSource".) What about toString()?
If your call to alert(jsonObj.ResultSet.totalResultsAvailable) yields a valid result, that tells me jsonObj is a JavaScript Object, not an Array. Looks to me like the constructor for JSONArray only takes a JS Array (e.g., ["item1", "item2", {"key":"value"}, ...] )