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

# Android SDK

> SDK Version 0.0.11

## 패키지 선언

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
import co.onecheck.ones1ght.android.*           // OneS1ght · FloorSession · SdkError · 리스너
import co.onecheck.ones1ght.android.model.*     // Building · Floor · Zone · Coordinates · Trigger · ConfigChange
import co.onecheck.ones1ght.android.network.ApiError
import co.onecheck.ones1ght.android.runtime.LogLevel
```

```java Java icon="java" theme={null}
import co.onecheck.ones1ght.android.*;          // OneS1ght · FloorSession · SdkError · Callback · 리스너
import co.onecheck.ones1ght.android.model.*;    // Building · Floor · Zone · Coordinates · Trigger · ConfigChange
import co.onecheck.ones1ght.android.network.ApiError;
import co.onecheck.ones1ght.android.runtime.LogLevel;
```

## 초기화

### .initialize

OneS1ght API 키로 측위엔진을 초기화합니다. 자체 서버를 구축한 경우에만 `baseUrl` 을 넘깁니다(기본값 `OneS1ght.DEFAULT_BASE_URL`).

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
OneS1ght.initialize(context = context.applicationContext, sdkKey = "YOUR_SDK_KEY")
```

```java Java icon="java" theme={null}
OneS1ght.initialize(context, "YOUR_SDK_KEY", new Callback<Void>() {
    @Override public void onSuccess(Void result) { }
    @Override public void onError(Throwable error) { }
});
```

### .requestPermission

측위엔진 사용을 위한 앱 권한을 요청합니다.

| 결과 | 뜻 |
| - | - |
| `AUTHORIZED` | 측위 가능 |
| `DENIED` | 권한 거부됨 |
| `UNSUPPORTED` | 측위 미지원 기기 |

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val status = OneS1ght.requestPermission(activity)
```

```java Java icon="java" theme={null}
OneS1ght.requestPermission(activity, new Callback<PermissionStatus>() {
    @Override public void onSuccess(PermissionStatus status) { }
    @Override public void onError(Throwable error) { }
});
```

### .setLanguage

SDK 로그 문구 언어를 설정합니다.\

`ko` : 한국어,  `ja` : 일본어,  `en` : 영어, `null` : 시스템 설정 언어

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
OneS1ght.setLanguage("ko")
```

```java Java icon="java" theme={null}
OneS1ght.setLanguage("ko");
```

### .onDebugLog

SDK 로그를 수신합니다.\

`level` : 로그 레벨, `message` : 로그 메세지

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
OneS1ght.onDebugLog = DebugLogListener { level, message ->
    if (level >= LogLevel.WARN) Log.w("OneS1ght", message)
}
```

```java Java icon="java" theme={null}
OneS1ght.setOnDebugLog((level, message) -> {
    if (level.compareTo(LogLevel.WARN) >= 0) Log.w("OneS1ght", message);
});
```

### .reset

세션을 버리고 측위를 멈추며, 저장된 키와 건물 정보를 지웁니다. 이후 `initialize` 를 다시 불러야 합니다(그 전엔 `NotInitialized`, `E1001`).

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
OneS1ght.reset()
```

```java Java icon="java" theme={null}
OneS1ght.reset(new Callback<Void>() {
    @Override public void onSuccess(Void result) { }
    @Override public void onError(Throwable error) { }
});
```

## 상태 조회

### .isInitialized

초기화 성공 확인 여부를 반환합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val ready = OneS1ght.isInitialized
```

```java Java icon="java" theme={null}
boolean ready = OneS1ght.isInitialized();
```

### .deviceAvailability

측위 가능 기기를 판별하고 미지원시 사유를 반환합니다. `initialize()` 뒤에 읽습니다 — 그 전엔 `DEVICE_NOT_SUPPORTED`(Android 17 미만은 `OS_VERSION_TOO_LOW`)입니다.

| 값 | 뜻 |
| - | - |
| `AVAILABLE` | 측위 가능 |
| `OS_VERSION_TOO_LOW` | Android 17(API 37) 미만 |
| `DEVICE_NOT_SUPPORTED` | UWB 미지원 기기 |

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
when (OneS1ght.deviceAvailability) {   // initialize() 뒤에
    DeviceAvailability.AVAILABLE            -> Unit
    DeviceAvailability.OS_VERSION_TOO_LOW   -> Unit
    DeviceAvailability.DEVICE_NOT_SUPPORTED -> Unit
    else                                    -> Unit
}
```

