FCM 到多个设备(令牌)列表

v i*_*i c 6 firebase flutter firebase-cloud-messaging

我的目标是使用 flutter 将 FCM 消息发送到包含在文档映射中的多个令牌。当前代码使用“全部发送”功能,并按预期发送给所有人。我希望插入一个 widget.document.[token] 或类似的参考将只发送到文档/列表中包含的所有项目。 Firebase 使用 sendAll 发送到特定设备,所以我希望这能奏效。

  • 使用文档(令牌)引用不会返回错误,但也不会返回消息

  • 使用仅包含令牌的快照会返回一个错误,即只能传递静态项目,以及一些语法问题

  • 使用 api/http 返回错误 posturl 返回 null

除了尝试上述方法外,我还研究了其他人尝试过的方法。

以下是我的一些错误:

  • 尝试调用:

  • [错误:flutter/lib/ui/ui_dart_state.cc(157)] 未处理的异常:NoSuchMethodError:方法 '[]' 在 null 上被调用。

  • 尝试调用: post(" https://fcm.googleapis.com/fcm/send ", body: "{\"token\":null,

这是我的数据库结构的图片:

Firebase 数据库结构

最后,这是我的代码:

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}'),
      ));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

当然,提前感谢大家的时间。

小智 0

  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();
Run Code Online (Sandbox Code Playgroud)

  //                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();
Run Code Online (Sandbox Code Playgroud)

以上将得到一个文档。然后,您可以映射文档并获取单个令牌,您可以将其传递到消息组件的令牌字段中。

  1. 您尚未将令牌传递到实际的异步函数 Messaging.sendToAll 中

    最终响应=等待Messaging.sendToAll(标题:titleController.text,正文:bodyController.text,);

上面的内容应该在正文中包含一个令牌字符串,如下所示。

final response = await Messaging.sendToAll(
      title: titleController.text,
      body: bodyController.text,
      token:fcmTokenReturnedFromFirestore
    );
Run Code Online (Sandbox Code Playgroud)