# 웹앱 연동

{% hint style="info" %}
Flutter SDK 2.13.0 이상, JavaScript SDK 11.25.1 이상 버전에서 지원하는 기능입니다.
{% endhint %}

{% hint style="info" %}
웹앱에 대해서는 [문서](/development-guide/faq/web-app-intergration.md)를 참고해주세요.
{% endhint %}

`InAppWebView`를 통해 자사 웹사이트를 랜더링하는 경우, 다음 같은 설정을 통해 웹사이트에 포함된 핵클 JavaScript SDK를 웹사이트 코드 변경없이 핵클 Flutter SDK 기능과 동일하게 사용할 수 있습니다.

이 경우 모든 핵클 이벤트는 Futter SDK를 통해 수집됩니다.

{% hint style="danger" %}
`initialUserScripts`의 경우 **안드로이드 환경에서 웹페이지 로드 전에 호출됨에 보장되지 않아** 반드시 `onWebViewCreated`에서 반환된 `controller`에서 페이지를 로드해주세요.
{% endhint %}

{% hint style="danger" %}
웹사이트에서 `beforeunload`, `unload` 시점에 이벤트를 발행하고, 웹뷰를 닫는 행위를 할 시 이벤트가 정상적으로 발생하지 않거나, os popup이 뜨는 등 이상동작이 발생할 수 있습니다.

해당 생명주기에서 이벤트를 발생시키기 위해서는 Flutter InAppWebView의 [**KeepAlive**](https://inappwebview.dev/docs/webview/keep-alive/) 기능을 사용하여 웹뷰 객체가 플러터 위젯 트리에서 삭제되도 네이티브 단에 유지되게 하면 이벤트가 정상적으로 발행됩니다.
{% endhint %}

```dart
import 'dart:collection';

import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:hackle/hackle.dart';

final keepAlive = InAppWebViewKeepAlive();

InAppWebView(
  initialSettings: InAppWebViewSettings(
    javaScriptEnabled: true,
  ),
  keepAlive = keepAlive,
  initialUserScripts: UnmodifiableListView<UserScript>([
    UserScript(
      source: HackleApp.getWebBridgeScript(),
      injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START,
      forMainFrameOnly: true
    )]),
  onWebViewCreated: (controller) {
    controller.loadUrl(urlRequest: URLRequest(url: WebUri('YOUR_WEB_URL')));
  },
  onJsPrompt: (controller, jsPromptRequest) async {
    if(HackleApp.isInvocableCommandInWebView(jsPromptRequest.message)) {
      var result = await HackleApp.handleWebInterfaceCommand(jsPromptRequest.message);
      return JsPromptResponse(action: JsPromptResponseAction.CONFIRM, handledByClient: true, value: result);
    } else {
      return JsPromptResponse(handledByClient: false);
    }
  },
);
```

{% hint style="warning" %}
해당 기능을 사용하기 위해서는 **JavaScript 웹페이지에서 동일한 App SDK 키를 사용**해야 합니다.

핵클 Flutter 웹뷰 설정은 안드로이드 `Javascript Userscript` 등을 이용하여 핵클 JavaScript SDK와 상호작용하게 됩니다.
{% endhint %}

## 웹뷰에서 발생하는 자동 수집 이벤트 연동

{% hint style="info" %}
Flutter SDK 2.26.0 이상, JavaScript SDK 11.51.0 이상 버전에서 지원하는 기능입니다.
{% endhint %}

웹뷰 내 웹사이트에서 발생하는 `$page_view`는 비활성화 상태입니다. 웹뷰 브릿지를 설정할 때 `HackleWebViewConfig`를 설정하여 자동 수집 이벤트를 활성화할 수 있습니다.

```dart
import 'dart:collection';

import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:hackle/hackle.dart';

final webViewConfig = HackleWebViewConfig.builder()
  .automaticScreenTracking(true)
	.automaticEngagementTracking(true)
  .build();

...
UserScript(
  source: HackleApp.getWebBridgeScript(webViewConfig: webViewConfig),
  injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START,
  forMainFrameOnly: true
)]),
...
```

### 설정 옵션

<table data-full-width="false"><thead><tr><th width="213.57421875">설정</th><th width="295.48828125">기능</th><th width="125.8125">기본값</th><th width="108.09765625">지원 버전</th></tr></thead><tbody><tr><td><code>automaticScreenTracking</code></td><td>웹사이트에서 발생하는 <code>$page_view</code> 수집 여부</td><td><code>false</code></td><td>2.26.0+</td></tr><tr><td><code>automaticEngagementTracking</code></td><td>웹사이트에서 발생하는 <code>$engagement</code> 수집 여부</td><td><code>false</code></td><td>2.28.0+</td></tr><tr><td><code>automaticRouteTracking</code></td><td>웹사이트에서 발생하는 페이지 정보 자동 수집 여부</td><td><code>true</code></td><td>2.28.0+</td></tr></tbody></table>


---

# 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/flutter/flutter-webapp-integration.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.
