My goal is to send FCM messages to multiple tokens contained in a document map using flutter. The current code uses the 'send all' function and it sends to all as expected. I'm hoping that inserting a widget.document.[token], or similar reference will send only to all those items contained in the document/list. Firebase uses sendAll to send to specific devices so I was hoping this would work.
using document(token) reference returns no errors but also no messages
using a snapshot that contains only tokens returns an error that only static items can be passed, along with some syntax problems
using api/http returns error posturl returns null
In addition to trying the above i've also researched what others have tried.
functions/index.ts, this is designed for mulitple tokens for single user
push list programmatically yielded some syntax errors, and post url null
Here are some of my errors:
Tried calling:
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The method '[]' was called on null.
Tried calling: post("https://fcm.googleapis.com/fcm/send", body: "{\"token\":null,
This is a picture of my database structure:
Finally, here is my code:
import 'package:chat/screens2/alert_widget.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:geo_firestore/geo_firestore.dart';
import 'package:geolocator/geolocator.dart';
import 'package:chat/api/messaging.dart';
import 'package:chat/models/messages.dart';
import 'package:flutter/widgets.dart';
class SendAlert extends StatefulWidget {
static const String id = 'send_alert';
final Message message;
final url;
final body;
final title;
final image;
final content;
SendAlert({
Key key,
this.title,
this.url,
this.body,
this.message,
this.image,
this.content,
String alertIdd,
}) : super(key: key);
get documents => null;
SendAlertState createState() => SendAlertState();
}
Firestore firestore = Firestore.instance;
GeoFirestore geoFirestore = GeoFirestore(firestore.collection('users'));
class SendAlertState extends State<SendAlert> {
FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
TextEditingController roomnameController = TextEditingController();
final TextEditingController titleController = TextEditingController();
final TextEditingController bodyController = TextEditingController();
final List<Message> messages = [];
TextEditingController citystateController = TextEditingController();
final db = Firestore.instance;
get title => null;
get body => null;
get uid => null;
get alertidd => null;
var currentLocation;
var clients = [];
List<Map<String, dynamic>> _documents;
void onBbackPressed(BuildContext context) => Navigator.pop(context);
@override
void initState() {
super.initState();
populateClientu();
Geolocator().getCurrentPosition().then((currloc) {
setState(() {
currentLocation = currloc;
});
});
_firebaseMessaging.onTokenRefresh.listen(sendTokenToServer);
_firebaseMessaging.getToken();
_firebaseMessaging.subscribeToTopic('all');
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
final notification = message['notification'];
setState(() {
messages.add(Message(
title: notification['title'], body: notification['body']));
});
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
final notification = message['data'];
setState(() {
messages.add(Message(
title: '${notification['title']}',
body: '${notification['body']}',
));
});
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
},
);
_firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(sound: true, badge: true, alert: true));
}
populateClientu() async {
Position position = await Geolocator()
.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
var queryLocation = GeoPoint(position.latitude, position.longitude);
List<DocumentSnapshot> snapshots =
await geoFirestore.getAtLocation(queryLocation, 10.0);
final documents = snapshots.map((doc) {
return doc.data;
}).toList();
setState(() {
_documents = documents;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color.fromARGB(255, 4, 22, 36),
title: Text('SEND MSG'),
leading: IconButton(
onPressed: () => this.onBbackPressed(context),
icon: Icon(Icons.arrow_back),
),
),
backgroundColor: Color.fromARGB(255, 4, 22, 36),
body:
Container(
width: 250,
height: 35,
margin: EdgeInsets.only(top: 4),
child: Opacity(
opacity: 0.8,
child: FlatButton(
color: Color.fromARGB(51, 255, 255, 255),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
side: BorderSide(
width: 0.75,
color: Color.fromARGB(255, 255, 255, 255),
style: BorderStyle.solid,
),
),
textColor: Color.fromARGB(255, 255, 255, 255),
padding: EdgeInsets.all(0),
child: Text(
"SEND ALERT",
style: TextStyle(
fontSize: 12,
letterSpacing: 2,
fontFamily: "Roboto",
fontWeight: FontWeight.w500,
),
textAlign: TextAlign.left,
),
onPressed: () async {
// const querySnapshot = await db <--- I suspect the document map has extra unused data. I thought maybe FCM will only accept and array of tokens, this did not work either.
// .collection('users')
// .document()
// .collection('token')
// .get();
sendNotification();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AlertWidget()));
})))
);
}
void sendTokenToServer(String fcmToken) {
print('Token: $fcmToken');
}
Future sendNotification() async {
//Future sendNotification(documents(token)) async { <--- I tried to pass widget.document[token]
final response = await Messaging.sendToAll(
title: titleController.text,
body: bodyController.text,
);
if (response.statusCode != 200) {
Scaffold.of(context).showSnackBar(SnackBar(
content:
Text('[${response.statusCode}] Error message: ${response.body}'),
));
}
}
}
Of course thank you all in advance for your time.