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:
- The "Flutter SDK" is only for mobile apps, it doesn’t work on web apps
- For web apps we should be using the "Web SDK" i.e. using Java Script not Flutter
- 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)