flutter webrtc RTCPeerConnection.addStream not working - flutter

Friends, I want to develop an application for Flutter using webrtc, but unfortunately I am facing problems that I am not able to solve.
errorCode: AddStream is not available with Unified Plan SdpSemantics. Please use AddTrack instead.
Thanks
Map<String, dynamic> configuration = {
"iceServers": [
{"url": "stun:stun1.l.google.com:19302"},
]
};
final Map<String, dynamic> offerSdpConstraints = {
"mandatory": {
"OfferToReceiveAudio": true,
"OfferToReceiveVideo": true,
},
'optional': [
{'DollsSftpKeyAgreement': true},
],
};
Map<String,dynamic> mediaConstraints = {
'audio': true,
'video': true,
};
_localStream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
_localRenderer.srcObject = _localStream;
RTCPeerConnection pc = await createPeerConnection(configuration,offerSdpConstraints);
pc.addStream(_localStream!);

I finally found the cause of this error and realized that
RTCPeerConnection.addStream(localStream) It is obsolete
and I use it
localStream?.getTracks().forEach((track) { peerConnection?.addTrack(track, localStream!); });
I hope it will be useful for you

Related

Problem fetching data from my api in flutter

I have the following code in my flutter app:
MODELS:
APIUser apiUserFromJson(String str) => APIUser.fromJson(json.decode(str));
String apiUserToJson(APIUser data) => json.encode(data.toJson());
class APIUser {
APIUser({this.id, this.username, this.email, this.role});
int? id;
String? username;
int? email;
String? role;
factory APIUser.fromJson(Map<String, dynamic> json) => APIUser(
id: json["user"]["id"],
username: json["user"]["username"],
email: json["user"]["email"],
role: json["user_role"],
);
Map<String, dynamic> toJson() => {
"id": id,
"username": username,
"email": email,
"role": role,
};
}
GlobalUser globalUsersFromJson(String str) =>
GlobalUser.fromJson(json.decode(str));
String globalUsersToJson(GlobalUser data) => json.encode(data.toJson());
class GlobalUser {
GlobalUser({
this.users,
});
List<APIUser>? users;
factory GlobalUser.fromJson(Map<String, dynamic> json) => GlobalUser(
users:
List<APIUser>.from(json["users"].map((x) => APIUser.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"users": List<dynamic>.from(users!.map((x) => x.toJson())),
};
}
UPDATED
MY METHOD FOR FETCHING:
Future<dynamic> getGlobalUsers() async {
try {
var token = storage.read('token');
final uri = Uri.parse("${ApiConstants.baseUrl}/get_users");
final headers = {
HttpHeaders.contentTypeHeader: 'application/json',
HttpHeaders.authorizationHeader: 'Token $token'
};
var response = await http.post(uri,
headers: headers); // Request Timeout response status code
**print(response);**
if (response.statusCode == 200) {
GlobalUser globalUsers = globalUsersFromJson(response.body);
return globalUsers;
}
if (response.statusCode == 401) {
return http.Response('Error', 401);
}
if (response.statusCode >= 500) {
return http.Response('Error', 500);
}
} catch (e) {
log(e.toString());
}
}
API RESPONSE IN POSTMAN FOR THE URL ASKED IN PREVIOUS METHOD getGlobalUsers:
[
{
"user": {
"id": 16,
"last_login": "2022-11-27T16:20:42.271178+01:00",
"username": "user1",
"email": "user1#mail.es",
"date_joined": "2022-11-27T15:30:47.851322+01:00",
"groups": [],
"user_permissions": []
},
"user_role": "worker"
}
]
In flutter, if I print the response of this method, I´m getting [], and I´m not sure about what am I doing wrong. The whole Backend API is working OK , as in POSTMan. THE PRINT STATEMENT IN FETCHING METHOD RETURNS NOTHING
Thanks in advance
int? email should be a String? email
You need to return List<dynamic> as your API response data is List
GlobalUser globalUsersFromJson(String str) =>
GlobalUser.fromJson(json.decode(str)as List<dynamic>);
factory GlobalUser.fromJson(List<dynamic> json) => GlobalUser(
users:
json
.map((e) => APIUser.fromJson(e as Map<String, dynamic>))
.toList();
);
TRY THIS...
factory GlobalUser.fromJson(Map<String, dynamic> json) => GlobalUser(
users:
List<APIUser>.from(json.map((x) => APIUser.fromJson(x))),
);
what you are doing is fetching all the data from the API and then using the data that you want in the widget in your app.

Accessing Flutter callkit Incoming Calls Params

am at the moment making use of this particular flutter package for my project but I can't access the params, please I really need your help
flutter_callkit_incoming: ^1.0.0+8
when am to receive an incoming call I use the below code
this._currentUuid = _uuid.v4();
var params = <String, dynamic>{
'id': _currentUuid,
'nameCaller': data.fromFullName,
'appName': 'Prayer Buddy',
'avatar': data.fromImage,
'handle': 'Prayer Partner Calling',
'type': type,
'duration': 30000,
'extra': <String, dynamic>{'userId': '1a2b3c4d'},
'headers': <String, dynamic>{'apiKey': 'Abc#123!', 'platform': 'flutter'},
'android': <String, dynamic>{
'isCustomNotification': true,
'isShowLogo': false,
'ringtonePath': 'ringtone_default',
'backgroundColor': '#0955fa',
'backgroundUrl': data.toImage,
'actionColor': '#4CAF50'
},
'ios': <String, dynamic>{
'iconName': 'AppIcon40x40',
'handleType': 'generic',
'supportsVideo': true,
'maximumCallGroups': 2,
'maximumCallsPerCallGroup': 1,
'audioSessionMode': 'default',
'audioSessionActive': true,
'audioSessionPreferredSampleRate': 44100.0,
'audioSessionPreferredIOBufferDuration': 0.005,
'supportsDTMF': true,
'supportsHolding': true,
'supportsGrouping': false,
'supportsUngrouping': false,
'ringtonePath': 'Ringtone.caf'
}
};
await FlutterCallkitIncoming.showCallkitIncoming(params);
on the FlutterCallkitIncoming.onEvent.listen((event) function am trying to access the params sent via the showCallkitIncoming(params)
so i did a print of the event print(event) the output was below
{ event: com.hiennv.flutter_callkit_incoming.ACTION_CALL_ENDED, body: {duration: 30000, extra: {userId: 1a2b3c4d}, uuid: 1fa5d670-5698-40fa-8705-bd794304fa96, avatar: http://arome.joons-me.com/user_img/james/images/image_picker_F27FD117-E882-4C51-9143-943E3BF4A8CF-24547-00000899F347179A.jpg, type: 0, nameCaller: James Amadin, handle: Prayer Partner Calling, appName: Prayer Buddy, ios: {supportsHolding: true, audioSessionPreferredIOBufferDuration: 0.005, supportsDTMF: true, maximumCallGroups: 2, includesCallsInRecents: true, audioSessionPreferredSampleRate: 44100.0, iconName: AppIcon40x40, supportsVideo: true, supportsGrouping: false, audioSessionActive: true, audioSessionMode: default, maximumCallsPerCallGroup: 1, supportsUngrouping: false, handleType: generic, ringtonePath: Ringtone.caf}} }
I want to access the extra from the return JSON, please how do I do that?
but when i tried to access it via the below code
try {
dynamic myMap = json.decode(event!.body);
if (myMap is! Map<String, dynamic>) throw FormatException();
final message = myMap['extra'];
print('1message == ${message}');
} catch (error) {
print('JSON is in the wrong format');
}
I got JSON is in the wrong format
I was able to resolve it by the following code
print(event!.body['extra']['userId']);
print(event.body['extra']['to_user']);
print(event.body['extra']['from_user']);

fetch a list JSON to a DropdownMenuItem?

I have a JSON object here:
{
"data": [
{
"id": 1,
"countryName": "India"
},
{
"id": 2,
"countryName": "USA"
}
],
"exceptionInfo": null,
"message": null,
"messages": null,
"isSuccess": true
}
I want to fetch the name parameter under data to a DropDownMenuList. I have a data model here:
import 'dart:convert';
GetCountry getCountryFromJson(String str) => GetCountry.fromJson(json.decode(str));
String getCountryToJson(GetCountry data) => json.encode(data.toJson());
class GetCountry {
GetCountry({
this.data,
this.exceptionInfo,
this.message,
this.messages,
this.isSuccess,
});
List<CountryModal> data;
dynamic exceptionInfo;
dynamic message;
dynamic messages;
bool isSuccess;
factory GetCountry.fromJson(Map<String, dynamic> json) => GetCountry(
data: List<CountryModal>.from(json["data"].map((x) => CountryModal.fromJson(x))),
exceptionInfo: json["exceptionInfo"],
message: json["message"],
messages: json["messages"],
isSuccess: json["isSuccess"],
);
Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(data.map((x) => x.toJson())),
"exceptionInfo": exceptionInfo,
"message": message,
"messages": messages,
"isSuccess": isSuccess,
};
}
class CountryModal {
CountryModal({
this.id,
this.countryName,
});
int id;
String countryName;
factory CountryModal.fromJson(Map<String, dynamic> json) => CountryModal(
id: json["id"],
countryName: json["countryName"],
);
Map<String, dynamic> toJson() => {
"id": id,
"countryName": countryName,
};
}
The function to fetch the data is below and is the indifferent file:
Future<GetCountry> Getcountry(String authToken) async{
try {
String uriParts = apiEndPoint.getUriParts('location/GetCountries');
var response = await http.get(
apiEndPoint.getHTTPUri(uriParts),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': authToken
},
);
var responseJson = jsonDecode(response.body);
GetCountry country = GetCountry.fromJson(responseJson);
return country;
}
catch (err) {
debugPrint(err.toString());
throw err;
}
}
This method fetches the item successfully into a ListView.builder widget but I am a bit lost on how to fetch this to a List<DropdownMenuItem> items.
I have tried going through solutions but nothing seems to work for me.
please help.
EDIT:-
Below is the code for the dropdown list -:
List<CountryModal> _countrylist = [];
String mycountry;
DropdownButton(
items: _countrylist.map((item) {
return new DropdownMenuItem(
child: new Text(
item.countryName,
style: TextStyle(fontSize: 14.0),
),
value: item.id.toString(),
);
}).toList(),
hint: Text(
"Please select the country",
style: TextStyle(
color: Colors.black45,
),),
onChanged: (newVal) {
setState(() {
mycountry = newVal;
});
},
value: mycountry,
),
Error message below -:
Sample json format -:
{
"error": "0",
"message": "Succesfully fetched",
"status": true,
"data": [
{
"id": "5df0b94841f0331baf1357bb",
"stateName": "test group",
},
{
"id": "5df0df507091683d2f1ad0cf",
"stateName": "new group",
}
]
}
You will just pass a map.toList() to the items field.
DropdownButton(items: myGetCountry.map((CountryModal e) {
return DropdownMenuItem(child: SomeWidget(e))).toList();
})

How to receive FCM push notification data in flutter web and redirect user to received link in notification?

I am trying to redirect user to specific page in flutter web on click of notification, till now I am receiving notification, the last open page is displayed in browser on click of notification, but I want user to redirect to specific page like specific post using unique post id, but I found no other ways, This thing happens in Android build, but doesn't happen on web build.
just take a look at ServiceWorker.js
in serviceworker.js even console.log() in not executing on receiving notification.
messaging.setBackgroundMessageHandler(function (payload) {
console.log(payload);
const promiseChain = clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(windowClients => {
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
windowClient.postMessage(payload);
}
})
.then(() => {
const title = payload.notification.title;
const options = {
body: payload.notification.body
};
return registration.showNotification(title, options);
});
return promiseChain;
});
self.addEventListener('notificationclick', function (event) {
console.log('notification received: ', event)
});
now the logic for sending FCM Push Notification:
#required String message,
#required String fcmToken,
#required String title,
String type,
String typeId,
}) async {
await http
.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$serverToken',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
"click_action": 'FLUTTER_NOTIFICATION_CLICK',
'body': message,
'title': '$title',
'sound': 'default'
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1',
'status': 'done',
'type': type ?? "",
'typeId': typeId ?? "",
},
'to': fcmToken.toString().trim(),
},
),
)
.then((value) {
print("Notification Sent");
});
final Completer<Map<String, dynamic>> completer =
Completer<Map<String, dynamic>>();
// firebaseMessaging.configure(
// onMessage: (Map<String, dynamic> message) async {
// completer.complete(message);
// },
// );
return completer.future;
}
Now the way I am handling Notification Receive:
print("in setup interacted message");
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
importance: Importance.max,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
NotificationSettings notifSettings =
await FirebaseMessaging.instance.requestPermission(
alert: true,
announcement: true,
badge: true,
carPlay: true,
criticalAlert: true,
provisional: true,
sound: true,
);
if (notifSettings.authorizationStatus == AuthorizationStatus.authorized) {
// Get any messages which caused the application to open from
// a terminated state.
try {
RemoteMessage initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
// If the message also contains a data property with a "type" of "post",
// navigate to a post screen
if (initialMessage != null && initialMessage.data['type'] == 'post') {
await Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => IndividualPostPage(
postObjectId: initialMessage.data['typeId'],
),
),
);
print(initialMessage.data);
initialMessage = null;
}
// Also handle any interaction when the app is in the background via a
// Stream listener
FirebaseMessaging.onMessageOpenedApp
.listen((RemoteMessage message) async {
print("here");
if (message != null && message.data['type'] == 'post') {
if (message.data['type'] == 'post') {
await Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => IndividualPostPage(
postObjectId: message.data['typeId'],
),
),
);
}
print(message.data);
message = null;
}
});
} catch (e) {
print("Error $e");
}
}
}
messaging.setBackgroundMessageHandler(function (payload) {
console.log(payload);
const promiseChain = clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(windowClients => {
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
windowClient.postMessage(payload);
}
})
.then(() => {
const title = payload.notification.title;
var click_action =payload.data.ui_route;//ui route is ur route
const options = {
body: payload.notification.body ,
data: {
click_action,
}
};
return registration.showNotification(title, options);
});
return promiseChain;
});
// Notification click event listener
self.addEventListener('notificationclick', e => {
data=e.notification.data.obj;
// Close the notification popout
e.notification.close();
// Get all the Window clients
e.waitUntil(clients.matchAll({ type: 'window' }).then(clientsArr => {
// If a Window tab matching the targeted URL already exists, focus that;
const hadWindowToFocus = clientsArr.some(windowClient => windowClient.url === e.notification.data.click_action ? (windowClient.focus(), true) : false);
// Otherwise, open a new tab to the applicable URL and focus it.
if (!hadWindowToFocus) clients.openWindow(e.notification.data.click_action).then(windowClient => windowClient ? windowClient.focus() : null);
}));
});

