PowerMap Android SDK
A professional-grade, high-performance Map SDK for Android.
You can download the .aar file directly and install it into your project:
- Download the latest release from: http://download.powermap.live/#sdks
- Copy the downloaded
powermap-sdk-release.aarinto your app module'slibsdirectory:app/libs/ - Add the dependency pointing to your local file in your
build.gradle.kts(app level):
dependencies {
implementation(files("libs/powermap-sdk-release.aar"))
// Note: When loading a local .aar file manually, you may also need to
// include the SDK's transitive dependencies (MapLibre, Compose, etc.)
// inside this file as well.
}
The PowerMap Android SDK is built with a Layered Facade Architecture, ensuring that high-performance native rendering is wrapped in an easy-to-use Kotlin API.
graph TD
App[Android App] --> PowerMap[PowerMapView]
PowerMap --> Controller[PowerMapController]
subgraph "Facade Layer"
Controller
end
subgraph "Manager Layer"
Controller --> MarkerMgr[MarkerManager]
Controller --> SearchMgr[SearchManager]
Controller --> RouteMgr[RoutingManager]
Controller --> GeomMgr[GeometryManager]
Controller --> TrackingMgr[TrackingManager]
Controller --> CameraMgr[CameraManager]
end
subgraph "Service Layer"
MarkerMgr --> TileSvc[TileService]
SearchMgr --> GeoSvc[GeocodingProvider]
TileSvc --> Cache[3-Layer Cache]
end
subgraph "Native Engine"
PowerMap --> NativeEngine[High-Performance OpenGL/Vulkan Rendering]
end
Cache -.-> Disk[(Local Storage)]
Cache -.-> CDN((PowerMap CDN))
- Unified Facade:
PowerMapControllerprovides a single entry point for all features, matching the Web and Flutter DX. - Native Rendering: Symbols, Lines, and Polygons are rendered via MapLibre/OpenGL for gorgeous 60FPS performance.
- Coroutines Native: Fully asynchronous APIs (
search,addRoute, etc.) built seamlessly with Kotlin Coroutines.
Get a map up and running in less than 2 minutes.
Step A: Initialize Dual-Auth
Setup the SDK with your API keys globally in your Application class or main Activity.
import com.powermap.sdk.PowerMapSDK
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
PowerMapSDK.initialize(
context = this,
apiKey = "YOUR_MAP_API_KEY", // Public key for tiles/base layers
clientId = "YOUR_CLIENT_ID", // Core Service Credentials
clientSecret = "YOUR_CLIENT_SECRET"
)
}
}
Step B: The Map View
You can add PowerMapView directly via XML or instantiate it programmatically.
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.powermap.sdk.ui.PowerMapView
import com.powermap.sdk.PowerMapStyle
import org.maplibre.android.geometry.LatLng
class MapActivity : AppCompatActivity() {
private lateinit var mapView: PowerMapView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mapView = PowerMapView(this)
setContentView(mapView)
mapView.initialize(
style = PowerMapStyle.DARK, // TH, EN, DARK, GRAY
initialCenter = LatLng(13.7563, 100.5018), // Bangkok
initialZoom = 14.0
) { controller ->
// The map is fully loaded and safe to manipulate!
controller.setOnMapClickListener { coords ->
println("Tapped at: $coords")
true
}
}
}
}
PowerMapView.initialize Options
| Parameter | Type | Default | Description |
|---|---|---|---|
style |
PowerMapStyle |
PowerMapStyle.TH |
Base tile style (TH, EN, DARK, GRAY). |
initialCenter |
LatLng |
LatLng(13.7563, 100.5018) |
The initial center point of the map. |
initialZoom |
Double |
14.0 |
Initial viewport zoom level (0-22). |
onMapReady |
(PowerMapController) -> Unit |
Required | Triggered when the GL context is fully initialized. |
Global Event Listeners (on PowerMapController)
setOnMapClickListener { latLng -> ... }setOnPoiClickListener { jsonElement -> ... }setOnMapLongClickListener { latLng -> ... }setOnErrorListener { throwable -> ... }
The SDK renders native Symbol Layers for highest drawing performance.
Core Marker Methods
| Method | Arguments | Description |
|---|---|---|
addMarker(position, ...) |
LatLng, color?, iconImage?, size?, data? |
Adds a GL-rendered map symbol marker. Best for performance. |
clearMarkers() |
- | Removes all GL symbols and circles. |
setOnMarkerClickListener |
(LatLng) -> Unit |
Intercepts click events on rendered markers. |
High Performance GL Markers
Best for large datasets. Rendered directly by the GPU.
// In your initialization callback:
val myMarker = controller.markers.addMarker(
position = LatLng(13.76, 100.50),
color = "#f97316", // Vibrant Orange natively parsed pinpoint
size = 1.5f
)
// Add an interactive tap listener
controller.setOnMarkerClickListener { latLng ->
println("Marker tapped! $latLng")
}
Directly manipulate the map viewport matching the fluidity of the Flutter SDK.
Movement Methods
| Method | Arguments | Description |
|---|---|---|
moveCamera(target, ...) |
LatLng, zoom?, tilt?, bearing?, durationMs? |
Smooth fly-to animation with optional rotations. |
flyTo(target, zoom) |
LatLng, Double |
Alias for moving the camera directly. |
zoomIn() / zoomOut() |
- | Modifies zoom level by 1.0 with smooth animation. |
setTilt(deg) / setPitch |
Double |
Set tilt angle (0 = 2D, 60+ = 3D). |
setBearing(deg) |
Double |
Set direction (0 = North). |
tiltUp() |
- | Shortcut to animate the camera to a 3D perspective view (60 degrees). |
tiltDown() |
- | Shortcut to animate back to a top-down view (0 degrees). |
State Properties
| Method | Returns | Description |
|---|---|---|
getCenter() |
LatLng? |
Returns current view center. |
getZoom() |
Double? |
Returns current map zoom level. |
getBearing() |
Double? |
Returns current map rotation. |
getTilt() |
Double? |
Returns current camera pitch. |
controller.moveCamera(
target = LatLng(13.7649, 100.5383),
zoom = 17.0,
tilt = 60.0,
bearing = 90.0
)
Calculate logistics-grade paths containing step-by-step metadata. Will automatically draw the route line on the map.
addRoute() Options
| Option | Type | Default | Description |
|---|---|---|---|
start |
LatLng |
Required | Origin coordinate. |
destination |
LatLng |
Required | Final destination coordinate. |
waypoints |
List<LatLng> |
emptyList() |
Stops between origin and destination (Max 25). |
optimize |
Boolean |
false |
If true, applies TSP logic to reorder waypoints. |
profile |
String |
"driving" |
Modes: "driving", "walking", "cycling". |
language |
String |
"th" |
Output instruction language: "th", "en". |
lifecycleScope.launch {
val route = controller.addRoute(
start = LatLng(13.7468, 100.5346),
destination = LatLng(13.7649, 100.5383),
optimize = true
)
println("Route calculated! Distance: ${route?.distanceStr}")
}
The Mobile SDK features Coroutine-based geocoding mirroring the Web SDK while adding safety boundaries like Debouncing and LRU Caching (50 items).
Search Methods
| Method | Execution | Description |
|---|---|---|
search() |
suspend |
Standard forward search. Checks local LRU Cache first. |
searchByCategory() |
suspend |
Searches for places nearby a location using a category ID (e.g. "2100" for Restaurant). |
autocompleteDebounced() |
Callback |
Safe to bind to UI inputs. Custom delay prevents quota burn. |
reverseGeocode() |
suspend |
Converts coordinates into a structured address. |
clearSearchCache() |
sync |
Clears the internal LRU cache manually. |
Language Detection (lang Parameter)
The lang parameter controls which search endpoint is used. The SDK automatically detects the language from the query text and passes the appropriate value:
lang value |
Endpoint | When to use |
|---|---|---|
"th" (default) |
/api/v2/map/address_th |
Query contains Thai characters only |
"en" |
/api/v2/map/address_en |
Query contains Latin/English characters only |
"mixed" |
/api/v2/map/address |
Query contains both Thai and English |
U+0E00–U+0E7F) and Latin (U+0041–U+007A). If a query contains both, "mixed" is passed to use the unified endpoint.// Language is detected automatically in powermap-android-sdk-demo:
fun detectLang(q: String): String {
val hasLatin = q.any { it.code in 0x41..0x7A }
val hasThai = q.any { it.code in 0x0E00..0x0E7F }
return when {
hasLatin && !hasThai -> "en"
hasLatin && hasThai -> "mixed"
else -> "th"
}
}
// Then pass it to the search call:
val lang = detectLang(query)
controller.autocompleteDebounced(
query = query,
delayMs = 500,
lang = lang
) { results ->
println("Found: ${results.first().name}")
}
// Or use with suspend search():
lifecycleScope.launch {
val results = controller.search("Central World", lang = "en")
println("Found: ${results.first().name} at ${results.first().position}")
}
// Category Search (e.g. Restaurants near current location)
lifecycleScope.launch {
val myLocation = controller.getCurrentLocation()
if (myLocation != null) {
val restaurants = controller.searchByCategory("2100", myLocation, dist = 5)
println("Found ${restaurants.size} restaurants nearby!")
}
}
// Reverse Geocode (Lat/Lng to Address)
lifecycleScope.launch {
val response = controller.reverseGeocode(LatLng(14.2558, 100.9810))
println("Address: ${response?.name}")
}
The SDK features a robust GeometryManager that natively handles GeoJSON, making it incredibly easy to visualize Custom Geofences or 3D buildings.
Geometry API Reference
| Method | Execution | Description |
|---|---|---|
addGeoJson() |
sync |
Injects raw GeoJSON data into the map source. |
importGeoJson() |
sync |
Parses GeoJSON and automatically renders layers based on Polygon, LineString, or Point types. |
addPolygonLayer() |
sync |
Renders Fills and Outlines. Mix with fillOpacity to create interactive Geofences. |
addPolylineLayer() |
sync |
Renders colored paths/lines with customizable thickness. |
addIndoorExtrusionLayer() |
sync |
Automatically extrudes Polygons into 3D assuming data has a height property. |
// 1. Prepare your Geometry Data (GeoJSON format: Lng, Lat)
val geofenceData = mapOf(
"type" to "Feature",
"geometry" to mapOf(
"type" to "Polygon",
"coordinates" to listOf(listOf(
listOf(100.534, 13.746), listOf(100.538, 13.746),
listOf(100.538, 13.749), listOf(100.534, 13.749),
listOf(100.534, 13.746) // Must close the loop
))
)
)
// 2. Inject Data into the Map Source
controller.geometry.addGeoJson("my-geofence", geofenceData)
// 3. Apply Visual Styles to that Source ID
controller.geometry.addPolygonLayer(
sourceId = "my-geofence",
fillColor = "#4264fb",
fillOpacity = 0.5f,
outlineColor = "#000000"
)
Highly integrated with FusedLocationProviderClient for battery-efficient, high-accuracy GPS positioning.
Core Methods
| Method | Returns | Description |
|---|---|---|
enableFollowMode() |
suspend Unit |
Locks camera on device GPS location. |
enableFollowModeWithCompass() |
suspend Unit |
Locks camera + rotates to match device heading with 3D tilt. |
disableFollowMode() |
sync |
Unlocks camera, stops tracking. |
getCurrentLocation() |
suspend LatLng? |
One-shot GPS request. |
requestPermission() |
suspend Boolean |
Checks and requests location permission automatically. |
showUserLocation(true) |
sync |
Enables visual blue dot indicator. |
lifecycleScope.launch {
// 1. One-shot: Get current coordinates
val myLocation = controller.getCurrentLocation()
// 2. Navigation mode with compass heading (3D view)
controller.enableFollowModeWithCompass()
// 3. Stop tracking later
controller.disableFollowMode()
}
Global tracking for SDK crashes or network failures is handled seamlessly.
controller.setOnErrorListener { throwable ->
println("PowerMap Error Detected: ${throwable.message}")
// Handle gracefully in UI
}
Browse our generated Dokka guides to see the comprehensive API surface. Start with PowerMapView and PowerMapController as your primary integration points.
© 2026 PowerMap Development Team. All rights reserved.