ubhub_maps_flutter 0.1.0
ubhub_maps_flutter: ^0.1.0 copied to clipboard
Flutter map and place-search widgets for the UBHUB public geospatial API.
UBHUB Flutter widgets #
ubhub_maps_flutter adds UbHubMap and UbHubPlaceSearch to the pure Dart
ubhub_maps SDK. The map uses MapLibre
Native to render UBHUB vector tiles. It does not use or expose ArcGIS credentials.
This initial 0.1.0 release has passed Android and iOS simulator builds. Authenticated on-device security/performance verification remains pending. Map rendering supports Android/iOS; search is a normal Flutter widget. Desktop and web maps show an explicit unsupported-platform message.
Installation #
flutter pub add ubhub_maps_flutter
For local development from this repository:
dependencies:
ubhub_maps_flutter:
path: ../ubhub_dart_sdk/packages/ubhub_maps_flutter
import 'package:ubhub_maps_flutter/ubhub_maps_flutter.dart';
final client = UbHubGeo(apiKey: apiKey);
// Keep options stable across rebuilds, e.g. in State.initState.
final options = UbHubMapOptions(apiKey: apiKey);
// Place in a bounded layout, such as an Expanded or SizedBox.
UbHubMap(
options: options,
markers: const [GeoPoint(latitude: 47.9184, longitude: 106.9177)],
onReady: (controller) { /* controller.flyTo(place.location); */ },
);
UbHubPlaceSearch(
client: client,
onSelected: (place) { /* Use the typed result and place.location. */ },
);
The caller closes client; the map owns and disposes its native transport.
Replace options to rotate a key or origin: this recreates the map and closes
the old session. Coordinates use named latitude/longitude; GeoJSON overlays
use longitude first. Supply route: routeResult.route.geometry.coordinates for a
route line (or any list of GeoPoint vertices). Attribution from the public
style remains visible; zoom is constrained to the gateway's 0–16 range.
No location tracking, location permissions, navigation or offline downloads.
Android and iOS setup #
The renderer currently requires Android compile SDK 36 and Java 21, and iOS 13 or later. Use an app toolchain compatible with maplibre_gl 0.27.1. Android INTERNET permission is declared by this plugin; no cleartext exception is needed. The iOS integration uses CocoaPods, with MapLibre 6.28.0. Swift Package Manager integration is not provided in this first version; use CocoaPods for the host app.
The repository includes Android and iOS example host projects. Run from its
packages/ubhub_maps_flutter/example directory:
flutter run --dart-define=UBHUB_API_KEY=YOUR_RESTRICTED_KEY
The recognized pub.flutter-io.cn example is example/lib/main.dart.
Authentication and resource isolation #
Use a restricted key with basemap scope; search additionally needs geocode.
Mobile keys are extractable and are not secrets. Restrict endpoints and supported
application identities, configure quotas, and rotate keys when necessary.
The default trusted API is https://developers.ubhub.mn. Advanced origin overrides
receive your key; only configure your own trusted UBHUB API deployment.
The widget validates the style before constructing a renderer. Only vector
sources and public basemap paths from that exact origin are accepted. Native
resources are rewritten to a unique .ubhub-map.invalid hostname: an opaque,
local routing handle, never an API key or actual network destination. Native
adapters translate it into a fixed public basemap request using that map's
credential session. Keys never enter URLs or native error messages. Redirects,
cookies, ambient credentials, unknown sessions and non-basemap paths are blocked.
Normal TLS validation stays enabled. Style fetches are limited to 2 MiB; native
resources to 8 MiB, with finite deadlines. Closing a session cancels its requests.
Do not call MapLibre's global/custom header or global HTTP-client configuration APIs in the same app: they replace its process-wide transport hook. Doing so causes UBHUB resources to fail closed, not switch to another map's credentials. MapLibre's hook is global, but each UBHUB map owns its key and upstream connections. Unrelated map requests receive no UBHUB credentials. Do not load untrusted map styles alongside authenticated maps; a local session handle is not an app sandbox.
Native asset disk caching is disabled in this first release to avoid credential reuse through a shared renderer cache. Already rendered tiles remain managed by MapLibre. Backend caches and lossless compression still apply. Resource requests consume the normal backend quotas. We make no FPS or device-memory claims until real Android/iOS measurements are available.
Search behavior #
Search waits 350 ms after typing and requires 2–200 characters. New queries, clearing the field, disabling it and disposal invalidate earlier results. Superseded HTTP requests may already have consumed quota; they are not cached. Loading, no-results and safe error states are displayed. Result lists scroll, and submitting the field selects the first loaded result. Decorations can be localized; default status strings are English in this version.
Validation #
flutter pub get
flutter analyze
flutter test
dart format --output=none --set-exit-if-changed .
For a publication dry run, stage outside this Git repository. Pub applies the
parent Dart package's .pubignore (which intentionally excludes packages/)
even when invoked inside the Flutter package:
# From the repository root; destination must not exist.
python3 tool/stage_flutter_package.py /tmp/ubhub-widgets-release
cd /tmp/ubhub-widgets-release
flutter pub get
flutter pub publish --dry-run
Release gate: build Android and iOS, then test two maps with different restricted keys against a controlled HTTPS gateway; verify each resource's Authorization, blocked redirects, bounded errors, and cancellation after disposal. Compare cold/warm load time, p95 pan/zoom frame time and memory on physical devices. Never capture authorization headers in exported traces.
License #
MIT for this package. MapLibre and other dependencies retain their own licenses. UBHUB API access and data licensing are separate.