# 연동하기

본 가이드에서는 Android, iOS에서 하이브리드 앱을 연동했을 시의 가상의 시나리오를 다룹니다. HTML 뷰와 Native 뷰 간의 차이를 해소하여 HTML 뷰에서 이벤트를 기록하고 앱으로 보낼 수 있는 방법에 대해 설명합니다.

해당 방법을 적용하기 위해선 SDK 설치 및 연동 작업이 선행되어야 합니다.

* [Android 시작하기](https://docs.dfinery.ai/developer-guide/platform/android/integration)
* [iOS 시작하기](https://docs.dfinery.ai/developer-guide/platform/ios/integration)

더 자세히 알아보려면 [리소스 및 샘플](/developer-guide/common/resource-and-sample.md)을 참조하세요.

## 자바스크립트 인터페이스

Android와 iOS 모두 web view에서 native code를 호출할 수 있는 네이티브 자바스크립트 인터페이스를 갖고 있습니다.

* Android: [JavascriptInterface](https://developer.android.com/guide/webapps/webview)
* iOS: [JavaScriptCore](https://developer.apple.com/documentation/javascriptcore)

구현은 다음 단계들로 구성됩니다.

1. Webview 또는 웹페이지를 위한 HTML 코드
2. Webview를 위한 네이티브 코드 구현

### Android

#### Android 용 HTML 코드

다음 HTML 코드를 Webview 또는 웹 페이지에 추가합니다.

```html
<h1>Logging Event From Web View</h1>
<div id="main">
 <button id="logSignUpEvent" onclick="logSignUPEvent()"> SignUp </button>
</div>
<script type="text/javascript">
 function logLoginEvent(){
 var eventName = "df_sign_up"
 var eventProperty = {'df_sign_channel': 'Facebook'};
 window.customJsBridge.logEvent(eventName, JSON.stringify(eventProperty));
}
</script>
```

#### WebActivity 클래스

다음 코드를 사용하여 웹 액티비티 클래스를 작성합니다.

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

```java
myWebview.getSettings().setJavaScriptEnabled(true);
myWebView.addJavascriptInterface(new MainJsInterface(), "customJsBridge");
myWebView.loadUrl("https://yourwebsite.com");
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
webView.settings.apply {
  this.javaScriptEnabled = true
}
myWebView.addJavascriptInterface(MainJsInterface(), "customJsBridge")
myWebView.loadUrl("https://yourwebsite.com")
```

{% endtab %}
{% endtabs %}

#### Javascript 인터페이스 클래스

JavascriptInterface로 invoke()를 구현할 MainJsInterface class를 생성합니다.

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

```java
public class MainJsInterface {
    @JavascriptInterface
    public void logEvent(String eventName, String eventProperty){
        JSONObject eventPropertyJsonObject = null;
        if(eventProperty != null){
            try {
                eventPropertyJsonObject = new JSONObject(eventProperty);
                } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        Dfinery.getInstance().logEvent(eventName, eventPropertyJsonObject);
    }
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
class MainJsInterface {
    @JavascriptInterface
    fun logEvent(eventName: String?, eventProperty: String?) {
        var eventPropertyJsonObject: JSONObject? = null
        if (eventProperty != null) {
            try {
                eventPropertyJsonObject = JSONObject(eventProperty)
            } catch (e: JSONException) {
                e.printStackTrace()
            }
        }
        Dfinery.getInstance().logEvent(eventName!!, eventPropertyJsonObject)
    }
}
```

{% endtab %}
{% endtabs %}

### iOS

#### iOS 용 HTML 코드

다음 HTML 코드를 Webview 또는 웹 페이지에 추가합니다.

```html
<h1>Logging Event From Web View</h1>
<div id="main">
 <button id="logSignUpEvent" onclick="logSignUPEvent()"> SignUp </button>
</div>
<script type="text/javascript">
 function logLoginEvent(){
 var eventName = "df_sign_up"
 var eventProperty = {'df_sign_channel': 'Facebook'};
 var message = {
    'eventName' : eventName,
    'eventProperty' : eventProperty
 };
 webkit.messageHandlers.customJsBridge.postMessage(message);
}
</script>
```

#### WKWebView 설정

다음과 같이 WKWebView 객체의 messageHandler를 연결후 웹뷰를 로드해 주세요.

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

```swift
import UIKit
import WebKit
import DfinerySDK

class WebView: UIViewController, WKScriptMessageHandler {

    var webView: WKWebView!
    
    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // messageHandler 연결
        webView.configuration.userContentController.add(self, name: "customJsBridge")

        let myURL = URL(string:"https://www.YOUR_WEBSITE.com")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }

    // WKScriptMessageHandler 프로토콜 구현
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "customJsBridge", let messageBody = message.body as? [String: Any] {
            if let eventName = messageBody["eventName"] as? String,
               let eventProperty = messageBody["eventProperty"] as? [String: Any] {
                // Dfinery SDK 이벤트 호출
                Dfinery.shared().logEvent(name: eventName, properties: property)
            }
        }
    }
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objective-c
// WebView.h
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
#import <DfinerySDK/DfinerySDK.h>

@interface WebView : UIViewController <WKScriptMessageHandler>

@property (nonatomic, strong) WKWebView *webView;

@end

@implementation WebView

// WebView.m

#import "WebView.h"

@implementation WebView

- (void)loadView {
    WKWebViewConfiguration *webConfiguration = [[WKWebViewConfiguration alloc] init];
    self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:webConfiguration];
    self.view = self.webView;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // messageHandler 연결
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"customJsBridge"];
    
    NSURL *myURL = [NSURL URLWithString:@"https://www.YOUR_WEBSITE.com"];
    if (myURL) {
        NSURLRequest *myRequest = [NSURLRequest requestWithURL:myURL];
        [self.webView loadRequest:myRequest];
    }
}

// WKScriptMessageHandler 프로토콜 구현
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.name isEqualToString:@"customJsBridge"]) {
        if ([message.body isKindOfClass:[NSDictionary class]]) {
            NSDictionary *messageBody = (NSDictionary *)message.body;
            
            NSString *eventName = messageBody[@"eventName"];
            NSDictionary *eventProperty = messageBody[@"eventProperty"];
            
            if (eventName && [eventProperty isKindOfClass:[NSDictionary class]]) {
                // Dfinery SDK 이벤트 호출
                [[Dfinery shared] logEvent:eventName withProperties:eventProperty];
            }
        }
    }
}

@end

```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Swift로 작성된 하이브리드 앱에서 logEvent 호출 시\
logEvent(\_ name: String, properties: \[String: Any]) 메서드가 아닌\
logEvent(name: String, properties: \[String: Any]) 메서드를 호출해 주세요
{% endhint %}

## 더 알아보기

### 날짜 및 시간 형식 속성 입력하기

날짜 및 시간 형식은 `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'` 포맷의 문자열 형태로 입력해야합니다.

{% hint style="info" %}
javascript에서 Date 객체를 활용하는 방법은 이 [문서](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Date)를 참고해주시기 바랍니다.
{% endhint %}

{% tabs %}
{% tab title="For Android" %}

```javascript
let today = new Date().toISOString();
let eventName = "df_sign_up"
let eventProperty = {
    'custom_property': today
};
window.customJsBridge.logEvent(eventName, JSON.stringify(eventProperty));
```

{% endtab %}

{% tab title="For iOS" %}

```javascript
let today = new Date().toISOString();
var eventName = "df_sign_up"
let eventProperty = {
    'custom_property': today
};
var message = {
    'eventName' : eventName,
    'eventProperty' : eventProperty
 };
webkit.messageHandlers.customJsBridge.postMessage(message);
```

{% endtab %}
{% endtabs %}

### 유저 식별 정보 설정

Dfinery Android SDK는 유저 식별 정보를 Enum으로 입력 받고 있습니다. HTML에서 유저 식별 정보를 입력하기 위해서는 [유저 식별 정보 상수](/developer-guide/common/constants.md#undefined-9)의 값을 입력하여 자바스크립트 인터페이스 상에서 문자열을 Enum으로 치환한 뒤 호출하는 것을 권장합니다.

#### Javascript

```javascript
window.customJsBridge.setIdentity('external_id', 'sampleUser');
```

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

```java
public class MainJsInterface {
    @JavascriptInterface
    public void setIdentity(String key, String value){
        DFIdentity identity = DFIdentity.get(key);
        DfineryProperties.setIdentity(identity, value);
    }
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
class MainJsInterface {
    @JavascriptInterface
    fun setIdentity(key: String?, value: String?) {
        val identity: DFIdentity = DFIdentity.get(key)
        DfineryProperties.setIdentity(identity, value)
    }
}
```

{% 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.dfinery.ai/developer-guide/platform/hybridapp/web-view-interface.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.