```java Java icon="java" theme={null}
DeviceAvailability availability = OneS1ght.getDeviceAvailability();
boolean available = OneS1ght.isDeviceAvailable();
```

### .googleMapKey

도면을 표시할 Google Maps API 키를 반환합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val mapKey = OneS1ght.googleMapKey   // String?
```

```java Java icon="java" theme={null}
String mapKey = OneS1ght.getGoogleMapKey();
```

### .SDK\_VERSION

사용중인 SDK 버전을 반환합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val version = OneS1ght.SDK_VERSION   // "0.0.11"
```

```java Java icon="java" theme={null}
String version = OneS1ght.SDK_VERSION;
```

## 프로필

### .createProfile

새로운 개인화 프로필을 생성합니다. 성공적으로 생성하면 고유 프로필 ID를 반환합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val profileId = OneS1ght.createProfile(mapOf("gender" to "F", "ageBand" to "20s"))
```

```java Java icon="java" theme={null}
Map<String, String> attributes = new HashMap<>();
attributes.put("gender", "F");
attributes.put("ageBand", "20s");
OneS1ght.createProfile(attributes, new Callback<String>() {
    @Override public void onSuccess(String profileId) { }
    @Override public void onError(Throwable error) { }
});
```

### .identify

수집할 측위 데이터를 묶을 프로필을 연결합니다. 연결 해제시 `null`으로 설정하세요.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
OneS1ght.identify(profileId)
```

```java Java icon="java" theme={null}
OneS1ght.identify(profileId);
```

### .fetchProfile

프로필의 속성을 조회합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val attributes = OneS1ght.fetchProfile(profileId)
```

```java Java icon="java" theme={null}
OneS1ght.fetchProfile(profileId, new Callback<Map<String, String>>() {
    @Override public void onSuccess(Map<String, String> attributes) { }
    @Override public void onError(Throwable error) { }
});
```

### .replaceProfile

프로필 속성을 교체하며 이전 데이터는 삭제됩니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
OneS1ght.replaceProfile(profileId, mapOf("gender" to "F", "ageBand" to "30s"))
```

```java Java icon="java" theme={null}
Map<String, String> attributes = new HashMap<>();
attributes.put("gender", "F");
attributes.put("ageBand", "30s");
OneS1ght.replaceProfile(profileId, attributes, new Callback<Void>() {
    @Override public void onSuccess(Void result) { }
    @Override public void onError(Throwable error) { }
});
```

### .deleteProfile

프로필 정보를 영구 삭제합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
OneS1ght.deleteProfile(profileId)
```

```java Java icon="java" theme={null}
OneS1ght.deleteProfile(profileId, new Callback<Void>() {
    @Override public void onSuccess(Void result) { }
    @Override public void onError(Throwable error) { }
});
```

## 공간 조회

### .buildings

테넌트와 연관된 모든 건물 목록을 조회합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val buildings = OneS1ght.buildings()
val building = OneS1ght.building(id = buildingId)
```

```java Java icon="java" theme={null}
OneS1ght.buildings(new Callback<List<Building>>() {
    @Override public void onSuccess(List<Building> buildings) { }
    @Override public void onError(Throwable error) { }
});
```

### .floors

건물의 층 목록을 조회합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val floors = OneS1ght.floors(buildingId)
```

```java Java icon="java" theme={null}
OneS1ght.floors(buildingId, new Callback<List<Floor>>() {
    @Override public void onSuccess(List<Floor> floors) { }
    @Override public void onError(Throwable error) { }
});
```

### .floor

선택한 층의 상세 정보를 조회합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val floor = OneS1ght.floor(buildingId, floorId)
val png = floor.image   // ByteArray?
```

```java Java icon="java" theme={null}
OneS1ght.floor(buildingId, floorId, new Callback<Floor>() {
    @Override public void onSuccess(Floor floor) { byte[] png = floor.getImage(); }
    @Override public void onError(Throwable error) { }
});
```

### .zones

