Невозможно получать push-уведомления FCM, используя функцию Firebase

#firebase #flutter #google-cloud-functions #firebase-cloud-messaging

#firebase #flutter #google-cloud-функции #firebase-облако-обмен сообщениями

Вопрос:

У меня было некоторое время с момента push-уведомления, когда я работал над своим приложением, у меня есть коллекция Firestore, которая при создании новых документов запускает функцию sendNotification.

Раньше функция выглядела так:

 export const sendChatNotification = functions.firestore.document('chatrooms/{chatroomId}/chats/{chatId}').onCreate(async (snap, ctx) => {

    //In Comment OLD Way to get info data for the notification
    const token = snap.get('sendToDeviceToken'); //snap.data().sendToDeviceToken;
    const sender = snap.get('fullSenderName'); //snap.data().fullSenderName;
    const body = snap.get('message'); //snap.data().message;

const payload = {
       notification: {
            title: sender,
             body: body,
        }
     };

return admin.messaging().sendToDevice(token, payload).then(response => {
        console.log('Message Function Executed sent to device with token: '   token   ' from sender: '   sender   ' with message: '   body );
    });
}
 

Это немного поработало, но перестало работать, хотя во всех журналах указано, что оно завершается со статусом ok.

В журнале нет ошибок

Теперь мой коллега сказал мне, что ему пришлось изменить этот код для новой функции, которая выглядит следующим образом:

 export const sendChatNotification = functions.firestore.document('chatrooms/{chatroomId}/chats/{chatId}').onCreate(async (snap, ctx) => {

    //In Comment OLD Way to get info data for the notification
    const token = snap.get('sendToDeviceToken'); //snap.data().sendToDeviceToken;
    const sender = snap.get('fullSenderName'); //snap.data().fullSenderName;
    const body = snap.get('message'); //snap.data().message;


    var tokens  = [];

    tokens.push(token)

    const payload = {
        notification: {
            title: sender,
            body: body,
        },
        android: {
            notification: {
                channelId: "roofdeck_default",
                click_action: 'FLUTTER_NOTIFICATION_CLICK',
                title: sender,
                body: body,
            }
        },
        apns: {
            headers: {
                "apns-push-type": "alert"
            },
            payload: {
                aps: {
                    category: "FLUTTER_NOTIFICATION_CLICK"
                }
            },
        },
        data: {
            postID: snap.id,
            type: "POST_TAG",
        },
        tokens: token
    }

    if (token.length > 0) {
        await fcm.sendMulticast(payload);
    }

});
 

Для полноты мы добавили эту строку кода после инициализации приложения:

 const fcm = admin.messaging();
 

Он также упомянул, что для этого ему пришлось создать канал для Android, поэтому я последовал руководству и изменил свой Main в приложении Flutter:

 const AndroidNotificationChannel channel = AndroidNotificationChannel(
  'roofdeck_default',
  'RoofDeck Notification Channel',
  description: 'This Channel is for RoofDeck Chat Notifications',
  importance: Importance.high,
  playSound: true,
);

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  print('A Background Message just showed up: ${message.messageId}');
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(channel);

  await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
    alert: true,
    badge: true,
    sound: true,
  );

  runApp(MyApp());
}
 

И на начальном экране я добавляю этот код в Init, чтобы он работал:

 @override
  void initState() {
    //_isIos = Platform.isIOS;
    fbm.requestPermission();
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('En OnMessage: ${message.notification.body.toString()}');
      RemoteNotification notification = message.notification;
      AndroidNotification android = message.notification?.android;
      if (notification != null amp;amp; android != null) {
        flutterLocalNotificationsPlugin.show(
          notification.hashCode,
          notification.title,
          notification.body,
          NotificationDetails(
            android: AndroidNotificationDetails(
              channel.id,
              channel.name,
              channelDescription: channel.description,
              color: Colors.blue,
              playSound: true,
              icon: '@mipmap/ic_launcher',
            ),
          ),
        );
      }
      //return;
    });
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('A new onMessageOpenedApp event was published!');
      print('En onMessageOpenedApp: ${message.notification.body.toString()}');
      RemoteNotification notification = message.notification;
      AndroidNotification android = message.notification?.android;
      if (notification != null amp;amp; android != null) {
        showDialog(
            context: context,
            builder: (_) {
              return AlertDialog(
                title: Text(notification.title),
                content: SingleChildScrollView(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(notification.body),
                    ],
                  ),
                ),
              );
            });
      }

      //return;
    });
    _saveToken();
    super.initState();
  }
 

Наконец, чтобы сгенерировать последний токен, я сохраняю токен в Firestore:

 Future<void> _saveToken() async {
    try {
      token = await fbm.getToken();
      var user = FirebaseAuth.instance.currentUser;
      if (token != null amp;amp; user != null) {
        FirebaseFirestore.instance.collection('users').doc(user.uid).update({
          'token': token,
          'tokenCreatedAt': DateTime.now(),
          'platform': Platform.operatingSystem,
        });
      }
    } catch (e) {
      print("Messaging(_saveToken): $e");
    }
  }
 

Я попробовал на устройстве iPhone, и через 2 часа уведомление по-прежнему не получено, хотя я вижу, что журналы новой облачной функции работают правильно.

Работает новый код

Любые идеи, что не так, почему, по крайней мере, на iPhone не работают уведомления.

С уважением,

Комментарии:

1. Используете ли вы эмулятор iOS, если он не будет работать, кроме того, для iOS вам необходимо настроить службы APN от Apple с помощью firebase и использовать токен apn для отправки уведомления

2. Где я могу получить APN? Извините

3. Для iOS вы можете обратиться к этой странице firebase.flutter.dev/ docs/ messaging / apple-интеграция , она довольно длинная, поэтому я не могу дать вам подробную информацию в комментарии.