Is it possible to use OneSignal with Flutter-Web?

Issue

Calling any of the OneSignal functions works fine on android but on web it throws the following exception.
Note that the subscription part is working, I had my appId set in the index.html, I uploaded the service worker js files and I received the first welcoming message.

But I need to be able to get the "playerId" and save it and also to be able to send notification from the web.

Example of OneSignal function calls:

  await OneSignal.shared.setAppId(kOneSignalAppId);
  OSDeviceState? deviceState = await OneSignal.shared.getDeviceState();
  OneSignal.shared.postNotification(notification);

Exception:

Error: MissingPluginException(No implementation found for method OneSignal#log on channel OneSignal)
at Object.throw_ [as throw] (http://localhost:49430/dart_sdk.js:5079:11)
at MethodChannel._invokeMethod (http://localhost:49430/packages/flutter/src/services/restoration.dart.lib.js:1526:21)
at _invokeMethod.next (<anonymous>)
at http://localhost:49430/dart_sdk.js:38749:33
at _RootZone.runUnary (http://localhost:49430/dart_sdk.js:38620:59)
at _FutureListener.thenAwait.handleValue (http://localhost:49430/dart_sdk.js:33820:29)
at handleValueCallback (http://localhost:49430/dart_sdk.js:34372:49)
at Function._propagateToListeners (http://localhost:49430/dart_sdk.js:34410:17)
at _Future.new.[_completeWithValue] (http://localhost:49430/dart_sdk.js:34258:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:49430/dart_sdk.js:34279:35)
at Object._microtaskLoop (http://localhost:49430/dart_sdk.js:38887:13)
at _startMicrotaskLoop (http://localhost:49430/dart_sdk.js:38893:13)
at http://localhost:49430/dart_sdk.js:34626:9

Error: MissingPluginException(No implementation found for method OneSignal#setAppId on channel OneSignal)
at Object.throw_ [as throw] (http://localhost:49430/dart_sdk.js:5079:11)
at MethodChannel._invokeMethod (http://localhost:49430/packages/flutter/src/services/restoration.dart.lib.js:1526:21)
at _invokeMethod.next (<anonymous>)
at http://localhost:49430/dart_sdk.js:38749:33
at _RootZone.runUnary (http://localhost:49430/dart_sdk.js:38620:59)
at _FutureListener.thenAwait.handleValue (http://localhost:49430/dart_sdk.js:33820:29)
at handleValueCallback (http://localhost:49430/dart_sdk.js:34372:49)
at Function._propagateToListeners (http://localhost:49430/dart_sdk.js:34410:17)
at _Future.new.[_completeWithValue] (http://localhost:49430/dart_sdk.js:34258:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:49430/dart_sdk.js:34279:35)
at Object._microtaskLoop (http://localhost:49430/dart_sdk.js:38887:13)
at _startMicrotaskLoop (http://localhost:49430/dart_sdk.js:38893:13)
at http://localhost:49430/dart_sdk.js:34626:9

Does it need a web plugin?
Does a one exist or should I create one?
If so could you please tell me how?

Solution

After a lot of investigation, I was able to confirm the following:

  1. The "Flutter SDK" is only for mobile apps, it doesn’t work on web apps
  2. For web apps we should be using the "Web SDK" i.e. using Java Script not Flutter
  3. For both mobile & web we can use the REST API, but in most cases it will need app-id, player-id & API Key, so for initilaization & getting the player-id we will still need the "Flutter SDK" for mobile apps or the "Web SDK" for web
    This is how I managed to make it work on both mobile & web app with the same code:
    For Web part
  • Initializing via Web SDK
  • Getting the player-id via Web SDK
  • Saving player-id in a hidden element via javascipt
  • Retrieve the player-id from the Flutter code via "universal_html" package
  • Settting external-id via the REST API
  • Sending notification via REST API

For mobile part

  • Initializing via Flutter SDK
  • Getting the player-id via Flutter SDK
  • Settting external-id via Flutter SDK
  • Sending notification via REST API (as Flutter SDK can’t send to external id)

index.html

<head>
  ...
  <script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js" async=""></script>
  <script>
    var OneSignal = window.OneSignal || [];
    var initConfig = {
      appId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      persistNotification: true,
      notifyButton: {
          enable: true
      },
    };
    OneSignal.push(function () {
      OneSignal.init(initConfig);
    });
  </script>
</head>
<body>
  <input type="hidden" id="osUserID" value="ERR" />
  ...
  <script>
    var eUserID = document.getElementById('osUserID');
    function getUserId() {
      OneSignal.getUserId(function(osUserID) {
        if (eUserID && osUserID) {
          eUserID.value = osUserID;
          }
      });
    }
    OneSignal.push(function () {
      OneSignal.isPushNotificationsEnabled(function(isEnabled) {
        if (isEnabled) getUserId();
      });
      OneSignal.on('subscriptionChange', function (isSubscribed) {
        if (isSubscribed) getUserId();
      });
    });
  </script>
</body>

From inside Flutter

  import 'package:flutter/foundation.dart';
  import "package:universal_html/html.dart";
  import 'package:onesignal_flutter/onesignal_flutter.dart';
  import 'onesignal_api.dart';
  ...
  Future<String> getPlayerId(String exteralId) async {
    String _osUserID;
    if (kIsWeb){
      InputElement? element = querySelector("#osUserID") as InputElement?;
      osUserID = element?.value??"Not Subscribed";
      await _oneSignalAPI.setExternalId(osUserID, exteralId);
    }
    else {
      await OneSignal.shared.setAppId(kOneSignalAppId);
      OSDeviceState? deviceState = await OneSignal.shared.getDeviceState();
      osUserID = deviceState?.userId??"Not Subscribed";
      await OneSignal.shared.setExternalUserId(exteralId);
    }
    return osUserID;
  }
  Future<void> sendMessage(String exteralId, String message) async {
    _oneSignalAPI.sendNotification(exteralId, message);
  }

Answered By – elbehairy

Answer Checked By – Clifford M. (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *