Migration Guide: v4 to v5¶
How to migrate your Android integration from ExpoFP SDK v4 to v5 and start using the new presenter-based architecture.
Summary v5 replaces direct view control with a presenter, streamlines initialization, adds coroutine-first APIs, and formalizes offline/preload flows.
Key Changes at a Glance¶
Area | v4 | v5 |
---|---|---|
Rendering | FplanView / SharedFplanView |
ExpoFpView + IExpoFpPlanPresenter |
Initialization | load(url, Settings) |
ExpoFpPlan.initialize(...) + createPlanPresenter(planLink, ...) |
State & errors | View callbacks (onReady , onError ) |
planStatusFlow (Flow<ExpoFpPlanStatus> ) |
Offline | OfflinePlanManager |
ExpoFpPlan.downloader |
Preload | SharedFplanView.preload(...) |
ExpoFpPlan.preloader (multiple preloads) |
Events | Settings.withEventsListener(...) |
IExpoFpPlanMessageListener |
Global location | GlobalLocationProvider |
ExpoFpPlan.globalLocationProvider |
Cleanup | Manual destroy() |
Not required (managed by view/presenter) |
Step 1. Initialization¶
View-based apps (v4 to v5)¶
Version 4 (FplanView / SharedFplanView):
public class YourActivity extends AppCompatActivity {
private FplanView fplanView;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fplanView = new FplanView(this);
setContentView(fplanView);
fplanView.load("https://demo.expofp.com", new Settings());
}
@Override protected void onDestroy() {
fplanView.destroy();
super.onDestroy();
}
}
Version 5 (Presenter + ExpoFpView):
// Application.onCreate (recommended once)
ExpoFpPlan.initialize(this)
// Before first use (allowed)
ExpoFpPlan.initialize(context)
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.RawLink("https://demo.expofp.com")
)
val expoView = ExpoFpView(this).apply { attachPresenter(presenter) }
setContentView(expoView) // No manual destroy() needed
Jetpack Compose (new in v5)¶
ExpoFpPlan.initialize(this)
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.RawLink("https://demo.expofp.com")
)
setContent {
AndroidView(factory = { presenter.getView() })
}
Step 2. Settings and Parameters¶
In v4, many options were passed via the Settings
object (focus behaviors, events, location). In v5, you configure the presenter:
- Initial link via
planLink
- Optional
additionalParams
(URL query items) - Optional
locationProvider
- Optional
messageListener
v4 flags like
focusOnLocation
/focusOnFirstLocation
were part ofSettings
; in v5 the map handles focus/blue-dot behavior internally.
Per-presenter location provider (v4 to v5)
v4
Settings settings = new Settings()
.withLocationProvider(new YourProvider(getApplication()));
// fplanView.load("https://demo.expofp.com", settings);
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.ExpoKey("demo"),
locationProvider = YourLocationProvider()
)
Global location provider (shared)
v5
ExpoFpPlan.globalLocationProvider.sharedProvider = YourLocationProvider()
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.ExpoKey("demo"),
locationProvider = ExpoFpPlan.globalLocationProvider
)
Step 3. Plan Status and Errors¶
In v4 you subscribed to readiness/error callbacks on the view. In v5 observe a Kotlin Flow
from the presenter.
lifecycleScope.launchWhenStarted {
presenter.planStatusFlow.collect { status ->
when (status) {
is ExpoFpPlanStatus.Initialization -> { /* starting */ }
is ExpoFpPlanStatus.Loading -> { /* status.percentage */ }
is ExpoFpPlanStatus.Ready -> { /* ready */ }
is ExpoFpPlanStatus.Error -> { /* status.error */ }
}
}
}
Step 4. Offline Downloaded Plans¶
v4: OfflinePlanManager
downloaded to cache; you managed old versions yourself.
v5: use ExpoFpPlan.downloader
.
// Download and save
val result = ExpoFpPlan.downloader.downloadPlan("demo")
val info = result.getOrNull() ?: return
// Open downloaded plan
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.DownloadedPlanInfo(info)
)
You can also unzip a bundled file named <expoKey>_<version>.zip
with downloadPlanFromZip(filePath)
.
Step 5. Preloaded Plans¶
v4: SharedFplanView.preload(...)
(single shared plan instance).
v5: ExpoFpPlan.preloader
supports multiple preloads and retrieving presenters as needed.
val preloaded = ExpoFpPlan.preloader.preloadPlan(
planLink = ExpoFpLinkType.ExpoKey("demo")
)
val presenter = ExpoFpPlan.preloader.getPreloadedPlanPresenter(preloaded)
If a preloaded plan is reloaded with a new
planLink
, the link is updated inExpoFpPreloadedPlanInfo
.
Step 6. Commands (v4 to v5)¶
In v4 you called methods on the view; in v5 you call them on the presenter. Some names changed for clarity; others were replaced by richer APIs.
v4 (view) | v5 (presenter) | Notes |
---|---|---|
zoomIn() / zoomOut() |
zoomIn() / zoomOut() |
Same behavior. |
fitBounds() |
fitBounds() |
Same. |
selectBooth(String) |
selectBooth(String) |
Same. |
selectExhibitor(String or String[]) |
selectExhibitor(String) / highlightExhibitors(List) |
Split responsibilities. |
selectCategory(String) |
selectCategory(String) |
Same. |
selectRoute(...) |
selectRoute(waypoints, onlyAccessible) |
Waypoints API in v5. |
selectCurrentPosition(Location, focus) |
selectCurrentPosition(ExpoFpPosition, focus) |
v5 unified model. |
updateLayerVisibility(layer, visible) |
activateFloor(floor) / setElementsVisibility(...) |
Use floors or elements visibility. |
getVisibility(...) / setVisibility(...) |
getElementsVisibility() / setElementsVisibility(...) |
Renamed. |
clear() / destroy() |
(not required) | Managed by presenter/view. |
v5 examples:
presenter.fitBounds()
presenter.selectBooth("Lounge 2 | Hall 3.1")
presenter.setElementsVisibility(ExpoFpElementsVisibility(controls=false, levels=false, header=false, overlay=false))
val floors = presenter.getFloors()
presenter.activateFloor(floor)
More commands are covered in Manage Plan.
Step 7. Events¶
v4: events were assigned via Settings.withEventsListener(...)
.
v5: implement IExpoFpPlanMessageListener
and pass it to the presenter (during creation is preferred).
class MyListener : IExpoFpPlanMessageListener {
override fun boothDidClick(e: ExpoFpResult<ExpoFpBoothClickEvent>, from: ExpoFpLinkType) { /*...*/ }
override fun directionDidBuild(e: ExpoFpResult<ExpoFpDirection?>, from: ExpoFpLinkType) { /*...*/ }
override fun detailsDidClick(e: ExpoFpResult<ExpoFpDetails?>, from: ExpoFpLinkType) { /*...*/ }
override fun exhibitorCustomButtonDidClick(e: ExpoFpResult<ExpoFpCustomButtonEvent>, from: ExpoFpLinkType) { /*...*/ }
override fun bookmarkDidClick(e: ExpoFpResult<ExpoFpBookmark>, from: ExpoFpLinkType) { /*...*/ }
override fun categoryDidClick(e: ExpoFpResult<ExpoFpCategory>, from: ExpoFpLinkType) { /*...*/ }
override fun currentPositionDidChange(e: ExpoFpResult<ExpoFpPosition>, from: ExpoFpLinkType) { /*...*/ }
override fun currentFloorDidChange(e: ExpoFpResult<ExpoFpFloor>, from: ExpoFpLinkType) { /*...*/ }
}
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.ExpoKey("demo"),
messageListener = MyListener()
)
See the full list in Listen Plan Events.
Step 8. Navigation (Location Providers)¶
- v4 configured providers via
Settings.withLocationProvider(...)
or used a global provider. - v5 attaches a provider directly to the presenter or uses
ExpoFpPlan.globalLocationProvider
.
Refer to Setup Navigation for permissions and partner wrappers (CrowdConnected, IndoorAtlas).
Step 9. Debugging¶
v5 provides a debug mode and a way to evaluate custom scripts on the plan during development.
ExpoFpPlan.isDebugModeEnabled = true
val js: ExpoFpResult<Any?> = presenter.evaluateCustomScript("console.log('ping')")
Migration Checklist¶
- [ ] Replace
FplanView
/SharedFplanView
withExpoFpView
+IExpoFpPlanPresenter
. - [ ] Initialize once with
ExpoFpPlan.initialize(...)
. - [ ] Move
Settings
options to presenter creation (planLink
,additionalParams
,locationProvider
,messageListener
). - [ ] Replace v4 callbacks with
planStatusFlow
. - [ ] Switch offline operations from
OfflinePlanManager
toExpoFpPlan.downloader
. - [ ] Replace
SharedFplanView.preload(...)
withExpoFpPlan.preloader
. - [ ] Migrate view-level commands to presenter methods; update visibility/floor APIs.
- [ ] Migrate event listeners to
IExpoFpPlanMessageListener
. - [ ] Review navigation setup (providers and permissions) per Setup Navigation.
- [ ] Remove any manual
destroy()
calls.