# Android

{% hint style="info" %}
Hackle Android SDK 는 Android API 16 이상 (4.1 Jelly Bean)을 지원합니다.
{% endhint %}

## 의존성 추가

[![](https://img.shields.io/maven-central/v/io.hackle/hackle-android-sdk)](https://central.sonatype.com/artifact/io.hackle/hackle-android-sdk)

```groovy
repositories {
  mavenCentral()
}
```

`build.gradle` 파일에 의존성을 추가합니다.

```groovy
dependencies {
  implementation 'io.hackle:hackle-android-sdk:2.66.1'
}
```

#### ProGuard

ProGuard를 사용하는 경우, aar 아티팩트에 난독화 규칙이 자동으로 포함됩니다. 이 경우가 아니라면 아래 규칙을 포함시켜야 합니다.

```
-keep class io.hackle.android.** { *; }
-keep class io.hackle.sdk.** { *; }
```

#### Third-party 의존성

핵클 Android SDK는 아래 third-party 의존성을 가지고 있습니다

<table><thead><tr><th width="450.45703125">라이브러리</th><th>설명</th></tr></thead><tbody><tr><td><code>com.squareup.okhttp3:okhttp:3.12.2</code></td><td>HTTP/HTTPS 클라이언트</td></tr><tr><td><code>com.google.code.gson:gson:2.8.6</code></td><td>JSON 직렬화/역직렬화</td></tr><tr><td><code>com.google.android.gms:play-services-base:17.3.0</code></td><td>Google Play Services 공통 모듈</td></tr></tbody></table>

## SDK 초기화

SDK를 사용하기 위해서 반드시 `HackleApp`을 초기화 해야 합니다.

* `HackleApp`을 초기화 하기 위해 SDK 키가 필요합니다.
* `HackleApp`은 SDK의 기능을 사용하기 위한 메소드들을 제공하는 클래스입니다.
* SDK 키는 핵클 대시보드 내 [SDK 연동 정보](https://dashboard.hackle.io/config/sdk-setting)에서 확인하실 수 있습니다.

초기화는 **비동기로 실행**되며, 핵클 서버로부터 필요한 정보들을 가져와서 SDK에 저장합니다.

{% hint style="warning" %}
초기화가 완료 되기 전에 A/B 테스트, 기능 플래그를 호출하면 기본 그룹(A), 꺼짐(false)을 리턴합니다.
{% endhint %}

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
import io.hackle.android.Hackle
import io.hackle.android.initialize

Hackle.initialize(applicationContext, YOUR_APP_SDK_KEY) {
  // SDK ready to use.
}
```

{% endtab %}

{% tab title="Java" %}

```java
import io.hackle.android.HackleApp;

HackleApp.initializeApp(getApplicationContext(), YOUR_APP_SDK_KEY);
```

{% endtab %}
{% endtabs %}

#### 권장 초기화 전략: 스플레시 화면을 통한 초기화

앱을 즉시 시작하지 않고 스플레시 화면을 표시하고 SDK를 초기화합니다. 이후 콜백을 통해 스플레시 화면을 닫고 사용자가 앱과 상호작용을 시작할 수 있도록 합니다.

### 초기화 시 사용자 주입

유저 정보를 포함하여 SDK를 초기화 할 수 있습니다.

* 유저 정보를 포함하지 않으면 로컬 스토리지에 저장된 유저 정보를 사용합니다.
* 유저 정보를 포함하는 경우 로컬 스토리지에 저장된 유저 정보는 사용하지 않습니다.
* 사용자 주입을 하지 않고, 로컬 스토리지에 저장된 유저 정보도 없는 경우 [Hackle Device ID](https://docs.hackle.io/getting-started/user-identifier)를 device id로 가지고 유저를 사용합니다.

{% hint style="info" %}
유저 정보는 SDK 초기화 이후에도 유저 정보 설정 함수를 통해 자유롭게 수정 할 수 있습니다.
{% endhint %}

{% hint style="warning" %}
초기화 시 주입한 유저 정보와 로컬 스토리지에 저장된 유저 정보는 병합하지 않습니다.

ex) 스토리지에 `userId: A` 가 저장된 상태에서 초기화 시 `deviceId: B` 를 주입하는 경우,\
`userId: null, deviceId: B`인 유저로 설정됩니다.
{% endhint %}

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
import io.hackle.android.Hackle
import io.hackle.android.initialize
import io.hackle.sdk.common.User

let user = User.builder()
    .userId("142")                  // 사용자 ID
    .deviceId("ae2182e0")           // 디바이스 ID
    .build()

Hackle.initialize(applicationContext, YOUR_APP_SDK_KEY, user) {
  // SDK ready to use.
}
```

{% endtab %}

{% tab title="Java" %}

```java
import io.hackle.android.HackleApp;
import io.hackle.sdk.common.User

User user = User.builder()
    .userId("142")                  // 사용자 ID
    .deviceId("ae2182e0")           // 디바이스 ID
    .build()

HackleApp.initializeApp(getApplicationContext(), YOUR_APP_SDK_KEY, user, () -> {
  // SDK ready to use.
});
```

{% endtab %}
{% endtabs %}

### 초기화 설정정보

설정정보를 포함하여 SDK를 초기화 할 수 있습니다.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
import io.hackle.android.Hackle
import io.hackle.android.HackleConfig
import io.hackle.android.initialize

val config = HackleConfig.builder()
  .build()

Hackle.initialize(applicationContext, YOUR_APP_SDK_KEY, config) {
  // SDK ready to use.
}
```

{% endtab %}

{% tab title="Java" %}

```java
import io.hackle.android.HackleApp;
import io.hackle.android.HackleConfig;

HackleConfig config = HackleConfig.builder()
  .build();

HackleApp.initializeApp(getApplicationContext(), YOUR_APP_SDK_KEY, config, () -> {
  // SDK ready to use.
});
```

{% endtab %}
{% endtabs %}

#### 설정 옵션

<table data-full-width="false"><thead><tr><th width="222.29296875">설정</th><th width="295.48828125">기능</th><th width="125.8125">기본값</th><th width="101.90234375">지원 버전</th></tr></thead><tbody><tr><td><code>exposureEventDedupIntervalMillis</code><sup>*</sup></td><td><p>동일한 사용자가 연속으로 발생시킨 동일한 A/B 테스트, 기능플래그 분배결과에 대한 노출 이벤트를 제거합니다.</p><ul><li>최솟값: 1000 (1초)</li><li>최댓값: 86400000(24시간)</li></ul></td><td>60000 (1분)</td><td>2.7.0+</td></tr><tr><td><code>eventFlushIntervalMillis</code></td><td><p>수집된 이벤트를 서버로 전송하는 주기입니다.</p><ul><li>최솟값: 1000 (1초)</li><li>최댓값: 60000 (1분)</li></ul></td><td>10000 (10초)</td><td>2.10.0+</td></tr><tr><td><code>pollingIntervalMillis</code></td><td><p>대시보드에서 설정한 정보를 주기적으로 업데이트 할 수 있습니다.</p><ul><li>최솟값 : 60000 (60초)</li></ul></td><td>-1<br>(주기적으로 업데이트하지 않음)</td><td>2.19.0+</td></tr><tr><td><code>automaticScreenTracking</code></td><td>화면 자동 추적 활성화 여부</td><td><code>true</code></td><td>2.39.0+</td></tr><tr><td><code>automaticAppLifecycleTracking</code></td><td>앱 시작 / 종료 자동 추적 활성화 여부</td><td><code>true</code></td><td>2.64.0+</td></tr><tr><td><code>sessionPolicy</code></td><td>세션 유지 조건과 만료 조건을 설정합니다.</td><td><p><code>ALWAYS_NEW_SESSION</code> ,</p><p><code>1800000</code></p></td><td>2.65.0+</td></tr><tr><td><code>optOutTracking</code></td><td>옵트아웃 활성화 여부.</td><td><code>false</code></td><td>2.65.0+</td></tr><tr><td><code>sessionTimeoutMillis</code><br>(deprecated)</td><td>세션만료 시간을 설정합니다. <code>sessionPolicy</code>를 사용해 주세요.</td><td>1800000<br>(30분)</td><td>2.13.0+</td></tr></tbody></table>

> <sup>\*</sup> 2.47.0 이후부터 앱 종료 후 재시작 시에도 지원합니다.\ <sup>\*</sup> 2.47.0 미만버전의 경우 최댓값은 : 3600000 (1시간) 입니다.

#### 세션 정책 설정

세션 정책을 설정하여 세션의 유지 조건과 만료 조건을 제어할 수 있습니다.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val sessionPolicy = HackleSessionPolicy.builder()
    .persistCondition(HackleSessionPersistCondition.NULL_TO_USER_ID)
    .timeoutCondition(
        HackleSessionTimeoutCondition.builder()
            .millis(3600000)
            .onForeground(false)
            .onBackground(true)
            .onApplicationStateChange(true)
            .build()
    )
    .build()

val config = HackleConfig.builder()
    .sessionPolicy(sessionPolicy)
    .build()

Hackle.initialize(applicationContext, YOUR_APP_SDK_KEY, config) {
    // SDK ready to use.
}
```

{% endtab %}

{% tab title="Java" %}

```java
HackleSessionTimeoutCondition timeoutCondition = HackleSessionTimeoutCondition.builder()
    .millis(3600000)
    .onForeground(false)
    .onBackground(true)
    .onApplicationStateChange(true)
    .build();

HackleSessionPolicy sessionPolicy = HackleSessionPolicy.builder()
    .persistCondition(HackleSessionPersistCondition.NULL_TO_USER_ID)
    .timeoutCondition(timeoutCondition)
    .build();

HackleConfig config = HackleConfig.builder()
    .sessionPolicy(sessionPolicy)
    .build();

HackleApp.initializeApp(getApplicationContext(), YOUR_APP_SDK_KEY, config, () -> {
    // SDK ready to use.
});
```

{% endtab %}
{% endtabs %}

### 인스턴스 가져오기

초기화 이후 아래 코드를 통해 `HackleApp` 인스턴스를 가져올 수 있습니다.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
import io.hackle.android.Hackle
import io.hackle.android.app

val hackleApp = Hackle.app
```

{% endtab %}

{% tab title="Java" %}

```java
import io.hackle.android.HackleApp;

HackleApp hackleApp = HackleApp.getInstance();
```

{% endtab %}
{% endtabs %}

### 대시보드 설정 정보 갱신

초기화 이후 대시 보드 설정 정보 갱신이 필요한 경우 명시적으로 갱신 할 수 있습니다.

{% hint style="warning" %}
해당 함수는 60초에 한번 제한적으로 호출할 수 있습니다.
{% endhint %}

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
hackleApp.fetch {
  // done
}
```

{% endtab %}

{% tab title="Java" %}

```java
hackleApp.fetch(new Runnable() {
    @Override
    public void run() {
        // done
    }
});
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hackle.io/development-guide/android.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