How to use Razorpay Orders API in Flutter?

I'm implementing a payment gateway in my flutter application. So Razorpay recommends me to use Orders API. But I don't get any ways to implement Orders API.
I had referred the below documentation. It contains examples for java, PHP, etc. But nothing found for Flutter / Dart.
https://razorpay.com/docs/payment-gateway/orders/integration/#example
Thanks in advance.
Future<void> generate_ODID() async {
var orderOptions = {
'amount': 50000, // amount in the smallest currency unit
'currency': "INR",
'receipt': "order_rcptid_11"
};
final client = HttpClient();
final request =
await client.postUrl(Uri.parse('https://api.razorpay.com/v1/orders'));
request.headers.set(
HttpHeaders.contentTypeHeader, "application/json; charset=UTF-8");
String basicAuth = 'Basic ' +
base64Encode(utf8.encode(
'${'YourKEY'}:${'YourSECRET'}'));
request.headers.set(HttpHeaders.authorizationHeader, basicAuth);
request.add(utf8.encode(json.encode(orderOptions)));
final response = await request.close();
response.transform(utf8.decoder).listen((contents) {
print('ORDERID'+contents);
String orderId = contents.split(',')[0].split(":")[1];
orderId = orderId.substring(1, orderId.length - 1);
Fluttertoast.showToast(
msg: "ORDERID: " +orderId,
toastLength: Toast.LENGTH_SHORT);
Map<String, dynamic> checkoutOptions = {
'key': 'YourKEY',
'amount': 11100,
'name': 'Demo',
'description': 'Fssai Registrtion Charge',
'prefill': {'contact': '8910407549', 'email': 'xx.xx#gmail.com'},
'external': {
'wallets': ['paytm']
}
};
try {
_razorpay.open(checkoutOptions);
} catch (e) {
print(e.toString());
}
});
}
I am using this same code snippet but when I am trying to do payments with google pay then it will fail with "Your money is not debited, Your server is busy" Error, but when I try to do with providing UPI Id manually then the transaction goes smoothly, otherwise transactions not done using UPI. Is there any way to solve this?
final client = HttpClient();
final request =
await client.postUrl(Uri.parse('https://api.razorpay.com/v1/orders'));
request.headers.set(
HttpHeaders.contentTypeHeader, "application/json; charset=UTF-8");
String basicAuth = 'Basic ' +
base64Encode(utf8.encode(
'${dotenv.env['RAZORPAY_KEY']!}:${dotenv.env['RAZORPAY_SECRET']!}'));
request.headers.set(HttpHeaders.authorizationHeader, basicAuth);
request.add(utf8.encode(json.encode(orderOptions)));
final response = await request.close();
response.transform(utf8.decoder).listen((contents) {
String orderId = contents.split(',')[0].split(":")[1];
orderId = orderId.substring(1, orderId.length - 1);
Map<String, dynamic> checkoutOptions = {
'key': dotenv.env['RAZORPAY_KEY']!,
'amount': total * 100,
"currency": "INR",
'name': 'E Drives',
'description': 'E Bike',
'order_id': orderId, // Generate order_id using Orders API
'timeout': 300,
};
try {
_razorpay.open(checkoutOptions);
} catch (e) {
log.e(e.toString());
}
You can use HttpClient and send a request to the Razorpay Orders API.
Hope this answers your question.
Thankfully, Razorpay has Flutter package which you can use. The following code snippet might help :
import 'package:razorpay_flutter/razorpay_flutter.dart';
_razorpay = Razorpay();
var options = {
'key': '<YOUR_KEY_ID>',
'amount': 100, //in the smallest currency sub-unit.
'name': 'Acme Corp.',
'order_id': 'order_EMBFqjDHEEn80l', // Generate order_id using Orders API
'description': 'Fine T-Shirt',
'prefill': {
'contact': '9123456789',
'email': 'gaurav.kumar#example.com'
}
};
_razorpay.open(options);
Please go through this page for further details. And this YouTube video will help as well.
You can use the Below code. it's working as expected.
createOrderId(amount, description, id, userId) async {
final int Amount = int.parse(amount) * 100;
http.Response response = await http.post(
Uri.parse(
"https://api.razorpay.com/v1/orders",
),
headers: {
"Content-Type": "application/json",
"Authorization":
"Basic ${base64Encode(utf8.encode('testKey:secreateKey'))} "
},
body: json.encode({
"amount": Amount,
"currency": "INR",
"receipt": "OrderId_$id",
"notes": {"userId": "$userId", "packageId": "$id"},
}));
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
openCheckout(amount, description, id, userId, data["id"]);
}
print(response.body);
}
void openCheckout(amount, description, id, userId, String orderId) async {
final int Amount = int.parse(amount) * 100;
var options = {
'key': 'testkey',
'amount': Amount,
'name': 'Name',
'description': description,
'order_id': orderId,
// "prefill": {
// "name": name,
// "email": emails,
// },
"notes": {"userId": "$userId", "packageId": "$id"},
'external': {
'wallets': ['paytm']
}
};
try {
_razorpay.open(options);
} catch (e) {
debugPrint('Error: e');
}
}
Might be helpful for someone.
Hope you set up all the necessary things.
Step 1: creating Order using Razorpay official Order Api:
//* create order##############################################################
void createOrder() async {
String username = 'xxxxxxxxxx';// razorpay pay key
String password = "xxxxxxxxxxxxxxxx";// razoepay secret key
String basicAuth =
'Basic ${base64Encode(utf8.encode('$username:$password'))}';
Map<String, dynamic> body = {
"amount": 1 * 100,
"currency": "INR",
"receipt": "rcptid_11"
};
var res = await http.post(
Uri.https(
"api.razorpay.com", "v1/orders"), //https://api.razorpay.com/v1/orders // Api provided by Razorpay Official 💙
headers: <String, String>{
"Content-Type": "application/json",
'authorization': basicAuth,
},
body: jsonEncode(body),
);
if (res.statusCode == 200) {
openCheckout(jsonDecode(res.body)['id']); // 😎🔥
}
print(res.body);
}
//*#################################################################
Step 2: Open Razorpay checkout interface.
After getting orderId from Razorpay official Api, pass the id when calling openCheckout(jsonDecode(res.body)['id']); function
void openCheckout(String orderId) async {
var options = {
'key': 'xxxxxxxxxxxxxxxx',
"amount": 1 * 100,
'order_id': orderId,
'name': 'main.co.in',
// 'prefill': {'contact': '', 'email': 'test#razorpay.com'},
'external': {
'wallets': ['paytm']
}
};
try {
razorpay.open(options);
} catch (e) {
debugPrint('Error: e');
}
}
3rd Step: Signature verification.
This is important if you automatically wanna transfer your amount to your bank account.
for Hmac SHA key , install this package: crypto:
handlerPaymentSuccess(PaymentSuccessResponse response) {
final key = utf8.encode('NgDLPyiDRPuQpcXy1E3GKTDv');
final bytes = utf8.encode('${response.orderId}|${response.paymentId}');
final hmacSha256 = Hmac(sha256, key);
final generatedSignature = hmacSha256.convert(bytes);
if (generatedSignature.toString() == response.signature) {
log("Payment was successful!");
//Handle what to do after a successful payment.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Success : payment successful"),
// content: const Text("Are you sure you wish to delete this item?"),
actions: <Widget>[
ElevatedButton(
onPressed: () {
Navigator.of(context).pop(true);
// PlaceOrderPrepaid();
},
child: Text("OK"))
// ),
],
);
},
);
} else {
log("The payment was unauthentic!");
}
}
Thats it!