FCM 到多个设备(令牌)列表
Posted
技术标签:
【中文标题】FCM 到多个设备(令牌)列表【英文标题】:FCM to multiple devices (tokens) list 【发布时间】:2020-05-01 03:51:40 【问题描述】:我的目标是使用颤振将 FCM 消息发送到文档映射中包含的多个令牌。当前代码使用“全部发送”功能,并按预期发送给所有人。我希望插入一个widget.document.[token] 或类似的引用将只发送到文档/列表中包含的所有项目。 Firebase uses sendAll to send to specific devices so I was hoping this would work.
使用文档(令牌)引用不会返回错误,但也不会返回任何消息
使用仅包含令牌的快照会返回一个错误,仅 可以传递静态项,还有一些语法问题
使用 api/http 返回错误 posturl 返回 null
除了尝试上述方法之外,我还研究了其他人尝试过的方法。
functions/index.ts, this is designed for mulitple tokens for single user
push list programmatically yielded some syntax errors, and post url null
以下是我的一些错误:
尝试调用:
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] 未处理的异常:NoSuchMethodError:方法 '[]' 在 null 上被调用。
尝试调用:post("https://fcm.googleapis.com/fcm/send", body: "\"token\":null,
这是我的数据库结构的图片:
最后,这是我的代码:
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'),
));
当然,提前感谢大家的宝贵时间。
【问题讨论】:
不太清楚您要解决的问题是什么。您是否尝试向部分用户发送推送通知?您是否希望 Flutter 应用程序发送这些推送通知(不推荐,因为一些安全原因很容易导致您的整个数据库受到损害)?如果是这样,您需要从用户列表中获取令牌列表,然后将其发布到 FCM API。那么你在哪一部分遇到了困难? i gps 并生成用户的文档地图。该文档来自图片中的数据库。所以我使用geoHash到gps,在这种情况下我会得到2个用户。我只想向这两个用户发送 gps。在更大的范围内可能有 100 个用户,但只有 8 个在 gps 过滤范围内,所以我只想发送给这 8 个用户/令牌。你提到了从颤振发送的安全问题,这就是我试图做的,类似于发送所有。我不知道如何使用api发送我目前拥有的文档图。我确实尝试了该 api,但没有成功。 您可以将令牌存储在firestore中并使用firebase功能。检查这个skcript.com/svr/… 我正在尝试firebase函数方法。 @vic 嗨,你能找到答案吗?我正在尝试做类似的事情。创建文档后,我需要按位置过滤用户并向这些用户发送通知。谢谢! 【参考方案1】:-
您的 firestore 实例返回用户文档列表。您需要遍历文档以仅提取文档中的标记并将它们放入字符串列表中,然后将其传递给 FCM。
如果您比较您的屏幕截图和应该返回文档的代码。他们不对齐。你可以改变它。
// 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();
到
// 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("DOCUMENT ID")
// .get();
上面会得到一个文件。然后,您可以映射文档并获取单个令牌,您可以将其传递到消息组件的令牌字段中。
您还没有将令牌传递给实际的异步函数 Messaging.sendToAll
最终响应 = 等待 Messaging.sendToAll( 标题:titleController.text, 正文:bodyController.text, );
上面应该在正文中包含一个标记字符串,如下所示。
final response = await Messaging.sendToAll(
title: titleController.text,
body: bodyController.text,
token:fcmTokenReturnedFromFirestore
);
【讨论】:
这是否允许从具有多个令牌的文档发送多个令牌,还是我必须多次发送?以上是关于FCM 到多个设备(令牌)列表的主要内容,如果未能解决你的问题,请参考以下文章
推送通知的 Amazon SNS android 设备令牌限制