how to Send push notifications from Flutter app - flutter

I use firebase messaging to push notifications.
Now i push notifications from console to users on app, but I want the user to push notifications from app to another user when send message. How can I do that?
Knowing that I have saved the device ID of each user on Firestore
and the ID is renewed every time the user logs into the application.
I tried using the following code to send notifications in case the user sends a message, but it didn't work
sendNotification(String body, String idToken) async {
await http.post(
(Uri.parse('https://fcm.googleapis.com/fcm/send')),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$servitoken',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
'body': "${body.toString()}",
'title': "!"
},
'priority': 'high',
'data': <String, dynamic>{
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
'id': '1',
'status': 'done'
},
'to': await "${idToken}",
},
),
);
}
,##

I will recommend you to use onesignal instead of just using firebase cloud messaging. Onesignal is easy to use and can make your development life more

Related

Integrating BankID (Swedish authentication service) into Flutter (Android and Ios)

I'm trying to impletment Swedish bankid on one of my project. But the resources that are available on the internet is too little. Can anybody help me how to implement BankId authentication on flutter app.
Not sure on how much experience you have whit BankId, so maybe you already know some of the stuffs, but this is how I solved it.
The service has three main endpoints for performing verification:
/auth/start: This endpoint is used to initiate the verification process and generates a unique key, called a bankIdToken, which is returned in the form of a GUID.
/auth/status: This endpoint is used to check the status of a verification process that has been initiated with the /auth/start endpoint. The status can be "waiting" or "completed".
/auth/verify: This endpoint is used to verify the identity of a user who has completed the verification process and returns a JSON object containing information about the user.
To perform a verification, the steps are as follows:
Send a request to /auth/start to initiate the process and receive the bankIdToken.
Pass the bankIdToken to /auth/verify to trigger the verification on the user's device (mobile, pc) , the status will be waiting.
After the user completes the process on their device, check the status by sending a request to /auth/status that will change the status to completed.
Send a request to /auth/verify to verify the user, this will return a JSON object containing user information.
You can also get testing bankid at https://demo.bankid.com/ and fake Swedish person numbers in skatteverket or https://fejka.nu/ ( GDPR Approved)
This is my flutter code whit hardcoded values
class AuthDataSource {
Future<AuthVerifyModel> authFlow() async {
final authStartResponse = await http.post(
Uri.https(BASEURL, '/auth/start'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'bankIdNumber': '198806192392',
}),
);
if (authStartResponse.statusCode != 200) {
throw ServerException();
}
final authStartModel =
AuthStartModel.fromJson(jsonDecode(authStartResponse.body));
final authStatusResponse = await http.post(
Uri.https(BASEURL, '/auth/status'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'bankIdToken': authStartModel.bankIdToken.toString(),
}),
);
if (authStatusResponse.statusCode != 200) {
throw ServerException();
}
final authVerifyResponse = await http.post(
Uri.https(BASEURL, '/auth/verify'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'bankIdToken': authStartModel.bankIdToken.toString()
}),
);
if (authVerifyResponse.statusCode != 200) {
throw ServerException();
}
return AuthVerifyModel.fromJson(jsonDecode(authVerifyResponse.body));
}
}

IOS notifications stop working until FCM token refresh

I have a live production AppStore App via flutter, IOS notifications work fine for a while (after the user performs a first login).
Then out of nowhere, they stop being displayed! Sometimes they go "missing" (example: maybe messages don't show, but another type of notification does show). Only when the user forces an FCM token refresh (via log out -> log in) do the notifications start working again...
What would cause the FCM token to "expire" on the APN side? And why does refreshing FCM token immediately fix the issue for the users? Using firebase_messaging: ^13.0.2
FCM code that works, just for a reference as to what I am doing in flutter:
sendNotificationV2(String token, String title, String body,
Map<String, dynamic>? payload) async {
var data_back = await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$SERVER_KEY',
},
body: jsonEncode(
<String, dynamic>{
'to': token,
'token': token,
'notification': <String, dynamic>{'body': body, 'title': title},
'priority': 'high',
'data': payload ?? <String, dynamic>{}
},
),
);
print("SENT NOTIFICATION FROM V2 METHOD, TOKEN: $token");
print(data_back);
print(data_back.body);
print(data_back.bodyBytes);
}

How to update row in a database table using http put request with id of the row?

I am trying to update my database table row using http put request in flutter web app.
My backend server working fine and able to put data on database using postman app. But unable to update data from my Flutter web app. How to Create Put Request and update the data using the id ofthe row.
Getting Below Error on browser_client.dart:
unawaited(xhr.onError.first.then((_) {
// Unfortunately, the underlying XMLHttpRequest API doesn't expose any
// specific information about the error itself.
completer.completeError(
ClientException('XMLHttpRequest error.', request.url),
StackTrace.current);
}));
I am trying below Api: id is row ID in the table. company, name, address, phone are updatable variables. Passing from TextEditfields from the flutter page.
Future<Company> updatedata(
id,
company,
name,
address,
phone,
) async {
Uri url =
Uri.parse("http://--link--/$id");
var response = await http.put(url);
print(response);
headers:
<String, String>{
'Content-Type': 'application/json; charset=UTF-8',
};
body:
jsonEncode(<String, String>{
"company": company,
"name": name,
"address": address,
"phone": phone,
});
if (response.statusCode == 200) {
return Company.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to update.');
}
}
The body and header details are placed outside the request. Make sure to include that along with the request.
var response = await http.put(url, headers:
<String, String>{
'Content-Type': 'application/json; charset=UTF-8',
}, body:
jsonEncode(<String, String>{
"company": company,
"name": name,
"address": address,
"phone": phone,
});
);

