Flutter:如何使用 fcm 以编程方式发送推送通知

Posted

技术标签:

【中文标题】Flutter:如何使用 fcm 以编程方式发送推送通知【英文标题】:Flutter: How can i send push notification programmatically with fcm 【发布时间】:2019-06-20 03:52:09 【问题描述】:

我正在创建一个聊天应用程序,如果此人有新消息,我想使用 fcm 发送通知,但我不知道如何继续。我发现的所有教程都用于从 firebase 发送消息。但是我想在有新消息给这个人时自动发送它

【问题讨论】:

***.com/questions/37371990/… 还有Dart package 也可以发送通知。 如何用颤振发送这个? DATA='"notification": "body": "this is a body","title": "this is a title", "priority": "high", "data": "click_action": " FLUTTER_NOTIFICATION_CLICK", "id": "1", "status": "done", "to": ""' curl fcm.googleapis.com/fcm/send -H "Content-Type:application/json" -X POST -d "$DATA" -H "授权:key=" 您可以使用正常的休息 API 进行 FCM 通知。查看更多详情 - arkapp.medium.com/flutter-fcm-rest-api-7719925f2e3e 【参考方案1】:

我将在这里列出一些我参与的相关问题并提供答案。我想您会发现很多有关在聊天应用中使用 Firebase 云消息传递 (FCM) 的相关信息。

    Is FCM the only way to build a chat app ? Suggested approach to use FCM in a chat app Is using topics a better solution then using the fcmToken in a chat app? Problems with FCM onMessage while app is in background Problem: after logoff, user continues to receive notifications

祝你好运!

【讨论】:

【参考方案2】:

如果您使用 firebase,可能的解决方法应该是这样的:

您需要为特定用户存储每个 Firebase FCM 令牌(此处需要考虑到用户可以从多个设备同时登录其帐户),以便您可以存储 userId em> 和他的 deviceUniqueId on flutter 你可以从 device_info https://pub.dev/packages/device_info 获得它:

  String identifier;
  final DeviceInfoPlugin deviceInfoPlugin = new DeviceInfoPlugin();
  try 
    if (Platform.isandroid) 
      var build = await deviceInfoPlugin.androidInfo;
      identifier = build.id.toString();
     else if (Platform.isios) 
      var data = await deviceInfoPlugin.iosInfo;
      identifier = data.identifierForVendor;//UUID for iOS
    
   on PlatformException 
    print('Failed to get platform version');
  

