> ## Documentation Index
> Fetch the complete documentation index at: https://docs.loci.ng/llms.txt
> Use this file to discover all available pages before exploring further.

# Android SDK

> loci-map-android: a Kotlin map for field data collection. It draws work areas, lets a user draw inside them, and can fill itself from the frame index using an API key.

The LOCI Map SDK for Android puts a map in your Kotlin app for field data
collection. Your users draw points, lines and polygons inside their work
areas, and you get the GeoJSON back, checked against the boundaries.

The map works on its own with boundaries you already hold. To fill it from
LOCI instead, you give the SDK an **API key** and it preloads frames and the
data recorded on them over the same public API this site documents. The map
never calls the network itself: every request happens in an explicit preload
step before the map appears.

> [!NOTE]
>
> This is the standalone native SDK, for apps not built with Flutter. If your
> app is built with Flutter, use the [Flutter SDK](/sdks/flutter-overview)
> instead. A native iOS SDK (Swift) is [coming soon](/sdks/native).

> **[Quickstart](/sdks/android-quickstart)**
>
> Three steps to a working map, plus the example screen.

> **[The map](/sdks/android-maps)**
>
> Work areas, layers, drawing, events, the controller, and styling.

> **[Frames](/sdks/android-frames)**
>
> Initialise with a key and preload frames. The part that uses this API.

> **[Flutter SDK](/sdks/flutter-overview)**
>
> Building with Flutter? The [Flutter SDK](/sdks/flutter-overview) is the
> same map, driven from Dart.

## Install

Add the dependency to your app module.

```kotlin app/build.gradle.kts theme={null}
dependencies {
    implementation("africa.milsat.loci:loci-map-android:0.3.0")
}
```

The library gives you Esri and GeoJSON in, `DataFromMap` out, built-in
controls or your own, and a plain Kotlin API. No map key is needed for the
map to render; the only credential you supply is an API key, and only if you
use frames.

## Platform setup

### Requirements

* Minimum **Android 5.0 (API 21)**.

### Location permission

The map uses the device location for geofencing and **Locate Me**. Declare
the permissions, and request `ACCESS_FINE_LOCATION` at run time before the
map is used.

```xml AndroidManifest.xml theme={null}
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
```

```kotlin SurveyActivity.kt theme={null}
ActivityCompat.requestPermissions(
    activity,
    arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
    1,
)
```

### Lifecycle

* Create the `LociMapView` in `onCreate` and call `release()` in `onDestroy`.
* Use the view and the controller on the main thread. Events arrive on it.

## Two ways to use it

Both use the same view properties and callbacks. Your own buttons call
commands on `view.controller`.

> **Prebuilt view**
>
> `LociMapView` draws the map and the controls — options, locate, zoom,
> undo, redo, work areas, imagery, navigate, Draw and Save. Rename, hide or
> replace any of them.

> **Your own**
>
> Set `controls = LociMapControls.NONE` and call commands on
> `view.controller` from your own buttons.

```kotlin prebuilt theme={null}
val view = LociMapView(context)
view.options = MapOptions(mapId = "survey-1", geometry = DrawGeometry.POLYGON)
view.workAreas = workAreas
view.onSave = { data -> println(data.featureGeometry) }
```

```kotlin your own buttons theme={null}
val view = LociMapView(context)
view.controls = LociMapControls.NONE
view.options = MapOptions(mapId = "mine", geometry = DrawGeometry.POINT)
view.workAreas = workAreas
view.onDrawCompleted = { data -> println(data.featureGeometry) }

val draw = Button(context).apply {
    text = "Add house"
    setOnClickListener { view.controller.startDrawing() }
}
val undo = Button(context).apply {
    text = "Undo"
    setOnClickListener { view.controller.undo() }
}
val column = LinearLayout(context).apply {
    orientation = LinearLayout.VERTICAL
    addView(view, LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f))
    addView(draw)
    addView(undo)
}
```

## What the map needs, and what it does not

* **No map key** to render. The map works out of the box.
* **An API key** only if you preload frames from LOCI. See
  [Frames](/sdks/android-frames).
* **The location permission**, granted at run time before the map is used.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.