hamuga_imap_sdk 0.0.13
hamuga_imap_sdk: ^0.0.13 copied to clipboard
Official Hamuga Map SDK for Flutter. Provides a MapLibre-powered map widget with built-in search, auto-suggestions, and secure API key handling through a local tile proxy.
Hamuga Map SDK for Flutter #
English #
hamuga_imap_sdk is Hamuga's Flutter map package. It combines a MapLibre-powered map widget with search, POI lookup, route planning, secure tile access through a local proxy, and runtime geofence support.
- Package:
hamuga_imap_sdk - Current version:
0.0.13 - Dart SDK:
^3.9.2 - Map dependency:
maplibre_gl ^0.24.1 - Default gateway:
https://gateway.hamuga.mn - Default style:
https://cdn.hamuga.mn/style.json
What the package provides #
- MapLibre map widget and camera/gesture configuration
- Address suggestions and POI search
- OTP-style and Valhalla route requests
- Local tile proxy that adds the
x-api-keyheader - Floating location, zoom, compass, and search controls
- Runtime circle geofences with status snapshots and event history
- iOS and Android background circle-monitoring bridge
- Draft circle/polygon geofence editor APIs
Install #
Add the package to pubspec.yaml:
dependencies:
hamuga_imap_sdk: ^0.0.13
Then fetch dependencies:
flutter pub get
Initialize once at startup #
Call HamugaApi.initialize before creating the map or invoking the static API helpers.
For a compile-time API key, run the app with:
flutter run --dart-define=HAMUGA_API_KEY=your_hamuga_api_key
import 'package:flutter/widgets.dart';
import 'package:hamuga_imap_sdk/hamuga_imap_sdk.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
HamugaApi.initialize(
apiKey: const String.fromEnvironment('HAMUGA_API_KEY'),
geofenceBaseUrl: 'https://gateway.hamuga.mn',
);
runApp(const MyApp());
}
apiKey is used for tile proxy requests, search/POI requests, route requests, and geofence checks. gatewayBaseUrl remains the base URL for search, POI, and routing. Set tileUrlTemplate on HamugaImapOptions to override only the tile URL. baseUrl and geofenceBaseUrl can be overridden independently when using another gateway environment.
Quick start #
The default cdn.hamuga.mn style automatically starts the local tile proxy when an API key is available. You do not need to create HamugaTileProxy manually for this path.
import 'package:flutter/material.dart';
import 'package:hamuga_imap_sdk/hamuga_imap_sdk.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: MapPage());
}
}
class MapPage extends StatelessWidget {
const MapPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: HamugaImap(
config: const HamugaImapConfig(),
search: true,
options: const HamugaImapOptions(
showMyLocationButton: true,
showZoomControls: true,
showCompassControl: true,
),
),
);
}
}
HamugaImapConfig requires an API key either through HamugaApi.initialize(...) or through its apiKey override.
Custom style and the tile proxy #
Use the manual proxy flow when a custom style needs authenticated Hamuga tiles:
final proxy = HamugaTileProxy.instance;
await proxy.start(
apiKey: 'your_hamuga_api_key',
baseUrl: 'https://gateway.hamuga.mn',
tileUrlTemplate: 'https://gateway.hamuga.mn/tile/tiles/{z}/{x}/{y}.pbf',
fetchStyle: false,
);
final styleJson = await proxy.fetchAndPatchStyle(
styleUrl: 'https://cdn.hamuga.mn/style.json',
);
if (styleJson == null) {
throw StateError('Could not fetch and patch the Hamuga style');
}
final map = HamugaImap(
config: HamugaImapConfig(styleUri: styleJson),
);
start returns the local port number. fetchAndPatchStyle accepts any style URL and replaces only the sources.hamuga tile URL with the local proxy URL. Stop a proxy that your code owns:
await proxy.stop();
The proxy binds to loopback and forwards tile requests with x-api-key. If the host platform blocks cleartext loopback traffic, apply the platform settings below.
Search, POI, and routing #
import 'package:flutter/foundation.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:hamuga_imap_sdk/hamuga_imap_sdk.dart';
final suggestion = await HamugaApi.suggest('Sukhbaatar Square');
final pois = await HamugaApi.poi('restaurant', page: 1, size: 10);
final route = await HamugaApi.planRoute(
from: const LatLng(47.918, 106.9176),
to: const LatLng(47.92, 106.92),
mode: 'WALK',
);
final calculated = await HamugaApi.calculateRoute(
HamugaCalculateRouteOptions(
locations: const [
HamugaRouteLocation(lat: 47.918, lon: 106.9176),
HamugaRouteLocation(lat: 47.92, lon: 106.92),
],
costing: 'pedestrian',
),
);
For area POI search, pass viewportBounds as [llx, lly, urx, ury] in longitude/latitude order.
Runtime geofences #
Configure one or more circle geofences through HamugaImapOptions.geofence:
import 'package:flutter/foundation.dart';
import 'package:hamuga_imap_sdk/hamuga_imap_sdk.dart';
HamugaImap(
config: const HamugaImapConfig(),
options: HamugaImapOptions(
geofence: HamugaGeofenceOptions(
geofences: const <HamugaRuntimeGeofence>[
HamugaRuntimeGeofence(
id: 'hq',
label: 'HQ',
geometry: HamugaGeofenceCircle(
centerLat: 47.9131732,
centerLon: 106.9267709,
radiusM: 50,
),
),
],
backgroundMonitoring: const HamugaGeofenceBackgroundMonitoringOptions(
enabled: true,
),
showDebugOverlay: true,
onTransition: (transition, state) {
debugPrint('${transition.name}: ${state.status.name}');
},
onEvent: (event, state) {
debugPrint('${event.type.name}: ${event.geofenceId}');
},
),
),
)
Current runtime behavior:
- Renders one or many runtime geofences on the map
- Checks each geofence when a user-location update arrives
- Stores
inside,outside, andunknownstatus - Records
checked,entered,exited, anderrorevents - Synchronizes circle geofences with native iOS/Android background monitoring when enabled
officeGeofence and onTransition remain supported for backward compatibility. New integrations should use geofences and onEvent. The published geofence quick notes are in doc/geofence/README.md; the full source documentation pack is in the repository's docs/geofence/ directory.
Platform setup #
iOS
Add the required location and local-network entries to ios/Runner/Info.plist when using location or background monitoring:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Show your location on the Hamuga map.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Monitor geofences in the background.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Monitor geofences in the background.</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
If permission_handler requires the location compile flag, add PERMISSION_LOCATION=1 to the iOS Podfile post_install settings.
Android
Add location and internet permissions to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
If the local tile proxy is used, allow loopback cleartext traffic in the application declaration:
<application
android:usesCleartextTraffic="true"
...>
maplibre_gl:0.24.1 requires a Java 21 toolchain on Android. A JDK 17 build can fail with invalid source release: 21.
Public API #
| API | Purpose |
|---|---|
HamugaApi.initialize(...) |
Configure the API key and gateway defaults. |
HamugaApi.suggest(query) |
Request one search suggestion. |
HamugaApi.poi(query, ...) |
Search POIs and optionally constrain the viewport. |
HamugaApi.planRoute(...) |
Request an OTP route plan. |
HamugaApi.calculateRoute(...) |
Request a Valhalla route calculation. |
HamugaImap |
Render a map and optional search/geofence overlays. |
HamugaImapConfig |
Configure style, camera, gestures, and an API-key override. |
HamugaImapOptions |
Configure controls, location, callbacks, search, geofences, and editor behavior. |
HamugaImapController |
Expose imperative map helpers and geofence history actions. |
HamugaTileProxy |
Start/stop the local authenticated tile proxy. |
Example app #
From the Flutter package directory:
cd example
flutter pub get
flutter run
The example reads configuration from example/.env when the host app wiring provides it. The supported variables are:
HAMUGA_API_KEY=your_hamuga_api_key
GEOFENCE_BASE_URL=https://gateway.hamuga.mn
OFFICE_LAT=47.9131732
OFFICE_LON=106.9267709
OFFICE_RADIUS=50
GEOFENCE_BACKGROUND_MONITORING=true
GEOFENCE_ONLY_DURING_WORK_WINDOWS=false
Without office coordinates, the example uses its mock office geofence. Do not commit a real API key.
Troubleshooting #
- Map or tiles do not load: initialize
HamugaApi, confirm the tile proxy is running for a custom style, and inspect[HamugaTileProxy]logs. - Map is blank on a device: check iOS local-networking/ATS settings or Android cleartext settings.
- My location does not work: verify runtime location permissions and
showMyLocationButton. - Geofence remains
unknown: verify the API key,geofenceBaseUrl, circle coordinates/radius, permissions, andshowDebugOverlay. - Android build reports source release 21: use JDK 21 for the MapLibre Android toolchain.
Development checks #
flutter pub get
flutter analyze
dart format . --line-length 120
flutter test
License #
Apache-2.0.
Монгол хэлээр #
hamuga_imap_sdk нь Flutter-д зориулсан Hamuga-ийн газрын зургийн package юм. MapLibre map widget, хайлт, POI, routing, API key бүхий local tile proxy болон runtime geofence-ийг нэгтгэнэ.
- Package:
hamuga_imap_sdk - Одоогийн хувилбар:
0.0.13 - Dart SDK:
^3.9.2 - Map dependency:
maplibre_gl ^0.24.1 - Үндсэн gateway:
https://gateway.hamuga.mn - Үндсэн style:
https://cdn.hamuga.mn/style.json
Package-ийн боломжууд #
- MapLibre map widget, camera болон gesture тохиргоо
- Хаягийн suggestion болон POI хайлт
- OTP-style болон Valhalla route хүсэлт
x-api-keyheader нэмдэг local tile proxy- Location, zoom, compass болон search control
- Status snapshot болон event history бүхий runtime circle geofence
- iOS болон Android background circle-monitoring bridge
- Draft circle/polygon geofence editor API
Суулгах #
pubspec.yaml дотор package нэм:
dependencies:
hamuga_imap_sdk: ^0.0.13
Дараа нь dependency тат:
flutter pub get
Апп эхлэхэд нэг удаа initialize хийх #
Map үүсгэх эсвэл static API helper дуудахаас өмнө HamugaApi.initialize-г дууд.
import 'package:flutter/widgets.dart';
import 'package:hamuga_imap_sdk/hamuga_imap_sdk.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
HamugaApi.initialize(
apiKey: const String.fromEnvironment('HAMUGA_API_KEY'),
geofenceBaseUrl: 'https://gateway.hamuga.mn',
);
runApp(const MyApp());
}
Compile-time key өгөх бол:
flutter run --dart-define=HAMUGA_API_KEY=your_hamuga_api_key
apiKey нь tile proxy, search/POI, route болон geofence хүсэлтэд ашиглагдана. gatewayBaseUrl нь search, POI болон routing-ийн base URL хэвээр байна. HamugaImapOptions.tileUrlTemplate нь зөвхөн tile URL-г override хийнэ. Өөр gateway environment ашиглах үед baseUrl болон geofenceBaseUrl-г тусад нь override хийж болно. Server-ийн нууц credential-ийг client аппад бүү оруул.
Богино эхлүүлэх жишээ #
Default cdn.hamuga.mn style ашиглах үед API key байгаа бол widget local tile proxy-г өөрөө эхлүүлнэ. Энэ замд HamugaTileProxy-г гараар үүсгэх шаардлагагүй.
import 'package:flutter/material.dart';
import 'package:hamuga_imap_sdk/hamuga_imap_sdk.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: MapPage());
}
}
class MapPage extends StatelessWidget {
const MapPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: HamugaImap(
config: const HamugaImapConfig(),
search: true,
options: const HamugaImapOptions(
showMyLocationButton: true,
showZoomControls: true,
showCompassControl: true,
),
),
);
}
}
HamugaImapConfig нь HamugaApi.initialize(...) эсвэл apiKey override-оор API key авна.
Custom style ба tile proxy #
Custom style-д authenticated Hamuga tile хэрэгтэй үед manual proxy урсгалыг ашигла:
final proxy = HamugaTileProxy.instance;
await proxy.start(
apiKey: 'your_hamuga_api_key',
baseUrl: 'https://gateway.hamuga.mn',
fetchStyle: false,
);
final styleJson = await proxy.fetchAndPatchStyle(
styleUrl: 'https://cdn.hamuga.mn/style.json',
);
if (styleJson == null) {
throw StateError('Could not fetch and patch the Hamuga style');
}
final map = HamugaImap(
config: HamugaImapConfig(styleUri: styleJson),
);
start нь local port буцаана. fetchAndPatchStyle нь дурын style URL авч зөвхөн sources.hamuga tile URL-ийг local proxy URL рүү солино. Өөрийн эхлүүлсэн proxy-г зогсоохдоо:
await proxy.stop();
Proxy нь loopback дээр bind хийж, tile хүсэлт бүрт x-api-key дамжуулна. Host platform cleartext loopback traffic-ийг хаавал доорх platform тохиргоог хий.
Search, POI болон routing #
import 'package:flutter/foundation.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:hamuga_imap_sdk/hamuga_imap_sdk.dart';
final suggestion = await HamugaApi.suggest('Сүхбаатарын талбай');
final pois = await HamugaApi.poi('restaurant', page: 1, size: 10);
final route = await HamugaApi.planRoute(
from: const LatLng(47.918, 106.9176),
to: const LatLng(47.92, 106.92),
mode: 'WALK',
);
final calculated = await HamugaApi.calculateRoute(
HamugaCalculateRouteOptions(
locations: const [
HamugaRouteLocation(lat: 47.918, lon: 106.9176),
HamugaRouteLocation(lat: 47.92, lon: 106.92),
],
costing: 'pedestrian',
),
);
Area POI хайхад viewportBounds-г [llx, lly, urx, ury] хэлбэрээр, longitude/latitude дарааллаар өг.
Runtime geofence #
HamugaImapOptions.geofence дотор нэг эсвэл олон circle geofence тохируул:
import 'package:flutter/foundation.dart';
import 'package:hamuga_imap_sdk/hamuga_imap_sdk.dart';
HamugaImap(
config: const HamugaImapConfig(),
options: HamugaImapOptions(
geofence: HamugaGeofenceOptions(
geofences: const <HamugaRuntimeGeofence>[
HamugaRuntimeGeofence(
id: 'hq',
label: 'HQ',
geometry: HamugaGeofenceCircle(
centerLat: 47.9131732,
centerLon: 106.9267709,
radiusM: 50,
),
),
],
backgroundMonitoring: const HamugaGeofenceBackgroundMonitoringOptions(
enabled: true,
),
showDebugOverlay: true,
onTransition: (transition, state) {
debugPrint('${transition.name}: ${state.status.name}');
},
onEvent: (event, state) {
debugPrint('${event.type.name}: ${event.geofenceId}');
},
),
),
)
Одоогийн runtime behavior:
- Map дээр нэг эсвэл олон runtime geofence зурна
- Location update ирэх бүрт geofence бүрийг шалгана
inside,outside,unknownstatus хадгалнаchecked,entered,exited,errorevent history бүртгэнэ- Идэвхжүүлсэн үед circle geofence-ийг iOS/Android background monitoring-той синхрончилно
officeGeofence болон onTransition нь backward-compatible хэвээр. Шинэ integration-д geofences болон onEvent ашигла. Нийтлэгдсэн geofence quick notes-ийг doc/geofence/README.md-ээс, source-ийн дэлгэрэнгүйг repository-ийн docs/geofence/ directory-оос унш.
Platform тохиргоо #
iOS
Location эсвэл background monitoring ашиглах үед ios/Runner/Info.plist дотор дараах тохиргоог нэм:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Show your location on the Hamuga map.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Monitor geofences in the background.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Monitor geofences in the background.</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
permission_handler location compile flag шаардвал iOS Podfile-ийн post_install тохиргоонд PERMISSION_LOCATION=1 нэм.
Android
android/app/src/main/AndroidManifest.xml дотор location болон internet permission нэм:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
Local tile proxy ашиглавал application declaration дотор loopback cleartext traffic зөвшөөр:
<application
android:usesCleartextTraffic="true"
...>
maplibre_gl:0.24.1 Android-д Java 21 toolchain шаарддаг. JDK 17 ашиглавал invalid source release: 21 гарч болно.
Нийтийн API #
| API | Үүрэг |
|---|---|
HamugaApi.initialize(...) |
API key болон gateway default тохируулна. |
HamugaApi.suggest(query) |
Нэг search suggestion хүснэ. |
HamugaApi.poi(query, ...) |
POI хайж, viewport-оор хязгаарлаж болно. |
HamugaApi.planRoute(...) |
OTP route plan хүснэ. |
HamugaApi.calculateRoute(...) |
Valhalla route calculation хүснэ. |
HamugaImap |
Map болон optional search/geofence overlay зурна. |
HamugaImapConfig |
Style, camera, gesture болон API-key override тохируулна. |
HamugaImapOptions |
Control, location, callback, search, geofence болон editor тохируулна. |
HamugaImapController |
Imperative map helper болон geofence history action өгнө. |
HamugaTileProxy |
Local authenticated tile proxy эхлүүлж, зогсооно. |
Жишээ апп #
Flutter package-ийн directory-оос:
cd example
flutter pub get
flutter run
Example host app wiring ашиглаж байвал example/.env-ээс тохиргоо уншина:
HAMUGA_API_KEY=your_hamuga_api_key
GEOFENCE_BASE_URL=https://gateway.hamuga.mn
OFFICE_LAT=47.9131732
OFFICE_LON=106.9267709
OFFICE_RADIUS=50
GEOFENCE_BACKGROUND_MONITORING=true
GEOFENCE_ONLY_DURING_WORK_WINDOWS=false
Office coordinate байхгүй үед example mock office geofence ашиглана. Бодит API key-г commit бүү хий.
Түгээмэл асуудал #
- Map эсвэл tile ачаалахгүй:
HamugaApiinitialize хийж, custom style ашиглавал tile proxy ажиллаж буйг шалга.[HamugaTileProxy]log-ийг унш. - Device дээр map хоосон: iOS local-networking/ATS эсвэл Android cleartext тохиргоог шалга.
- My location ажиллахгүй: Runtime location permission болон
showMyLocationButton-ийг шалга. - Geofence
unknownхэвээр: API key,geofenceBaseUrl, circle coordinate/radius, permission болонshowDebugOverlay-г шалга. - Android source release 21 алдаа: MapLibre Android toolchain-д JDK 21 ашигла.
Хөгжүүлэлтийн шалгалт #
flutter pub get
flutter analyze
dart format . --line-length 120
flutter test
License #
Apache-2.0.