Events
Flutter has no per-event on(event, callback)/off(event, callback) like web and the
natives. Instead, addEventListener takes a single listener object with five typed
callback fields covering every SDK lifecycle event, and removeEventListener removes that
whole object — there is no per-event subscription on Flutter.
final listener = OneSygnalEventListener(
onReady: () {
print('SDK ready');
},
onSurveyShown: (event) {
print('Survey shown: ${event.surveyId}');
},
onSurveyCompleted: (event) {
print('Survey completed: ${event.surveyId}');
},
onSurveyDismissed: (event) {
print('Survey dismissed: ${event.surveyId}');
},
onQuestionAnswered: (event) {
print('Question ${event.questionId} answered in survey ${event.surveyId}');
},
);
OneSygnal().addEventListener(listener);
// later:
OneSygnal().removeEventListener(listener);OneSygnalEventListener (in onesygnal_event_listener.dart) is a closure-based
convenience class — every field is an optional named closure, so you only need to pass the
ones you care about. Its five fields:
| Field | Type |
|---|---|
onReady | void Function()? |
onSurveyShown | void Function(SurveyShownEvent event)? |
onSurveyCompleted | void Function(SurveyCompletedEvent event)? |
onSurveyDismissed | void Function(SurveyDismissedEvent event)? |
onQuestionAnswered | void Function(QuestionAnsweredEvent event)? |
If you’d rather subclass than pass closures, OneSygnalEventListenerInterface is the
abstract base OneSygnalEventListener implements — every method has a no-op default, so
you only override what you need:
class MyListener extends OneSygnalEventListenerInterface {
@override
void surveyShown(SurveyShownEvent event) {
print('Survey shown: ${event.surveyId}');
}
}You can register addEventListener before initialize() has even run — subscribing just
attaches to the event stream, it doesn’t require the SDK to already be running. Events
start arriving once initialize() completes.
Event payloads
| Event | Dart callback | Payload class | Fields |
|---|---|---|---|
ready | onReady | — | none |
survey:shown | onSurveyShown | SurveyShownEvent | surveyId (String) |
survey:completed | onSurveyCompleted | SurveyCompletedEvent | surveyId (String) |
survey:dismissed | onSurveyDismissed | SurveyDismissedEvent | surveyId (String) |
survey:question_answered | onQuestionAnswered | QuestionAnsweredEvent | surveyId (String), questionId (String) |
These are the same event names the natives emit, wrapped in typed Dart classes instead of
the raw Map the channel carries — the wire payload underneath is a Map with an
event_type discriminator plus these fields.
No survey:step
Web additionally has a survey:step event ({ surveyId, questionId, step }, fired once
per answered question, with a step index). Flutter has no equivalent: the bridge only
forwards the native survey:question_answered event, which has no step field — web’s
survey:step has no channel wire equivalent to bridge. See
web’s events page if you’re sharing analytics-forwarding code
across platforms and need to know this payload doesn’t carry a step index here.
Multiple listeners
You can call addEventListener more than once — every registered listener receives every
event. The bridge only subscribes to the native event channel while at least one Dart
listener is registered (lazily, on the first addEventListener; torn down on the last
removeEventListener), not for the app’s whole lifetime.
See Platform Parity for how these events compare across web, Android, and iOS.