How it works
The SDK is one Rust core behind a frozen interface. This page explains the concepts that interface exposes, so the tutorials’ calls read as applications of them rather than recipes to copy. Every concept below is part of the frozen FFI contract.
Coordinates and the camera
A position is a GeographicCoordinate: latitude and longitude in decimal
degrees on the WGS 84 ellipsoid. A region is a BoundingBox between a
south-west and a north-east corner, and a box never spans the
antimeridian.
The camera is a MapCamera value: an anchored pose of center, zoom,
bearing, and pitch. The ground point under the center sits at the
viewport center, zoom and pitch are clamped, and bearing wraps into the
range from 0 up to but not including 360 degrees.
| Camera attribute | What it means |
|---|---|
center | The coordinate anchored at the viewport center |
zoom_level | Scale; a continuous level, not necessarily a whole number |
bearing_degrees | Rotation clockwise from north |
pitch_degrees | Tilt from top-down (0) toward the horizon |
A camera carries no setters. A new pose is a new constructor call, and
the attribute getters read the state back as it was built. The second
constructor, fit_bounds, frames a bounding box inside the inset region
you give it: top-down, north-up, zoomed to the largest level that keeps
the whole box visible, and anchored on the inset region’s center. Insets
are the pixels your own overlays keep clear, so route cards and
attribution never hide the destination.
The camera answers screen mappings without drawing. project_to_screen
and screen_to_ground_coordinate convert between a coordinate and
viewport pixels, visible_tile_keys lists the tiles the view covers, and
ground_meters_per_screen_pixel sizes a scale bar.
Zoom levels and tiles
A tile is one payload at a fixed zoom, addressed by a TileKeyRecord: a
column, a row counted from the north, and the zoom level. The addressing
is the web-mercator XYZ scheme. At zoom 0 the world is one tile, and each
level doubles the columns and rows.
The camera’s zoom is continuous, so it answers two different questions.
tile_zoom_level gives the nearest whole level a tile fetch should use.
visible_tile_keys gives every tile at a chosen level that intersects
the visible ground, sorted row-major from the north.
A raster tile is a pre-rendered image. The contract carries it as
RasterTileData with its encoded bytes, an image format (PNG or JPEG),
and a resolution: Standard, or Retina for the doubled-texel @2x
form. A vector tile carries geometry and style separately from the
pixels and is rendered on the device. The shipped renderer draws raster
imagery, and vector rendering is a later path.
The provider registry
Provider-backed capability reaches you through MapSdk, an object with
no providers at construction. You register implementations, then call
the contract methods: forward and reverse geocoding, routing, the
distance matrix, place search, traffic incidents, traffic flow, and
raster tiles. Every call resolves through a registry. A call into a
contract with no registration throws ProviderNotConfigured naming the
contract, and the elevation contract has no registered implementation
today.
There are two registration paths:
register_mapquest_providersinstalls the whole map-platform provider set from one API key, with the SDK defaults for rate limiting and retries.register_geocoding_provider_from_foreignandregister_raster_tile_provider_from_foreigninstall an implementation your own Kotlin or Swift code supplies through theGeocodingProviderandRasterTileProviderinterfaces.
Registration is per object, and re-registration replaces every slot. A
second MapSdk object needs its own registration.
The cache path
register_mapquest_providers_with_tile_cache installs the same provider
set and wraps the raster-tile contract in a disk response cache: a SQLite
database at a path you own, under an absolute byte budget. A cache hit
answers from disk, and a cache miss goes to the network and back-fills.
Cached tile responses are retained under the tiles category’s
time-to-live, 30 calendar days by default. That default is also the
imagery provider’s terms ceiling. set_raster_tile_cache_time_to_live
tunes the value, an override above the ceiling is accepted and clamped,
and raster_tile_cache_terms reads back three values: the effective
time-to-live, the provider’s declared ceiling, and the category default.
The byte budget is fixed when the store opens, so retuning it means
registering again, and a fresh registration starts at the category
default.
Raster imagery is the layer the cache holds. Offline routing is a separate layer with its own archive (see below).
The frozen contract and four platforms
One UniFFI UDL file defines the surface, and it is the single source of truth. The Kotlin, Swift, and React Native bindings are generated from it, and the WebAssembly TypeScript mirror is regression-checked against it. The contract changes addition-only: existing members keep their signature and meaning, and new capability arrives as new members.
| Platform | How you call the contract |
|---|---|
| Android (Kotlin) | Suspend functions and typed records; failures are the contract’s SdkError variants |
| iOS (Swift) | Async throwing methods and records |
| React Native | Promise-returning TurboModule methods with lower camel case field names |
| WebAssembly | A hand-reviewed TypeScript mirror over wasm-bindgen, covering the camera, rendering, and offline-routing slice |
Plain data crosses as records and enums. The error model crosses as the
SdkError variants the failing call can produce, with verbatim detail
text. get_sdk_compiled_version on every surface answers the compiled
SDK version, so a diagnostics screen can compare the loaded core with the
artifacts your application shipped.
Navigation state
Routing returns a RouteData: legs between consecutive waypoints, and
steps inside each leg, each carrying its distance, duration, maneuver
label, and instruction texts. Navigation consumes that value rather than
extending it.
MapNavigationController holds a trip. You start one with
start_trip(route, unit_system, step_advance_policy, deviation_policy)
and deliver one position fix at a time with provide_location_update.
The controller publishes four topics: banner instructions, speech
triggers, deviation status, and phase changes. A subscription is
cancelled explicitly through its handle.
A trip has three phases: Navigating, OffRoute, and Arrived.
Rerouting is not a phase; a trip moves between navigating and off route
until it arrives. Deviation has two grades:
FullyOffRoutefreezes progress until a graded fix recovers or a reroute replaces the route.OffStepOnRoutemeans the fix is off the current step but still on a later part of the route, and the trip keeps navigating.
Guidance uses two policies you choose at trip start. StepAdvancePolicy
decides when the trip moves to the next step, and DeviationPolicy
decides when a fix counts as off route. A fix without a reported
accuracy never advances a step and is never judged for deviation, so a
simulated source must carry accuracy like a real one.
Instruction text has two channels. The banner channel carries the
display text, and the speech channel carries the text-to-speech text
through SpeechInstruction. The SDK decides when a line is newsworthy
and supplies the text verbatim. Your application owns playback and
synthesis, and utterance_id is a stable identity for deduplication.
A deviation asks for a replacement route through a small gate.
begin_reroute_calculation answers true when the request passes the
in-flight, cooldown, and movement checks, provide_reroute applies the
replacement, and cancel_reroute_calculation abandons it. The trip
state’s is_calculating_new_route reports the in-flight fact.
Offline routing
Offline routing answers from a compiled archive rather than a network round trip. The archive is built from an OpenStreetMap extract and is self-describing. It answers routes with an A* search over a memory-mapped graph and honors recorded turn restrictions. Maneuver text derives from the geometry where the extract carries no street names.
The archive’s direct route call joins the native contract in a later slice. Today it answers the automatic fallback when the online provider fails and the WebAssembly surface’s offline route seam, and one compiled archive serves every target.
Where to go next
The tutorials apply these concepts in order: Your first map, Search and routing, Turn-by-turn navigation, and Offline maps.