선택한 층의 모든 구역을 조회합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val zones = OneS1ght.zones(buildingId, floorId)
val zone = OneS1ght.zone(buildingId, floorId, zoneId)
```

```java Java icon="java" theme={null}
OneS1ght.zones(buildingId, floorId, new Callback<List<Zone>>() {
    @Override public void onSuccess(List<Zone> zones) { }
    @Override public void onError(Throwable error) { }
});
```

### .locators

선택한 층의 로케이터 정보를 조회합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val floorLocators = OneS1ght.locators(buildingId, floorId)
val ready = floorLocators.positioningReady
```

```java Java icon="java" theme={null}
OneS1ght.locators(buildingId, floorId, new Callback<FloorLocators>() {
    @Override public void onSuccess(FloorLocators floorLocators) { }
    @Override public void onError(Throwable error) { }
});
```

## 층 지정

### .setFloorMap

구역 이벤트에 쓸 층을 지정합니다(선택). 지정하지 않아도 좌표는 나오지만, 구역 이벤트 · 시책을 받으려면 필요합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val floor = OneS1ght.floor(buildingId, floorId)
OneS1ght.setFloorMap(floor, buildingId)
```

```java Java icon="java" theme={null}
OneS1ght.floor(buildingId, floorId, new Callback<Floor>() {
    @Override public void onSuccess(Floor floor) {
        OneS1ght.setFloorMap(floor, buildingId, new Callback<Void>() {
            @Override public void onSuccess(Void result) { }
            @Override public void onError(Throwable error) { }
        });
    }
    @Override public void onError(Throwable error) { }
});
```

### .refreshZones

최신화된 구역 정보를 조회합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val zones = OneS1ght.refreshZones()
```

```java Java icon="java" theme={null}
OneS1ght.refreshZones(new Callback<List<Zone>>() {
    @Override public void onSuccess(List<Zone> zones) { }
    @Override public void onError(Throwable error) { }
});
```

## 측위 세션

### .floorSession

측위 세션을 반환합니다. 층과 무관한 앱 전체 단일 인스턴스이며, `initialize` 전에는 `NotInitialized` 를 던집니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val session = OneS1ght.floorSession()
```

```java Java icon="java" theme={null}
FloorSession session = OneS1ght.floorSession();
```

### .begin

사용자 측위를 시작합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.begin()
```

```java Java icon="java" theme={null}
session.begin(new Callback<Void>() {
    @Override public void onSuccess(Void result) { }
    @Override public void onError(Throwable error) { }
});
```

### .end

사용자 측위를 종료합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.end()
```

```java Java icon="java" theme={null}
session.end(new Callback<Void>() {
    @Override public void onSuccess(Void result) { }
    @Override public void onError(Throwable error) { }
});
```

### .pause · .resume

사용자 측위를 중지, 재개합니다. 종료와 달리 SDK 내 측위 엔진은 종료하지 않습니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.pause()
session.resume()
```

```java Java icon="java" theme={null}
session.pause();
session.resume();
```

### .isRunning · .isPaused

측위 상태여부와 중지여부를 반환합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
val running = session.isRunning
val paused = session.isPaused
val current = session.floor   // Floor?
```

```java Java icon="java" theme={null}
boolean running = session.isRunning();
boolean paused = session.isPaused();
Floor current = session.getFloor();
```

## 세션 이벤트

### .onPosition

실시간으로 사용자 좌표를 전달합니다. 엔진이 내는 속도 그대로 오며, 서버 전송만 콘솔 설정값(기본 초당 4회)으로 줄입니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.onPosition = PositionListener { coordinates -> Log.d("OneS1ght", "${coordinates.x}, ${coordinates.y}") }
```

```java Java icon="java" theme={null}
session.setOnPosition(coordinates -> Log.d("OneS1ght", coordinates.getX() + ", " + coordinates.getY()));
```

### .onZoneEnter · .onZoneExit

구역 진입, 이탈시 이벤트가 동작합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.onZoneEnter = ZoneListener { zone -> Log.d("OneS1ght", "IN ${zone.name}") }
session.onZoneExit  = ZoneListener { zone -> Log.d("OneS1ght", "OUT ${zone.name}") }
```

```java Java icon="java" theme={null}
session.setOnZoneEnter(zone -> Log.d("OneS1ght", "IN " + zone.getName()));
session.setOnZoneExit(zone -> Log.d("OneS1ght", "OUT " + zone.getName()));
```

### .onZoneDwell

특정 구역의 체류 시간이 초과할 경우(`dwellSeconds` 기준) 이벤트가 발생합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.onZoneDwell = DwellListener { zone, seconds -> Log.d("OneS1ght", "DWELL ${zone.name} ${seconds}s") }
```

