I send a message to the user via await client.send_message(entity, message)
how can i delete this message?
it's not work
mes= await client.send_message(entity, message)
client.delete_message(mes.id)
This should work:
mes = await client.send_message(entity, message)
await mes.delete()
Related
I am working on a flutter app where after sign-in, I have to validate a user's idToken on a custom backend (written in Go) using the Firebase admin SDK: firebase.google.com/go.
I am using the following snippet to sign-in the user via GoogleSignIn and retrieve the Firebase idToken on the client side:
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
Future<String> signInWithGoogle() async {
await Firebase.initializeApp();
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final UserCredential authResult = await _auth.signInWithCredential(credential);
final User user = authResult.user;
String FirebaseIdToken = await _auth.currentUser.getIdToken();
print("FirebaseIdToken: " + FirebaseIdToken);
if (user != null) {
/* code to validate user and return it */
} return null;
}
I copy the token corresponding to the FirebaseIdToken variable and send it to the backend using Postman with a Authentication: Bearer <token> request header.
At the backend, there is the following:
/* am.cli here is basically the auth.Client in firebase admin SDK and clientToken is the token received from flutter app. */
idToken, err := am.cli.VerifyIDToken(context.Background(), clientToken)
log.Println("ERROR:", err)
I get the following error printed:
ERROR: failed to verify token signature
Based on the documentation for both client & backend, I believe that I'm using the correct methods to retrieve and to verify the token.
I have tried to retrieve the idToken with the following code as well:
IdTokenResult idTokRes = await _auth.currentUser.getIdTokenResult(true);
print("idTokRes: " + idTokRes.token);
But this fails the same way. (And idTokRes.token and the FirebaseIdToken from the previous method are not same.)
I have also tried to verify the token manually on https://jwt.io/ with the public certificate and the private key which fails as well.
Any help would be appreciated!
Thanks to a member of the Flutter community, I was able to solve the problem.
Turns out, for some reason, the FirebaseIdToken printed by
print("FirebaseIdToken: " + FirebaseIdToken);
is not the complete token. Because of being large, the output gets truncated.
(Still not sure why though. Does Dart's print() statement truncate large strings?)
Edit: Apparently, its the terminal window that truncates/wraps a large output by embedding linebreaks to it.
But, by using the following snippet
String firebaseIdToken = await user.getIdToken();
while (firebaseIdToken.length > 0) {
int startTokenLength =
(firebaseIdToken.length >= 500 ? 500 : firebaseIdToken.length);
print("TokenPart: " + firebaseIdToken.substring(0, startTokenLength));
int lastTokenLength = firebaseIdToken.length;
firebaseIdToken =
firebaseIdToken.substring(startTokenLength, lastTokenLength);
}
I was able to print the complete token in 3 broken parts, which I then concatenated, and sent to the backend via Postman and got no errors this time.
Thanks Rexford!
I am trying to send push notification from my php application to my flutter apps via Firebase messaging service. while I start the emulator it receives a token from firebase, then i copy that token and can send message. But I want to store that token to my mysql database once i receive the token. I have 2 scenario. For the first time if user install the apps, i'll insert the token to my database so that i can send message using that token. Now I am confused how to update that token every time the user login(not inserting new token again and again to database).
void setupNotification() async{
_firebaseMessaging.
_firebaseMessaging.getToken().then((token){
//insert the token to user database
saveToken(token);
});
Stream<String> fcmStream = _firebaseMessaging.onTokenRefresh;
fcmStream.listen((token) {
//always update the user database with new token
saveToken(token);
});
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async{
print("message while app is open: $message");
},
onResume: (Map<String, dynamic> message) async{
print("message: $message");
},
onLaunch: (Map<String, dynamic> message) async{
print("message: $message");
}
);
}
I mean how to identify that the token is new or old(updated) ?
You need to create a Locally stored json file in your app using path_provider plugin.This file will get initialized everytime user opens the app and will contain a user Model containing token of user.On the very first page of the app in initState check if the user is not null.
IF NULL:
Get fcm token and store it in database.After storing it in database write the token in your Locally stored file.
ELSE:
Do nothing
Next time when same user opens the app again in initstate it will check if user is not null.This time it will not add a new token in database as our code to insert token into database won't execute.
Example:
We will store user as follows.
class User {
String token;
String platform;
User({
this.token = '',
this.platform = '',
});
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['token'] = this.token;
data['platform'] = this.platform;
return data;
}
User.fromJson(Map<String, dynamic> json): this(
platform: json["platform"],
token: json["token"],
);
}
Local Data file:
class LocalData {
static User _user;
static User get user => _user;
/// Flag for Authentication.
static bool get isTokenAdded=> _user != null;
static loadData() async {
final file = File((await getApplicationDocumentsDirectory()).path + '/data.json');
try {
final data = jsonDecode(await file.readAsString());
_user = User.fromJson(data['user']);
} catch (e) {
print(e);
}
}
static writeData() async {
final file = File((await getApplicationDocumentsDirectory()).path + '/data.json');
await file.writeAsString(jsonEncode({
'user': _user?.toJson(),
}));
}
static void addToken(User user) {
LocalData._user = user;
writeData();
}
static void removeToken() {
LocalData._user = null;
writeData();
}
}
App's main function:
void main() async {
/// Load Local Data.
WidgetsFlutterBinding.ensureInitialized();
await LocalData.loadData();
runApp(YourApp());
}
Now in initState of your apps first page you can check if token is already added in database by
if(LocalData.isTokenAdded()){
//do nothing
}else{
//get token and insert it into database then write it in file:
LocalData.user.token = token;
LocalData.writeData();
}
I have implemented firebase otp in my flutter application
When I install the app on my device and requested for the same number on that deice it does not send me the message. But when I change the number it send the message
So I changed the device and tried to send the previous number, it sent message successfully. Then I used the number on second device and it did not send the message
* When I use the same number on the device it does not send the OTP
Here is the code for sending the otp
Future<void> verifyPhone() async {
final PhoneCodeAutoRetrievalTimeout autoRetrieve = (String verID) {
this.verificationId = verID;
};
final PhoneCodeSent smsCodeSent = (String verId, [int forceCodeResend]) {
this.verificationId = verId;
};
final PhoneVerificationCompleted verifiedSuccess =
(AuthCredential phoneAuthCredential) {
print('verified');
};
final PhoneVerificationFailed verifyFailed = (AuthException exception) {
print('${exception.message}');
};
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: widget.phone,
timeout: const Duration(seconds: 5),
verificationCompleted: verifiedSuccess,
verificationFailed: verifyFailed,
codeSent: smsCodeSent,
codeAutoRetrievalTimeout: autoRetrieve);
log("OTP sent");
}
This is the code for verifying the OTP
signIn() async{
final AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: enteredOtp,
);
await FirebaseAuth.instance.signInWithCredential(credential).then((user) {
//SOME CODE HERE
}).catchError((e) {
showAlert(
context: context,
title: "Empty or Invalid OTP",
);
log("Invalid OTP");
});
}
What's wrong in here? How do I fix this and get the otp for the same number in device.
Actually in point of fact, I believe that's actually expected, and intended usage. (Or close to it) as if Firebase can confirm phone identity via push notifications, it doesn't even send the text, as it's already verified. (Usually only happens if it's verified the phone once). But if you're sending it to a phone number other than the phone number the device is connecting to, then it can't use the previous verificationID in the system.
So I would suggest checking to see which parts of the code function and not. Check to see if the code and authorization fails, or if it will continue to the next part of the program fully authorized. Add some print statements in there just to make sure. But I'm pretty sure that should be the way it works.
I am using shared preferences to store the token, email, username and other user details when a user logs in using firebase authentication. The firebase token expires in every one hour so I need to refresh the token on the basis of when the user has returned to the app which I am doing in getCurrentUser() function below. I want to know that if a user has logged in my app, used it for 5 minutes or so and then close the application, will that timer function would still be listening and call the function after the timeout or not?
If it doesn't do so then How can I achieve checking this?
void checkTokenValidity(int time) {
Timer(Duration(seconds: time), () async {
print('token timed out');
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('token', 'expired');
prefs.remove("currentUser");
});
}
Future<String> getCurrentUser() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String currentToken = prefs.getString('token');
final String cuser = prefs.getString('currentUser');
print("current: $cuser");
if (cuser != null && currentToken != 'expired') {
print('signed in and $currentToken');
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token');
String uid = prefs.getString('userId');
String email = prefs.getString('userEmail');
String photo = prefs.getString('photo');
_authenticatedUser =
User(email: email, id: uid, token: token, photo: photo);
return 'success';
} else if (currentToken == 'expired') {
print('token is expired');
final FirebaseUser user = await FirebaseAuth.instance.signInAnonymously();
var token = await user.getIdToken();
prefs.setString('token', token);
String uid = prefs.getString('userId');
String email = prefs.getString('userEmail');
String photo = prefs.getString('photo');
_authenticatedUser =
User(id: uid, email: email, token: token, photo: photo);
checkTokenValidity(3600);
return 'token';
} else {
print('user is null');
return null;
}
}
In my authentication function which is not here, I have called checkTokenValidity(3600) just after the user successfully logs in.
I have also tried using FirebaseUser user = await FirebaseAuth.instance.currentUser(); but that also didn't solve the problem.
You went the wrong way. The right way is to add error handler on 401 (Unauthorized) error and handle it by refreshing token and retrying the same query.
I have a Flutter app that uses Firebase messaging to delivery notifications.
This is the base code, it does nothing special, besides saving the token on my DB.
FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) {
},
onResume: (Map<String, dynamic> message) {
},
onLaunch: (Map<String, dynamic> message) {
},
);
_firebaseMessaging.getToken().then((token) {
saveToken(token);
});
Do I have to implement some kind of background service to keep saving the new token on my DB everytime it gets refreshed? I remember using onTokenRefresh() on Android(JAVA) to do this, but I found nothing about it in Flutter (DART).
I read somewhere that the token gets refreshed every 3600 seconds. I wonder if this is true.
No, FCM token doesn't refresh every 3600 seconds. It only refreshes when :
When user Uninstall/Reinstall the app or Clears App Data
You manually delete FCM Instance using FirebaseMessaging().deleteInstanceID()
You can listen to token refresh stream using:
FirebaseMessaging().onTokenRefresh.listen((newToken) {
// Save newToken
});
Hope it helps
You can use firebaseMessaging.onTokenRefresh to get a stream which receives an event each time a new token is received.
Here is an example of subscribing to the firebaseMessaging.onTokenRefresh stream and updating the token if the token has changed:
FirebaseMessaging().onTokenRefresh.listen((token) async {
final prefs = await SharedPreferences.getInstance();
final String firebaseTokenPrefKey = 'firebaseToken';
final String currentToken = prefs.getString(firebaseTokenPrefKey);
if (currentToken != token) {
print('token refresh: ' + token);
// add code here to do something with the updated token
await prefs.setString(firebaseTokenPrefKey, token);
}
});
You can try with this.. as per new updation
FirebaseMessaging.instance.onTokenRefresh.listen((newToken) {
// Save newToken
});
After the user logs in my app logs her in again automatically every 3500 seconds.
I used a Timer like this:
void _timerPressed() {
const timeout = const Duration(seconds: 3500);
new Timer.periodic(timeout, (Timer t) => _handleSignIn());
}
I set the timer in the 'login' button press method after the login has occurred:
void _loginPressed() {
print('The user wants to login with $_email and $_password');
_handleSignIn()
.then((FirebaseUser user) => print(user))
.catchError((e) => print(e));
_timerPressed();
}
(Don't be fooled by the name of the method, '_timerPressed'. I used a button press for testing the technique and haven't gotten around to renaming the method after I tied it in to the login button.)