# Android

<figure><img src="https://169964493-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FwMb5WkedgvZ9Yk3Yxqep%2Fuploads%2FoCyaDTPB6oJRvlgbwXqa%2FFlutter.png?alt=media&#x26;token=d20e6582-bf40-40cc-96a5-06c601be77b4" alt=""><figcaption></figcaption></figure>

***

Android 가이드 문서는 아래 조건을 기준으로 작성되었습니다.

* 사용언어 : <mark style="color:blue;">`Kotlin`</mark>&#x20;
  * 해당 가이드는 코틀린 언어를 기반으로 작성되었습니다.
* 아키텍쳐 : <mark style="color:blue;">`ViewBinding`</mark>
  * 해당 가이드는 [<mark style="color:orange;">ViewBinding(뷰결합)</mark>](https://developer.android.com/develop/ui/views/layout/webapps/webview?hl=ko#EnablingJavaScript) 아키텍처로 작성되었습니다.
  * findViewByld 형식의 아키텍처를 사용하시는 경우, 자체적인 샘플 코드의 수정이 필요할 수 있습니다.

```kotlin
// build.gradle (:app)
android {
  // ...
  buildFeatures {
      viewBinding true
  }
  // ...
}
```

***

## 1단계: Activity 레이아웃 파일 생성

<mark style="color:blue;">`res/layout`</mark> 경로에 런처를 실행할 Activity 레이아웃 파일을 생성합니다.

{% hint style="warning" %}
파일명, 컴포넌트명, 속성값은 샘플로 작성된 명칭으로 수정하셔도 무방합니다.
{% endhint %}

```xml
<!-- res/layout/activity_launcher.xml -->

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    tools:context=".LauncherActivity">

    <WebView
        android:id="@+id/webViewLauncher"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

<mark style="color:blue;">`AndroidManifest.xml`</mark> 파일의 <mark style="color:blue;">`<application></application>`</mark> 태그 내 런처 WebView Activity를 추가합니다.

* 게임은 세로모드 해상도에 최적화 되어 <mark style="color:blue;">`screenOrientation`</mark> 값을 <mark style="color:blue;">`portrait`</mark> 으로 고정해주세요.

```xml
<!-- AndroidManifest.xml -->
<application ...>
    <!-- 추가 -->
    <activity
        android:name=".LauncherActivity"
        android:screenOrientation="portrait"
        android:theme="@style/Theme.{projectName}.NoActionBar"
        tools:ignore="LockedOrientationActivity" /> 
</application>
```

***

## 2단계: Activity 내 WebView 설정 추가

### 1. Javascript Interface 선언

런처 ↔ 클라이언트 앱 간의 통신을 위해 우리는 <mark style="color:blue;">`Javascript Interface`</mark> 선언이 필요합니다.&#x20;

이와 관련된 내용은 [<mark style="color:orange;">\[안드로이드 개발자 사이트\]</mark>](https://developer.android.com/guide/webapps/webview?hl=ko#EnablingJavaScript)를 참고 할 수 있습니다.

#### Javascript Interface 추가 코드

* <mark style="color:blue;">`addJavascriptInterface`</mark> 선언 시 name 값을 <mark style="color:blue;">`BlpLauncher`</mark> 로 설정해야 합니다.

```xml
binding.webViewLauncher.apply {
    // JavascriptInterface 추가
    addJavascriptInterface(
        ExampleWebAppInterface(this@LauncherActivity),
        "BlpLauncher"
    )
}
```

<mark style="color:blue;">`ExampleWebAppInterface`</mark> 클래스 내부에 아래 케이스 function들을 선언합니다.

<table><thead><tr><th width="274">Interface function</th><th>Description</th></tr></thead><tbody><tr><td><mark style="color:orange;"><code>closeLauncher()</code></mark></td><td>런처의 Back 버튼 UI 클릭 시 (뒤로가기 처리)</td></tr><tr><td><mark style="color:orange;"><code>launcherLoaded()</code></mark></td><td>런처의 로드가 완료된 후 추가적인 처리 필요 시 사용</td></tr><tr><td><mark style="color:orange;"><code>timerMissionComplete()</code></mark></td><td>타이머 미션 완료 후 추가적인 처리 필요 시 사용</td></tr><tr><td><mark style="color:orange;"><code>giftReceived()</code></mark></td><td>육성완료 후 추가적인 처리 필요 시 사용</td></tr></tbody></table>

```kotlin
// 블리피 Launcher Web <-> App 인터페이스 규격
class ExampleWebAppInterface(private val mContext: Context) {
    @JavascriptInterface
    fun closeLauncher() {
        // 런처 뒤로가기 > 런처 종료
        (mContext as Activity).finish()
    }
    
    @JavascriptInterface
    fun launcherLoaded() {
        // 런처의 로드가 완료된 후 추가적인 처리 필요 시 사용
    }
    
    @JavascriptInterface
    fun timerMissionComplete() {
        // 타이머 미션 완료 후 추가적인 처리 필요 시 사용
    }
    
    @JavascriptInterface
    fun giftReceived() {
        // 육성완료 후 추가적인 처리 필요 시 사용
    }
}
```

### 2. WebView 기본 설정 추가

런처가 WebView 내에서 정상적인 동작을 하려면 몇가지 기본 설정이 필요합니다.

* WebView에 로드한 런처 자바스크립트 코드가 정상적으로 허용되도록 <mark style="color:blue;">`javaScriptEnabled`</mark> 값을 <mark style="color:blue;">`true`</mark> 로 설정해주세요.
* 런처에서는 <mark style="color:blue;">`Storage`</mark> 영역을 사용하기에 <mark style="color:blue;">`domStorageEnabled`</mark> 값을 <mark style="color:blue;">`true`</mark> 로 설정해주세요.

```kotlin
binding.webViewLauncher.settings.apply {
    javaScriptEnabled = true    // 자바 스크립트 허용
    domStorageEnabled = true    // storage enabled (스토리지 사용하여 dom 가져올 수 있도록 함)
}
```

### 3. WebView URL 로드

Activity가 실행되었을 때 <mark style="color:blue;">`onCreate()`</mark> 안에서 <mark style="color:blue;">`런처 호출 URL`</mark> 을 WebView에 로드합니다.

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // ...

    binding.webViewLauncher.apply {
        // WebView에 런처 호출 URL을 로드
        loadUrl("런처 호출 URL")
    }

    // ...
}
```

***

## 3단계: onDestroy() 설정

Activity가 종료될 때 <mark style="color:blue;">`onDestroy()`</mark> 라이프 사이클이 수행됩니다. \
이 때 WebView 인스턴스를 초기화 하고 Destroy 하여 메모리 누수를 방지합니다.&#x20;

런처 WebView가 포함된 Activity 뿐만 아니라 이 후 추가적으로 WebView Activity를 생성할 경우 다음과 같이 <mark style="color:blue;">`onDestroy()`</mark> 처리를 넣어주는 편이 좋습니다.

```kotlin
// WebView 초기화 및 destroy - 메모리 누수 방지
override fun onDestroy() {
    super.onDestroy()
		
    binding.webViewLauncher.apply {
        clearCache(true)
        clearHistory()
        loadUrl("about:blank")
        removeAllViews()
        destroy()
    }
}
```

{% hint style="info" %}
개발에 대한 추가 설명이 더 필요하신가요?

"[<mark style="color:orange;">\[Client Admin\]</mark>](https://client-admin.bleepy.io/login) 로그인 → 오른쪽 하단 채널톡 위젯" 클릭 후 개발 카테고리에 문의 남겨주시면 기술 개발팀에서 확인 후 연락드리겠습니다.
{% endhint %}

***

## 4단계: 화면 전환 설정

### 1. AndroidManifest 설정

Activity별 <mark style="color:blue;">`<intent-filter></intent-filter>`</mark> 내부 data-element에 <mark style="color:blue;">`scheme`</mark> 와 <mark style="color:blue;">`host`</mark> 설정을 추가해주세요.

```xml
<!-- AndroidManifest.xml -->
...
<activity
    android:name=".{ActivityName}"
    android:screenOrientation="portrait"
    android:theme="@style/Theme.Example.NoActionBar"
    android:exported="true"
    tools:ignore="LockedOrientationActivity">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="{host}"
            android:scheme="{scheme}" />
    </intent-filter>
</activity>
...
```

자세한 설명은 [<mark style="color:orange;">\[Manifest data-element\]</mark>](https://developer.android.com/guide/topics/manifest/data-element?hl=ko) 를 참고합니다.

### 2. queryString을 통한 데이터 얻기

<mark style="color:blue;">`scheme`</mark> , <mark style="color:blue;">`host`</mark> 값 외 queryString을 사용하여 Activity에서 원하는 데이터를 사용할 수 있습니다.

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    binding = ActivityWebviewBinding.inflate(layoutInflater)
    setContentView(binding.root)

    // URI query string 데이터 값 추출
    val intent = intent
    if (Intent.ACTION_VIEW == intent.action) {
        val uri: Uri? = intent.data

        // 딥링크 내 queryString형태로 정의한 parameter key로 value를 얻습니다.
        val paramValue: String? = uri?.getQueryParameter("parameter key")
    }

    ...
}
```

{% hint style="info" %}
개발에 대한 추가 설명이 더 필요하신가요?

"[<mark style="color:orange;">\[Client Admin\]</mark>](https://client-admin.bleepy.io/login) 로그인 → 오른쪽 하단 채널톡 위젯" 클릭 후 개발 카테고리에 문의 남겨주시면 기술 개발팀에서 확인 후 연락드리겠습니다.
{% endhint %}
