OneSignal / OneSignal-Flutter-SDK

OneSignal is a free push notification service for mobile apps. This plugin makes it easy to integrate your flutter app with OneSignal
https://www.onesignal.com
Other
623 stars 213 forks source link

getInitialMessage like FirebaseMessaging #576

Open darwin-morocho opened 2 years ago

darwin-morocho commented 2 years ago

Description: With Firebase when the app is closes and then we got a push notification we can use getInitialMessage() to check if the app was opened by clicking in a push.

like this

    /// check if we have a initial message
    final RemoteMessage? message = await messaging.getInitialMessage();

But with onesignal we have to use

OneSignal.shared.setNotificationOpenedHandler((OSNotificationOpenedResult result) {
  // Will be called whenever a notification is opened/button pressed.
});

The above code is not a good solution because if the app was closed and opened without a push that code never won't be executed. A posible solution could be using a timer and if the above code is not executed after some milliseconds we can asume that the app was not opened using a push notification but that is not a good solution too.

  Timer? _initialNotificationTimer;
final _completer = Completer<AppNotification?>();

 oneSignal.setNotificationOpenedHandler(
      (result) async {

        if (!_completer.isCompleted) {
          _initialNotificationTimer?.cancel();
          _completer.complete(result.notification);
        }
      },
    );

  Future<OSNotification?> get initialNotification async {
    await _initCompleter.future;
    _initialNotificationTimer = Timer(
      const Duration(milliseconds:500),
      () {
        if (!_completer.isCompleted) {
          _completer.complete(null);
        }
      },
    );
    return _completer.future;
  }

The above code Only works on Android

Environment onesignal_flutter: ^3.3.1

Is there a method like getInitialMessage() In OneSignal with flutter ?

emawby commented 2 years ago

@darwin-morocho We don't have anything like that right now, but we will investigate adding something similar

hassanyasin1020 commented 1 year ago

Hi @darwin-morocho I'm experiencing the same issue. I need to navigate in the terminated state but cannot find any alternative to getInitialMessage for OneSignal.

Have you figured out a way to handle this with OneSignal? Any help would be appreciated.

jkalebe commented 6 months ago

Hello guys

I am working on a Flutter project where I need to handle notifications using OneSignal. The app needs to open a specific status screen when a notification is clicked, but this isn't working when the app is completely closed.

Here's a brief outline of the issue:

The OneSignal initialization doesn't happen in main.dart because the OneSignal app ID is fetched from a backend, so I can't statically initialize it. The listener for notification clicks is set up after fetching the OneSignal app ID. This works well when the app is in the foreground or background, but fails when the app is completely shut down. Here's the relevant part of the code:

void _setOneSignalNotifications() {
  String? id;

  if (_company?.settingsOneSignal != null) {
    id = _company?.settingsOneSignal?['appId'];
  }

  if (id != null && id.isNotEmpty) {
    OneSignal.Debug.setLogLevel(OSLogLevel.verbose);

    OneSignal.initialize(id);
    OneSignal.Notifications.requestPermission(true);

    OneSignal.Notifications.addClickListener((event) async {
      _handleNotificationOpened(event);
    });
  }
}

Future<void> _handleNotificationOpened(OSNotificationClickEvent event) async {
  try {
    final data = json.decode(event.notification.rawPayload?["custom"]);
    if (!hasCustomNotificationPayload(data)) return;

    final orderId = data["a"]["orderId"];

    openStatusScreen(orderId);
  } catch (e, stackTrace) {
    RateLimiter.reportException(e, stackTrace: stackTrace);
  }
}

bool hasCustomNotificationPayload(data) {
  return data["a"] != null;
}

void openStatusScreen(String orderId, {BuildContext? context}) {
  try {
    final Order orderTemp = orders.firstWhere((element) {
        return element.id == orderId;
      });
    Navigator.push(
      context ?? Get.context!,
      MaterialPageRoute(
        builder: (context) => OrderStatusPage(
          routeArgument: RouteArgument(order: orderTemp),
        ),
      ),
    );
  } catch (e, stackTrace) {
    RateLimiter.reportException(e, stackTrace: stackTrace);
  }
}

I'm looking for suggestions or best practices on how to handle this scenario effectively. Specifically, how can I ensure that the notification click listener works even when the app is completely closed? Any advice or insights would be greatly appreciated.

Thank you!