```java Java icon="java" theme={null}
session.setOnZoneDwell((zone, seconds) -> Log.d("OneS1ght", "DWELL " + zone.getName() + " " + seconds));
```

### .onTriggers

공간 내 이벤트(또는 시책) 동작시 이벤트가 발생합니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.onTriggers = TriggersListener { zoneId, triggers ->
    triggers.forEach { trigger -> Log.d("OneS1ght", "${trigger.type} ${trigger.payload}") }
}
```

```java Java icon="java" theme={null}
session.setOnTriggers((zoneId, triggers) -> {
    for (Trigger trigger : triggers) Log.d("OneS1ght", trigger.getType());
});
```

### .onFloorDetected

엔진이 로케이터 BLE 신호로 층을 찾으면 층 ID 로, 층을 잃으면 `null` 로 호출됩니다.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.onFloorDetected = SessionFloorListener { floorId ->
    if (floorId == null) return@SessionFloorListener
    lifecycleScope.launch {
        val floor = OneS1ght.floor(buildingId, floorId)
        OneS1ght.setFloorMap(floor, buildingId)
    }
}
```

```java Java icon="java" theme={null}
session.setOnFloorDetected(floorId -> {
    if (floorId == null) return;
    OneS1ght.floor(buildingId, floorId, new Callback<Floor>() {
        @Override public void onSuccess(Floor floor) {
            OneS1ght.setFloorMap(floor, buildingId, new Callback<Void>() {
                @Override public void onSuccess(Void result) { }
                @Override public void onError(Throwable error) { }
            });
        }
        @Override public void onError(Throwable error) { }
    });
});
```

### .onStopped

사용자 측위가 중지된 경우 이벤트가 발생합니다.

| 이유 | 뜻 |
| - | - |
| `ENDED` | `end()` · `reset` · 키 교체 |
| `ENGINE_FAILED` | 측위엔진 구동 실패시 |

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.onStopped = SessionStoppedListener { reason ->
    when (reason) {
        FloorSession.StopReason.ENDED         -> Unit
        FloorSession.StopReason.ENGINE_FAILED -> Unit
        else                                  -> Unit
    }
}
```

```java Java icon="java" theme={null}
session.setOnStopped(reason -> {
    if (reason == FloorSession.StopReason.ENGINE_FAILED) { }
});
```

### .onConfigChanged

콘솔 페이지에서 설정이 변경되었을 경우 이벤트가 발생합니다.

| 신호 | 의미 |
| - | - |
| `ZonesChanged(floorId)` | 구역 변경 |
| `PlanChanged(floorId)` | 도면 변경 |
| `RulesChanged(zoneId)` | 시책 변경 |
| `SdkConfigChanged` | 원격 설정 변경 |
| `ResyncNeeded` | 재연결 · 이벤트 누락 |

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
session.onConfigChanged = ConfigChangeListener { change ->
    when (change) {
        is ConfigChange.ZonesChanged, is ConfigChange.ResyncNeeded -> lifecycleScope.launch { OneS1ght.refreshZones() }
        is ConfigChange.PlanChanged -> redrawFloor()
        else -> Unit
    }
}
```

```java Java icon="java" theme={null}
session.setOnConfigChanged(change -> {
    if (change instanceof ConfigChange.ZonesChanged || change instanceof ConfigChange.ResyncNeeded) {
        OneS1ght.refreshZones(new Callback<List<Zone>>() {
            @Override public void onSuccess(List<Zone> zones) { }
            @Override public void onError(Throwable error) { }
        });
    }
});
```

## 데이터 전송

좌표는 300건 또는 60초마다, 그리고 백그라운드 진입과 `end()` 때 자동 전송됩니다.

### .uploadPendingPositions

쌓인 좌표 즉시 전송.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
OneS1ght.uploadPendingPositions()
```

```java Java icon="java" theme={null}
OneS1ght.uploadPendingPositions(new Callback<Void>() {
    @Override public void onSuccess(Void result) { }
    @Override public void onError(Throwable error) { }
});
```

### .discardPendingPositions

쌓인 좌표 폐기.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
OneS1ght.discardPendingPositions()
```

```java Java icon="java" theme={null}
OneS1ght.discardPendingPositions();
```

## 오류 처리

