Skip to content

Listen Plan Events

Listen and respond to user interactions and runtime messages from a plan.

Overview

  • Implement IExpoFpPlanMessageListener to receive event callbacks.
  • Assign the listener when creating the presenter (recommended) or later via setMessageListener(...).
  • Callbacks are invoked on the main thread.
  • The SDK does not retain your listener globally; manage its lifecycle in your UI/component.

Step 1. Implement a Listener

class YourListener : IExpoFpPlanMessageListener {

    override fun bookmarkDidClick(
        bookmark: ExpoFpResult<ExpoFpBookmark>,
        from: ExpoFpLinkType
    ) {
        // Handle bookmark click (success or error)
    }

    override fun boothDidClick(
        boothEvent: ExpoFpResult<ExpoFpBoothClickEvent>,
        from: ExpoFpLinkType
    ) { /* ... */ }

    override fun categoryDidClick(
        category: ExpoFpResult<ExpoFpCategory>,
        from: ExpoFpLinkType
    ) { /* ... */ }

    override fun currentFloorDidChange(
        floor: ExpoFpResult<ExpoFpFloor>,
        from: ExpoFpLinkType
    ) { /* ... */ }

    override fun currentPositionDidChange(
        position: ExpoFpResult<ExpoFpPosition>,
        from: ExpoFpLinkType
    ) { /* ... */ }

    override fun detailsDidClick(
        details: ExpoFpResult<ExpoFpDetails?>,
        from: ExpoFpLinkType
    ) { /* ... */ } // details may be null

    override fun directionDidBuild(
        direction: ExpoFpResult<ExpoFpDirection?>,
        from: ExpoFpLinkType
    ) { /* ... */ } // direction may be null (reset)

    override fun exhibitorCustomButtonDidClick(
        buttonEvent: ExpoFpResult<ExpoFpCustomButtonEvent>,
        from: ExpoFpLinkType
    ) { /* ... */ }

    override fun visitedDidClick(
        visitedEvent: ExpoFpResult<ExpoFpVisitedClickEvent>,
        from: ExpoFpLinkType
    ) { /* ... */ }

    // Debug-only (fires only in debug mode, see below)
    override fun windowErrorDidReceive(
        error: ExpoFpResult<ExpoFpWindowError>,
        from: ExpoFpLinkType
    ) { /* ... */ }

    override fun consoleMessageDidReceive(
        message: ExpoFpResult<ExpoFpConsoleMessage>,
        from: ExpoFpLinkType
    ) { /* ... */ }
}

Step 2. Attach the Listener

val listener = YourListener()

val presenter = ExpoFpPlan.createPlanPresenter(
    planLink = ExpoFpLinkType.ExpoKey("demo"),
    messageListener = listener
)

Alternatively: set after creation

// Keep a strong reference to the listener; the SDK does not retain it.
val listener = YourListener()
presenter.setMessageListener(listener)

// Later, to remove:
presenter.removeMessageListener()

Tip: Attaching the listener at creation ensures you do not miss early events during initial loading.

Listener lifecycle

The SDK does not retain the message listener. Keep your own strong reference to it for as long as you need callbacks.

You can manually call removeMessageListener() to clear the listener earlier if needed.


Step 3. Use in UI

View-based UI (Activity/Fragment)

class MainActivity : AppCompatActivity() {

    private lateinit var presenter: IExpoFpPlanPresenter
    private val listener = YourListener()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ExpoFpPlan.initialize(this)

        presenter = ExpoFpPlan.createPlanPresenter(
            planLink = ExpoFpLinkType.ExpoKey("demo"),
            messageListener = listener
        )

        val expoView = ExpoFpView(this).apply { attachPresenter(presenter) }
        setContentView(expoView)
    }

    override fun onDestroy() {
        super.onDestroy()
        // Note: a non-preloaded presenter is disposed automatically on destroy; no manual cleanup needed.
    }
}

Jetpack Compose

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ExpoFpPlan.initialize(this)

        val listener = YourListener()
        val presenter = ExpoFpPlan.createPlanPresenter(
            planLink = ExpoFpLinkType.ExpoKey("demo"),
            messageListener = listener
        )

        setContent {
            AndroidView(factory = { presenter.getView() })
        }
    }
}

Events Reference

Event (method) Payload type Notes
bookmarkDidClick(bookmark, from) ExpoFpResult<ExpoFpBookmark> User tapped a bookmark.
boothDidClick(boothEvent, from) ExpoFpResult<ExpoFpBoothClickEvent> Booth pressed on the plan.
categoryDidClick(category, from) ExpoFpResult<ExpoFpCategory> Category selected.
currentFloorDidChange(floor, from) ExpoFpResult<ExpoFpFloor> Current floor changed.
currentPositionDidChange(position, from) ExpoFpResult<ExpoFpPosition> Position updates (if location provider is active).
detailsDidClick(details, from) ExpoFpResult<ExpoFpDetails?> Details selected/deselected. null means deselected.
directionDidBuild(direction, from) ExpoFpResult<ExpoFpDirection?> Direction built or reset. null on reset.
exhibitorCustomButtonDidClick(buttonEvent, from) ExpoFpResult<ExpoFpCustomButtonEvent> Custom button pressed.
visitedDidClick(visitedEvent, from) ExpoFpResult<ExpoFpVisitedClickEvent> Visited pressed.
windowErrorDidReceive(error, from) ExpoFpResult<ExpoFpWindowError> Debug only: JS window.onerror.
consoleMessageDidReceive(message, from) ExpoFpResult<ExpoFpConsoleMessage> Debug only: Web console messages.

About ExpoFpResult<T>
Handle both success and error branches. Do not assume success-only callbacks. Treat nullable payloads (T?) accordingly.


Debug-only Events

//create
val presenter = ExpoFpPlan.createPlanPresenter(
    planLink = ExpoFpLinkType.ExpoKey("demo"),
    isDebugModeEnabled = true
)

//reload
presenter.reloadPlan(
    isDebugModeEnabled = true
)
  • WebView window.onerror: windowErrorDidReceive(error, from)ExpoFpResult<ExpoFpWindowError>
  • Web console messages: consoleMessageDidReceive(message, from)ExpoFpResult<ExpoFpConsoleMessage>

Note: Debug mode can slow down initialization and increase logging. Use it only in debug builds.


Best Practices

  • Attach early: Provide messageListener in createPlanPresenter(...) to capture early lifecycle events.
  • Main thread work: Keep callbacks lightweight; offload heavy work to background coroutines.
  • Lifecycle ownership: Create and remove the listener with your screen/component lifecycle to prevent leaks.
  • Null-aware handling: Some payloads can be null (e.g., details, direction on reset). Check before use.
  • Error-aware handling: Always handle ExpoFpResult errors (network, parsing, etc.).
  • Debug mode: Enable only when troubleshooting. Disable in production.