使用 SignalR 的 Flutter 推送通知

Flutter Push Notification using SignalR

我在我的 Flutter 应用程序上使用 SignalR 推送通知,效果很好。我从后端获取消息并使用 flutter_local_notifications 显示通知。问题是 SignalR 服务会在一段时间后关闭。 如何让我的应用程序在后台运行?甚至在重启时开始?

这是我的代码:

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:isolate_test/Model/UserMessageModel.dart';
import 'package:signalr_core/signalr_core.dart';
import 'EndPointService.dart';
import 'NotificationService.dart';

class SignalRProvider {
  static String appName = "NOTIFICATION";
  static String? userName = "";
  static String deviceName = "android_app";
  static List<UserMessageModel> messages = <UserMessageModel>[];

  HubConnection connection = HubConnectionBuilder()
      .withUrl(
          'my_url',
          HttpConnectionOptions(
            logging: (level, message) => print(message),
          ))
      .withAutomaticReconnect()
      .withHubProtocol(JsonHubProtocol())
      .build();
  Function(bool update)? onMessagesUpdateCallback;
  SignalRProvider({
    this.onMessagesUpdateCallback,
  });

  setUsername(String username) {
    userName = username;
  }

  Future initSignalR(BuildContext context) async {
    WidgetsFlutterBinding.ensureInitialized();
    await NotificationService().init();
    connection.on('SignalRUserReceiveMessage', (message) async {
      var data = message!.first;
      if (data != null) {
        UserMessageModel msg = UserMessageModel.fromJson(data);
        messages.add(msg);
        msg.showNotification();
      }
      if (onMessagesUpdateCallback != null) {
        onMessagesUpdateCallback!(true);
      }
    });

    connection.on('SignalRMonitoringMessage', (message) async {
      var data = message!.first;
      if (data != null) {
        UserMessageModel msg = UserMessageModel.fromJson(data);
        messages.add(msg);
        msg.showNotification();
      }
      if (onMessagesUpdateCallback != null) {
        onMessagesUpdateCallback!(true);
      }
    });

    connection.on("SignalRReceiveConnectedMessage", (message) async {
      await connection.send(methodName: 'SignalRInit', args: [
        userName,
        appName,
        connection.connectionId,
      ]);
    });
    connection.on("SignalRReceiveDisconnectedMessage", (message) async {
      if (connection.state == HubConnectionState.disconnected) {
        connection.start();
      }
    });
    await connection.start();
  }

  List<UserMessageModel> getMessages() {
    return messages;
  }

  Future deleteMessage(UserMessageModel _msg) async {
    if (_msg == null) return;
    var response =
        await EndPointService().SetupApi("Message", "", []).httpDelete(
      HeaderEnum.BasicHeaderEnum,
      ResponseEnum.ResponseModelEnum,
      jsonEncode(_msg),
    );
  }

  addOrUpdateMessage(UserMessageModel _msg) {
    if (_msg == null) return;
    if (messages != null) {
      var found =
          messages.firstWhere((e) => e.user == _msg.user && e.id == _msg.id);
      var index =
          messages.indexWhere((e) => e.user == _msg.user && e.id == _msg.id);
      if (found != null) {
        messages[index] = _msg;
      } else {
        messages.add(_msg);
      }
      if (onMessagesUpdateCallback != null) {
        onMessagesUpdateCallback!(true);
      }
    }
  }

  setMessagesUpdateCallback(Function(bool update) func) {
    onMessagesUpdateCallback = func;
  }
}

SignalR 问题

SignalR for Flutter 使用网络套接字和 SSE 接收来自 SignalR service 的消息。如果应用程序因用户重新启动 phone 或 OS 关闭应用程序以节省电量而终止,则这些推送通知将 不会被应用程序接收 .

为了克服这个问题,应用程序开发人员(和 SignalR)必须在 Android 上使用 FCM,在 iOS 上使用 APN(或者 FCM 也会在 iOS 上使用 APN)。所有其他方法将受到更多限制,因为操作系统不允许用户一直保持后台进程 运行。这实际上在几年前就被允许了,但是操作系统已经做出这些更改以节省用户电量——它们强制所有应用程序通过相同的推送通知媒介——Android 上的 FCM,iOS 上的 APNs。

Flutter 的 SignalR 既不使用 FCM 也不使用 APNs。在目前的状态下,SignalR 不太适合 Android 或 iOS - 请查看与您在 .

上遇到类似问题的人的评论

备选方案

最简单/最简单的入门方法是使用Firebase Cloud Messaging

  • 在Android上,它将直接用于向设备发送消息,并且
  • 在 iOS,FCM 将使用 APN 可靠地访问设备

警告: 在 Android 上,有一个更复杂的替代方案,称为 unifiedpush,但限制包括向用户显示通知 随时处理后台通知。

我的分析: 这一切都是基于我通过阅读 pubspec.yaml, the GitHub issues on the original repo, the SignalR documentation 的快速调查和一些实现 Flutter 推送通知的经验完成的。

披露: 我刚刚在 2 天前发布了一个名为 push which would be well suited to these types of Push Notification packages making the transformation to using FCM on Android and APNs on iOS. However, as an app developer, in most cases, you should use firebase_messaging, not push.

的推送通知库

我使用 SignalR,但在原生平台上(IOS & Android),我制作了股票应用程序并获得实时价格。当应用程序进入后台时,我会在 5 秒后断开与 SignalR 服务器的连接,当应用程序再次进入前台时,我会检查应用程序的当前状态是否未连接到服务器 SignalR,我会再次连接。我认为如果您的应用程序仍然在后台状态下连接并从 signalR 服务器接收数据是不好的。