Skip to Content

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:

FieldType
onReadyvoid Function()?
onSurveyShownvoid Function(SurveyShownEvent event)?
onSurveyCompletedvoid Function(SurveyCompletedEvent event)?
onSurveyDismissedvoid Function(SurveyDismissedEvent event)?
onQuestionAnsweredvoid 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

EventDart callbackPayload classFields
readyonReadynone
survey:shownonSurveyShownSurveyShownEventsurveyId (String)
survey:completedonSurveyCompletedSurveyCompletedEventsurveyId (String)
survey:dismissedonSurveyDismissedSurveyDismissedEventsurveyId (String)
survey:question_answeredonQuestionAnsweredQuestionAnsweredEventsurveyId (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.