실패는 `SdkError`(SDK 상태) 와 `ApiError`(통신, `co.onecheck.ones1ght.android.network.ApiError`) 를 반환하며, 자세한 내용은 [에러 코드](/developers/sdk/troubleshooting/error-codes)를 참고하세요.

```kotlin Kotlin icon="https://mintcdn.com/onecheck/wv66PbaB8dD4xd9I/images/icons/kotlin.svg?fit=max&auto=format&n=wv66PbaB8dD4xd9I&q=85&s=3721cc48a6f44aef50ea7a0151e369f2" theme={null}
try {
    OneS1ght.initialize(context = context.applicationContext, sdkKey = key)
} catch (e: SdkError) {
    Log.w("OneS1ght", e.code.code)                     // "E1003"
} catch (e: ApiError) {
    Log.w("OneS1ght", "${e.code.code} ${e.message}")   // "E5005 …"
}
```

```java Java icon="java" theme={null}
OneS1ght.initialize(context, key, new Callback<Void>() {
    @Override public void onSuccess(Void result) { }
    @Override public void onError(Throwable error) {
        if (error instanceof SdkError) {
            Log.w("OneS1ght", ((SdkError) error).getCode().getCode());   // "E1003"
        } else if (error instanceof ApiError) {
            Log.w("OneS1ght", ((ApiError) error).getCode().getCode() + " " + error.getMessage());
        }
    }
});
```

## 모델

목록은 `List<T>`, 바이트는 `ByteArray` 입니다.

### Coordinates

| 필드 | 타입 | 설명 |
| - | - | - |
| `x` · `y` | `Double` | 도면 로컬 미터 |
| `z` | `Double` | 높이 |

### Building · Floor

| 타입 | 필드 | 설명 |
| - | - | - |
| `Building` | `id` · `name` | 건물 ID · 이름 |
| | `floorCount: Int?` | 층 수 |
| `Floor` | `id` · `name` | 층 ID · 이름 |
| | `image: ByteArray?` | 도면 PNG 바이트(디코딩됨) — 목록 조회에선 `null` |
| | `hasPlan: Boolean` | 도면 등록 여부 |
| | `originX` · `originY` | 도면 원점(미터) |
| | `widthM` · `heightM` | 도면 크기(미터) |
| | `minX` · `minY` · `maxX` · `maxY` | 배치 범위 |

### Locator · FloorLocators

| 타입 | 필드 | 설명 |
| - | - | - |
| `Locator` | `address: Int` | UWB MAC 뒤 2바이트 |
| | `x` · `y` · `z` | 도면 로컬 미터 |
| `FloorLocators` | `locators` | 층의 로케이터 목록 |
| | `sessionId: Int?` | UWB 세션 — 층마다 다름 |
| | `positioningReady: Boolean` | 로케이터와 세션이 모두 있는가 |

### Zone

| 필드 | 타입 | 설명 |
| - | - | - |
| `id` · `name` | `String` | 구역 ID · 이름 |
| `polygon` | `List<Position>` | 꼭짓점(`x`, `y` 미터) |
| `dwellSeconds` | `Int?` | 체류 이벤트 기준(초) |

### Trigger

| 필드 | 타입 | 설명 |
| - | - | - |
| `triggerId` | `String` | 트리거 ID |
| `type` | `String` | `signage` · `coupon` · `tracking` · `merch` · `generic` |
| `payload` | `Map<String, String>?` | 타입별 부가 정보 |

열거형(`ConfigChange` · `StopReason` · `PermissionStatus` · `DeviceAvailability` · `LogLevel`)은 마이너 버전에서 값이 늘 수 있습니다 — `when` 에 `else` 를 둡니다.

## 제약

* `suspend` API 는 어느 코루틴에서든 호출 가능. `identify` · `discardPendingPositions` · `pause` · `resume` 은 메인 스레드에서 사용합니다.
* UWB 측위는 포그라운드 전용입니다. 백그라운드로 가면 측위가 멈추고, 들어가 있던 구역은 이탈(`onZoneExit`)로 처리되며 실시간 수신이 끊깁니다. 돌아오면 측위가 다시 시작되고 `ResyncNeeded` 가 옵니다.
* 좌표 버퍼는 앱상 메모리에 임시 저장되며 강제 종료 시 미전송 좌표는 사라집니다.
* 에뮬레이터에서는 측위할 수 없습니다.


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