Why is it bad practice to use an FCM Server Key on a Flutter/Android client?

I'd like to send messages from my Flutter app using my Firebase Cloud Messaging (FCM) server key. But I'm told this is bad practice and should be done on the server-side. But as the code within APKs are invisible to users why is it a security problem?
void send() async {
await http.post(
'https://fcm.googleapis.com/fcm/send',
headers: <String, String>{
'Content-Type': 'application/json',
'Authorization': 'key=$serverToken',
},
body: jsonEncode(
<String, dynamic>{
'notification': <String, dynamic>{
'body': 'This is a body',
'title': 'Banana'
},
'priority': 'high',
'data': <String, dynamic>{
'audioid': '139',
'title': 'done all over time',
'name': 'Greengirl'
},
'to': '/topics/test_fcm_topic',
},
),
);
}
In general and not only regarding your specific question regarding FCM keys only, your code within the APK isn't normally visible to your average users. But your APK code is definitely not safe from whomever tries hard enough to find it and reverse engineer it.
Almost nothing is impossible to reverse engineer. I used 'almost' because I can't confirm and say 'everything'.
FCM is free, but it's not about the money. Imagine somebody has your token and can send messages on your behalf to anybody else of your users?
Emails are free to use in general, however, would you mind sharing it with anybody else?

How to read and write Data in Airtable with Flutter?

dependencies:
airtable: ^0.0.2
import 'package:airtable/airtable.dart'; ??
import 'package:dart_airtable/dart_airtable.dart'; ??
void main() async {
final apiKey = 'my-airtable-api-key'
final projectBase = 'my-airtable-project-base';
final recordName = 'Tasks';
var airtable = Airtable(apiKey: apiKey, projectBase: projectBase);
var records = await airtable.getAllRecords(recordName);
print(records);
}
If anyone knows how to solve it, I will be very grateful.
First of all, it seems like you mix two things together. Currently there are two packages that provide a library for the communication with airtable: airtable 0.0.2 and dart_airtable 0.1.1.
In your example code you use the import statement for the first package but the code from the second one. As the first one doesn't provide a valid link to a repository I'll have a look at the second one.
To retrieve records for a project from the API you can use this code:
var records = await airtable.getAllRecords(recordName);
Unfortunately the package has some bugs. As I wanted to create a record I used the method createRecord like this:
var test = await airtable.createRecord(
recordName,
AirtableRecord(
fields: [
AirtableRecordField(
fieldName: 'Short Description',
value: 'Test Description',
),
],
),
);
print(test);
But the only response I got was null. So I cloned the project and debugged the method. The result was this:
{"error":{"type":"INVALID_REQUEST_UNKNOWN","message":"Invalid request: parameter validation failed. Check your request data."}}
After a little bit of searching I found out that the package sends wrong data to the airtable API. In a toJson method of the AirtableRecord model, the author added the unnecessary fields id and createdTime. After deleting them, the method works.
Response:
AirtableRecord(id: rec9bqN78Le1dbC1g, createdTime: 2020-10-20 19:10:21.000Z, fields: {Short Description: Test Description})
I didn't look for the remaining methods, but my advice is to write your own connection to the airtime API or use the existing package and change the things that aren't working. Hopefully this helps you.
Edit:
I'll checked the repository again, and it seems that the author is inactive. As it only contains a few methods and models to work with the airtable API, I'll guess it's not a bad idea to just wrote your own implementation.
Here an simple example of how to do this (with Dio for the network connection):
try {
final response = await Dio().post(
'https://api.airtable.com/v0/$projectBase/$recordName',
options: Options(
contentType: 'Application/json',
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
data: {
'records': [
{
'fields': {
'Short Description': 'Cactus',
'Total': 11.5,
}
},
],
},
);
// TODO: Whatever you want to do with the response. A good practice is to transform it into models and than work with them
print(response);
} on DioError catch (e) {
// TODO: Error handling
if (e.response != null) {
print(e.response.data);
} else {
print(e.request);
print(e.message);
}
}
Response:
{"records":[{"id":"recrvxH93gJgAGo7j","fields":{"Short Description":"Cactus","Total":11.5},"createdTime":"2020-10-21T20:41:19.000Z"}]}
You could now extend this, maybe as a service with the GetIt package and add your required funtions. I definetly recommend to also use models for your response (have a look at this).
I used one of their example workspaces. The projectBase was an ID. You can just look at their API documentation to see how to build the requests.
Edit 2:
Read could be simple done by this:
final response = await Dio().get(
'https://api.airtable.com/v0/$projectBase/$recordName',
options: Options(
contentType: 'Application/json',
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
);
Update:
final response = await Dio().patch(
'https://api.airtable.com/v0/$projectBase/$recordName',
options: Options(
contentType: 'Application/json',
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
data: {
'records': [
{
'id': 'rechYkD0pDW1NjFAF',
'fields': {
'Short Description': 'Cactus II',
'Total': 11.5,
}
},
],
},
);
And delete:
final response = await Dio().delete(
'https://api.airtable.com/v0/$projectBase/$recordName/rec0bMv507juqS7pv',
options: Options(
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
);
These are only examples, I advice you to also read the API documentation to get a overview of what is possible. And your own implementation with proper error handling.
Edit 3:
You can use the filterByFormula parameter to retrieve all the data that matches your condition (Reference).
E.g.:
final response = await Dio().get(
'https://api.airtable.com/v0/$projectBase/$recordName',
queryParameters: {
'filterByFormula': 'SEARCH("Cactus",{Short Description})' // Searches the value 'Cactus' in the 'Short description' field.
},
options: Options(
headers: {
'Authorization': 'Bearer $yourApiKey',
'Accept': 'Application/json',
},
),
);