然后要获取 Firebase 为每个设备提供的唯一 CFM 令牌,您可以使用 Firebase firebase_messaging 插件 (https://pub.dev/packages/firebase_messaging) getToken() 获取它并将令牌插入到 Firestore(或您要存储它的其他数据库)

  FirebaseMessaging firebaseMessaging = new FirebaseMessaging();

  firebaseMessaging.requestNotificationPermissions(
      const IosNotificationSettings(sound: true, badge: true, alert: true));
  firebaseMessaging.onIosSettingsRegistered
      .listen((IosNotificationSettings settings) 
    print("Settings registered: $settings");
  );

  firebaseMessaging.getToken().then((token)

    print('--- Firebase toke here ---');
    Firestore.instance.collection(constant.userID).document(identifier).setData( 'token': token);
    print(token);

  );

之后,您可以为一个用户插入一个或多个连接到多个设备的 FCM 令牌。 1 个用户……n 个设备,1 个设备……1 个唯一令牌,用于从 Firebase 获取推送通知。

当有新消息发送给该人时自动发送:现在您需要调用 Firestore API(确实非常快,但需要注意您在此处使用的计划限制) 或另一个 API 调用(如果您将令牌存储到另一个数据库),以便为每个用户获取令牌/令牌并发送推送通知。

要从 Flutter 发送推送通知,您可以使用 Future 异步函数。 Ps:我在这里传递一个 List 作为参数,以便使用 "registration_ids" 而不是 "to" 并将推送通知发送到多个令牌,如果用户已经在多个设备上登录。

Future<bool> callOnFcmApiSendPushNotifications(List <String> userToken) async 

  final postUrl = 'https://fcm.googleapis.com/fcm/send';
  final data = 
    "registration_ids" : userToken,
    "collapse_key" : "type_a",
    "notification" : 
      "title": 'NewTextTitle',
      "body" : 'NewTextBody',
    
  ;

  final headers = 
    'content-type': 'application/json',
    'Authorization': constant.firebaseTokenAPIFCM // 'key=YOUR_SERVER_KEY'
  ;

  final response = await http.post(postUrl,
      body: json.encode(data),
      encoding: Encoding.getByName('utf-8'),
      headers: headers);

  if (response.statusCode == 200) 
    // on success do sth
    print('test ok push CFM');
    return true;
   else 
    print(' CFM error');
    // on failure do sth
    return false;
  

您还可以检查邮递员的邮递电话以进行一些测试。 POST 请求 在标题上添加:

    key 授权 value key=AAAAO........ // 项目概览 -> 云消息传递 -> 服务器密钥 key Content-Type with value application/json

并在正文上添加


 "registration_ids" :[ "userUniqueToken1", "userUniqueToken2",... ],
 "collapse_key" : "type_a",
 "notification" : 
     "body" : "Test post",
     "title": "Push notifications E"
 

"registration_ids" 将其发送到多个令牌(同一用户同时登录多个设备) “to” 以便将其发送到单个令牌(每个用户一个设备/或始终更新与他的设备连接的用户令牌并具有 1 个令牌...1 个用户)

我正在对响应进行编辑,以便在受信任的环境或服务器上添加FCM 服务器密钥非常重要!

【讨论】:

firebaser here 在客户端代码中使用"key=your_server_key" 是一个严重的安全风险,因为它允许恶意用户向您的用户发送他们想要的任何消息。这是一种不好的做法,不应在生产级应用程序中使用。如需更好的方法,请参阅fireship.io/lessons/flutter-push-notifications-fcm-guide 和我的答案:***.com/a/57842615 是的,这个也是为了开发目的,就像上面的邮递员示例一样,我正在编辑答案,因为我也在服务器上设置了服务器密钥,当调用 API 时!跨度> 我们如何做到这一点'这里需要考虑到用户可以从多个设备同时登录他的帐户' 当您可以保存需要使用的元数据但确实可以使用另一个数据库时,我以使用 Cloud Firestore 为例。您可以在 Collection 上保存用户 ID,在每个 Document 上使用 device_info pub.dev/packages/device_info 在 Flutter 上的每个设备中唯一的设备 ID,您可以非常简单地获得该信息在 Collection 上,您可以存储 Firebase 令牌,以便在该设备上发送推送通知。这样,1 次使用可以有多个设备,每个设备将有一个令牌。抱歉迟到了 我的 firebase 项目中目前有 2 个 android 应用,如何指定通知与哪个应用相关?【参考方案3】:
    //Notification Sending Side Using Dio flutter Library to make http post request

        static Future<void> sendNotification(receiver,msg)async

        var token = await getToken(receiver);
        print('token : $token');

        final data = 
          "notification": "body": "Accept Ride Request", "title": "This is Ride Request",
          "priority": "high",
          "data": 
            "click_action": "FLUTTER_NOTIFICATION_CLICK",
            "id": "1",
            "status": "done"
          ,
          "to": "$token"
        ;

        final headers = 
          'content-type': 'application/json',
          'Authorization': 'key=AAAAY2mZqb4:APA91bH38d3b4mgc4YpVJ0eBgDez1jxEzCNTq1Re6sJQNZ2OJvyvlZJYx7ZASIrAj1DnSfVJL-29qsyPX6u8MyakmzlY-MRZeXOodkIdYoWgwvPVhNhJmfrTC6ZC2wG7lcmgXElA6E09'
        ;


        BaseOptions options = new BaseOptions(
          connectTimeout: 5000,
          receiveTimeout: 3000,
          headers: headers,
        );


        try 
          final response = await Dio(options).post(postUrl,
              data: data);

          if (response.statusCode == 200) 
            Fluttertoast.showToast(msg: 'Request Sent To Driver');
           else 
            print('notification sending failed');
            // on failure do sth
          
        
        catch(e)
          print('exception $e');
        




      

      static Future<String> getToken(userId)async

        final Firestore _db = Firestore.instance;

        var token;
        await _db.collection('users')
            .document(userId)
            .collection('tokens').getDocuments().then((snapshot)
              snapshot.documents.forEach((doc)
                token = doc.documentID;
              );
        );

        return token;


      


    //Now Receiving End 

        class _LoginPageState extends State<LoginPage>
        with SingleTickerProviderStateMixin 

      final Firestore _db = Firestore.instance;
      final FirebaseMessaging _fcm = FirebaseMessaging();

      StreamSubscription iosSubscription;



    //this code will go inside intiState function 

    if (Platform.isIOS) 
          iosSubscription = _fcm.onIosSettingsRegistered.listen((data) 
            // save the token  OR subscribe to a topic here
          );

          _fcm.requestNotificationPermissions(IosNotificationSettings());
        
        _fcm.configure(
          onMessage: (Map<String, dynamic> message) async 
            print("onMessage: $message");
            showDialog(
              context: context,
              builder: (context) => AlertDialog(
                content: ListTile(
                  title: Text(message['notification']['title']),
                  subtitle: Text(message['notification']['body']),
                ),
                actions: <Widget>[
                  FlatButton(
                    child: Text('Ok'),
                    onPressed: () => Navigator.of(context).pop(),
                  ),
                ],
              ),
            );
          ,
          onLaunch: (Map<String, dynamic> message) async 
            print("onLaunch: $message");
            // TODO optional
          ,
          onResume: (Map<String, dynamic> message) async 
            print("onResume: $message");
            // TODO optional
          ,
        );

//saving token while signing in or signing up
 _saveDeviceToken(uid) async 
    // FirebaseUser user = await _auth.currentUser();

    // Get the token for this device
    String fcmToken = await _fcm.getToken();

    // Save it to Firestore
    if (fcmToken != null) 
      var tokens = _db
          .collection('users')
          .document(uid)
          .collection('tokens')
          .document(fcmToken);

      await tokens.setData(
        'token': fcmToken,
        'createdAt': FieldValue.serverTimestamp(), // optional
        'platform': Platform.operatingSystem // optional
      );
    
  

【讨论】:

你的答案背景我理解,但代码不清楚。您使用了哪些 Firebase 组件。如果您可以在此页面中添加包含的文件并且还想知道您为什么使用 DIO 插件,那就更好了。

以上是关于Flutter:如何使用 fcm 以编程方式发送推送通知的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式发送 Firebase 云消息?

如何使用 FCM 和 Flutter(一个到另一个设备)发送推送通知?

Flutter FCM:在数据消息中发送documentSnapshot

currentuser 如何在flutter中通过fcm向另一个用户发送请求通知?

如何在接收基于 Flutter 构建的 FCM 推送通知时修复应用程序崩溃

有没有办法从flutter App内部发送FCM通知?