Added the actual ru.dgis.sdk:sdk-map + compose-map dependencies (from https://artifactory.2gis.dev/sdk-maven-release) instead of the Canvas placeholder guess. Verified the exact API surface by downloading the AARs directly and inspecting classes with javap (DGis.initialize, MapOptions, MapComposableState/MapComposable, CameraPosition/GeoPoint) rather than relying on possibly-stale docs. DgisSdkProvider lazily calls DGis.initialize() once per process, catching failure so a missing key doesn't crash the app; DgisMapView renders the real MapComposable when that succeeds, falling back to the old placeholder canvas otherwise. Important finding: the existing DGIS_API_KEY (2GIS's public REST/JS API key format) does NOT work with this native SDK. It requires a separate dgissdk.key file issued per-app-package from dev.2gis.com, placed in app/src/main/assets/ (gitignored). Documented in README. Without it the app still runs fine on the placeholder map. Also restricted ndk.abiFilters to arm64-v8a — the SDK's native libs otherwise balloon the APK from ~19MB to ~190MB. Verified: testDebugUnitTest passes, assembleDebug produces a working (arm64-only, ~69MB) APK. Not runtime-verified against a real map key or device — no emulator/device available in this environment. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5 KiB
guideCity
Android walking city-guide app. Detects the user's location, finds nearby landmarks, and narrates historical/architectural information about them by voice while showing a swipeable card stack. Starting city: Moscow.
Architecture
┌────────────────────┐
│ Android app │ Kotlin + Jetpack Compose
│ (android/) │ 2GIS map, on-device TTS,
└─────────┬──────────┘ location, Room favorites
│ HTTPS / REST (JSON)
┌─────────▼──────────┐
│ FastAPI backend │ Python, SQLAlchemy, Alembic
│ (backend/) │ Dockerized
└─────────┬──────────┘
│ SQL
┌─────────▼──────────┐
│ PostgreSQL+PostGIS │ cities / places / place_content
└────────────────────┘
backend/— FastAPI service exposing city/place/nearby-search endpoints, backed by PostgreSQL+PostGIS. Seebackend/for details.android/— Kotlin/Compose app skeleton (MVVM, Hilt, Retrofit, Room, DataStore, 2GIS MapKit, on-device TextToSpeech).
Backend quickstart
cp .env.example .env
docker compose up -d db
docker compose exec api alembic upgrade head # (once api image is built: docker compose up -d --build api adminer first)
docker compose exec api python -m seed.seed_loader --file seed/moscow_gorky_park.yaml
docker compose exec api python -m seed.seed_loader --file seed/moscow_red_square.yaml
docker compose exec api python -m seed.seed_loader --file seed/moscow_city.yaml
curl http://localhost:8000/api/v1/health
curl "http://localhost:8000/api/v1/nearby?lat=55.7525&lon=37.6231"
Swagger UI: http://localhost:8000/docs Adminer (DB inspection): http://localhost:8080
The api service binds 0.0.0.0:8000 (see docker-compose.yml), so it's
also reachable from other devices on the same LAN at
http://<this-machine's-LAN-IP>:8000/ — no extra config needed, just make
sure nothing (firewall, VPN) blocks port 8000 on that interface.
It's also reverse-proxied behind nginx at https://guidetest.vrubel.xyz/,
which works from anywhere (not just the local network) and is the preferred
API_BASE_URL for the Android app during this test phase.
Android quickstart
cp android/local.properties.example android/local.properties
# fill in sdk.dir and DGIS_API_KEY (test key: b4df01a8-61db-4cb9-8286-7e069495987d)
cd android && ./gradlew :app:assembleDebug
Point the app's API base URL (API_BASE_URL in local.properties) at
https://guidetest.vrubel.xyz/ (works from anywhere), http://10.0.2.2:8000/
for the emulator, or your machine's LAN IP for a physical device on the same
Wi-Fi/LAN.
Run unit tests before building — ./gradlew testDebugUnitTest, then
./gradlew :app:assembleDebug.
2GIS map SDK
The app depends on the real 2GIS MapKit SDK (ru.dgis.sdk:sdk-map +
compose-map, from https://artifactory.2gis.dev/sdk-maven-release, wired
up in settings.gradle.kts/app/build.gradle.kts). It needs a separate
key from the DGIS_API_KEY above:
DGIS_API_KEY(theb4df01a...value) is a 2GIS public REST/JS API key — not used by the native SDK at all currently.- The native MapKit SDK instead needs a
dgissdk.keyfile, issued per-app (tied to the package namecom.guidecity.app) from https://dev.2gis.com/. Place it atandroid/app/src/main/assets/dgissdk.key(gitignored — don't commit it).
Without that key file, DgisSdkProvider fails to initialize (logged, not
crashed) and DgisMapView falls back to a placeholder canvas rendering
(user location + nearby place dots, no real map tiles). Once a real key is
in place, the real map should render automatically — no code changes needed.
Also note: the SDK bundles native libraries per CPU architecture, which
balloons APK size a lot (~19MB → ~190MB unfiltered). app/build.gradle.kts
restricts ndk.abiFilters to arm64-v8a only (~69MB) since that covers
virtually all real devices today — remove that filter if you need to test
on an x86 emulator or 32-bit device.
Notes / current scope
This is iteration 1: Moscow only (Gorky Park, Red Square area, Moscow-City), no user accounts (favorites are local/Room-only), no speed/heading-aware auto content-length selection yet (reserved API params exist, unused). Nearby-search radius caps at 10km. Place markers aren't yet plotted on the real 2GIS map (only the placeholder does that) — follow-up work.
The 2GIS REST/JS API key above is used directly via
local.properties/BuildConfig for development convenience — don't ship it
as-is in a public repo. Same goes for dgissdk.key once you have one.