2

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?

elbehairy
  • 51
  • 6

2 Answers2

3

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);
  }
elbehairy
  • 51
  • 6
0

OneSignal have SDK for web push, flutter web is a website (webapp) at the end so you should configure OneSignal for web and try it out.

One Signal

You can do this to get player_id using JavaScript:

OneSignal.push(function() {
/* These examples are all valid 
*/

OneSignal.getUserId(function(userId) {
console.log("OneSignal User ID:", userId);
// (Output) OneSignal User ID: 270a35cd-4dda-4b3f-b04e-41d7463a2316    
  });
});

//Another example:

OneSignal.push(function() {               

OneSignal.getUserId().then(function(userId) {
console.log("OneSignal User ID:", userId);
// (Output) OneSignal User ID: 270a35cd-4dda-4b3f-b04e-41d7463a2316    
  });
});

Then you can pass it to the flutter code via the url.

user16930239
  • 6,319
  • 2
  • 9
  • 33
  • I already done that, that is how I'm "receiving" notifications, and I can see the subscribed user's player ids in the OneSignal dashboard as well, this is basically adding the configuration in the index.html
    , and uploading the sdk files (service worker .js files). But my question is about accessing OneSignal from inside the Flutter code as I did in the android version.
    – elbehairy Sep 26 '21 at 10:47
  • Could you please clarify how to pass the User ID to flutter as you mentioned in your updated answer? – elbehairy Sep 26 '21 at 12:12
  • After you got UserId send it a specific page. Like this www.yourdomain.com/register notification/UserId=xxxxxxxxxxxx – user16930239 Sep 26 '21 at 12:22
  • Sorry, but I still don't understand how to read this information in the flutter code. – elbehairy Sep 26 '21 at 17:14
  • You should make a page that reads url variables (this could be the main page). Then the JavaScript code in the html will redirect the user to this page and add the UserId to the url, then your flutter code could read it. For example: https://www.example.com/main?UserId=123456 – user16930239 Sep 26 '21 at 17:23
  • I understand your point, but how to make "a page that reads url variables" in Flutter? Could you please provide a sample Flutter code? – elbehairy Sep 26 '21 at 23:46
  • https://www.fluttercampus.com/guide/52/how-to-get-parameters-from-url-in-flutter-web/ – user16930239 Sep 26 '21 at 23:55
  • Thanks, the link provided help, I'm now able to read the parameters if I entered them manually in the browser, but I still don't know for to pass them to main.dart from inside the index.html – elbehairy Sep 27 '21 at 02:51
  • https://www.w3schools.com/howto/howto_js_redirect_webpage.asp – user16930239 Sep 27 '21 at 05:28
  • Unfortunately, this is not working, it put the page in an endless loop, keep on reloading the page. This also didn't solve setting the external id & sending a notification from the Flutter code. I have found a better approach and added it as an answer. – elbehairy Oct 12 '21 at 13:38