I used the flutter_callkit_incoming package for incoming calls, and everything works and I want to cast/convert event.toString() to Map so that I can extract a map value of body and extra.
When run this code print(event.toString()), it outputs like this below:
{ event: com.hiennv.flutter_callkit_incoming.ACTION_CALL_ACCEPT, body: {id: b9be7c0a-1c2a-46e9-ba47-e66e0e2c96ee, nameCaller: Leslie Joe, avatar: http://192.168.43.196:3000/images/1641224008963_image_picker1623631765702357491.jpg, number: 233507300523, type: 0, duration: 30000, extra: {caller: 233541395590, callee: 233507300523, callerImage: 1641224008963_image_picker1623631765702357491.jpg, calleeName: Leslie Joe, uuid: b9be7c0a-1c2a-46e9-ba47-e66e0e2c96ee, callType: calling, callerName: Woo Bear}, android: {isCustomNotification: true, ringtonePath: ringtone_default, backgroundColor: #0D1117, backgroundUrl: , actionColor: #0D1117}} }
final encodedData = json.encode(event.toString());
final decodedData = json.decode(encodedData);
final data = decodedData["body"];
final extraData = decodedData["body"]["extra"];
print(data);
print(extraData);
But it gave me errors
E/flutter (16521): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
E/flutter (16521): #0 _MainScreenState.listenerEvent.<anonymous closure>
package:sharpcall/…/screens/main_screen.dart:166
E/flutter (16521): #1 _rootRunUnary (dart:async/zone.dart:1434:47)
E/flutter (16521): #2 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (16521): #3 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (16521): #4 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter (16521): #5 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter (16521): #6 _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
E/flutter (16521): #7 _MapStream._handleData (dart:async/stream_pipe.dart:218:10)
E/flutter (16521): #8 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
E/flutter (16521): #9 _rootRunUnary (dart:async/zone.dart:1434:47)
E/flutter (16521): #10 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (16521): #11 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (16521): #12 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter (16521): #13 _DelayedData.perform (dart:async/stream_impl.dart:591:14)
E/flutter (16521): #14 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:706:11)
E/flutter (16521): #15 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:663:7)
E/flutter (16521): #16 _rootRun (dart:async/zone.dart:1418:47)
E/flutter (16521): #17 _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter (16521): #18 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
E/flutter (16521): #19 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
E/flutter (16521): #20 _rootRun (dart:async/zone.dart:1426:13)
E/flutter (16521): #21 _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter (16521): #22 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
E/flutter (16521): #23 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
E/flutter (16521): #24 _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
E/flutter (16521): #25 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)
I need your help on how to convert it to a map correctly. Please check the package's example here Thanks.
CodePudding user response:
This is the json format of your event.toString() output
{
"event": "com.hiennv.flutter_callkit_incoming.ACTION_CALL_ACCEPT",
"body": {
"id": "b9be7c0a-1c2a-46e9-ba47-e66e0e2c96ee",
"nameCaller": "Leslie Joe",
"avatar": "http://192.168.43.196:3000/images/1641224008963_image_picker1623631765702357491.jpg",
"number": 233507300523,
"type": 0,
"duration": 30000,
"extra": {
"caller": "233541395590",
"callee": "233507300523",
"callerImage": "1641224008963_image_picker1623631765702357491.jpg",
"calleeName": "Leslie Joe",
"uuid": "b9be7c0a-1c2a-46e9-ba47-e66e0e2c96ee",
"callType": "calling",
"callerName": "Woo Bear"
},
"android": {
"isCustomNotification": true,
"ringtonePath": "ringtone_default",
"backgroundColor": "#0D1117",
"backgroundUrl": "",
"actionColor": "#0D1117"
}
}
}
You can use an online tool to create classes with toMap() & fromMap() or toJson() & fromJson() methods that you can use to produce models of your objects
An example tool is https://app.quicktype.io/ (no null-safety) or https://www.webinovers.com/web-tools/json-to-dart-convertor (null-safety)
For me I like to write my own classes to have control over default values and some more functionalities. So here are the classes I would write to convert your json output
Event eventFromMap(String str) => Event.fromMap(json.decode(str));
class Event {
Event({
this.event,
this.body,
});
String? event;
Body? body;
factory Event.fromMap(Map<String, dynamic> json) => Event(
event: json["event"],
body: json["body"] == null ? null : Body.fromMap(json["body"]),
);
}
class Body {
Body({
this.id,
this.nameCaller,
this.avatar,
this.number,
this.type,
this.duration,
this.extra,
this.android,
});
String? id;
String? nameCaller;
String? avatar;
int? number;
int? type;
int? duration;
Extra? extra;
Android? android;
factory Body.fromMap(Map<String, dynamic> json) => Body(
id: json["id"],
nameCaller: json["nameCaller"],
avatar: json["avatar"],
number: json["number"],
type: json["type"],
duration: json["duration"],
extra: json["extra"] == null ? null : Extra.fromMap(json["extra"]),
android: json["android"] == null ? null : Android.fromMap(json["android"]),
);
}
class Android {
Android({
this.isCustomNotification = false, // add your custom default value
this.ringtonePath,
this.backgroundColor,
this.backgroundUrl,
this.actionColor,
});
bool isCustomNotification;
String? ringtonePath;
String? backgroundColor;
String? backgroundUrl;
String? actionColor;
factory Android.fromMap(Map<String, dynamic> json) => Android(
isCustomNotification: json["isCustomNotification"],
ringtonePath: json["ringtonePath"],
backgroundColor: json["backgroundColor"],
backgroundUrl: json["backgroundUrl"],
actionColor: json["actionColor"],
);
}
class Extra {
Extra({
this.caller,
this.callee,
this.callerImage,
this.calleeName,
this.uuid,
this.callType,
this.callerName,
});
String? caller;
String? callee;
String? callerImage;
String? calleeName;
String? uuid;
String? callType;
String? callerName;
factory Extra.fromMap(Map<String, dynamic> json) => Extra(
caller: json["caller"],
callee: json["callee"],
callerImage: json["callerImage"],
calleeName: json["calleeName"],
uuid: json["uuid"],
callType: json["callType"],
callerName: json["callerName"],
);
}
Now if you type
final event = eventFromMap(rawEvent.toString()); // Your response
You can use event.body?.extra?.caller for example to access data with autocomplete benefit which is better than maps in my opinion
CodePudding user response:
Thanks for your quick solution Sir but it still gives me the same errors. Luckily, I explored the package and found its class called CallEvent with its fields - String name and dynamic body so if the body field is Map, we will be able to get body value as Map from the class.
if (event!.body is Map) {
final extraData = event.body["extra"];
print(extraData);
}
I hope it may help someone else in the future. Thanks! Happy New Year to you all!!
