# iOS SDK

{% hint style="success" %} <mark style="color:$success;">**iOS SDK v1.0.0-rc02 (호환성 정보)**</mark>

**iOS** 15.0+
{% endhint %}

{% hint style="info" %}

## <mark style="color:$tint;">Notice</mark>

현재 CocoaPods을 통한 설치는 지원하지 않습니다. 추후 Swift Package Manager 지원이 제공될 예정입니다
{% endhint %}

## iOS SDK 설치하기

핑거푸시 링크 iOS SDK는 아래 방법으로 설치할 수 있습니다.

{% tabs %}
{% tab title="직접 설치" %}
1\. 핑거푸시 링크 iOS SDK를 다운로드합니다.

{% file src="<https://3038700150-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeoSKISgBZXnZ708j5r5d%2Fuploads%2FvsiunIKV1CIJ8zzdr9Nf%2Ffplink.xcframework.zip?alt=media&token=321edf86-95a6-41eb-be2d-3e91e6489e80>" %}

2\. fplink.xcframework를 프로젝트에 추가합니다. \
\[Xcode] > \[프로젝트 파일] > \[General] > \[Frameworks, Libraries, and Embedded Content]에서 ‘+’를 클릭합니다.

3\. \[Add Other...]에서 ‘Add Files...’를 클릭하고 fplink.xcframework를 선택합니다.

4\. fplink.xcframework의 Embed를 **Do Not Embed**로 설정합니다.

5\. \[Targets 프로젝트] > \[Build Settings] > **'User Script Sandboxing'** 값을 **No**로 변경합니다.

6\. RunScript 를 추가합니다.\
\[Targets 프로젝트] > \[Build Phases] > '+' 클릭 > **'New RunScript Phase'** 클릭 후 아래의 스크립트를 추가합니다.

{% code title="fplink script" overflow="wrap" expandable="true" %}

```sh
set -euo pipefail

: "${CODE_SIGN_ENTITLEMENTS:=}"
[ -n "$CODE_SIGN_ENTITLEMENTS" ] || exit 0

ENTITLEMENTS_PATH="${SRCROOT}/${CODE_SIGN_ENTITLEMENTS}"
[ -f "$ENTITLEMENTS_PATH" ] || exit 0

RESOURCES_DIR="${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
OUTPUT_PLIST="$RESOURCES_DIR/AssociatedDomains.plist"

[ -f "$ENTITLEMENTS_PATH" ] || exit 0

mkdir -p "$RESOURCES_DIR"
rm -f "$OUTPUT_PLIST"

/usr/libexec/PlistBuddy -c "Add :applinks array" "$OUTPUT_PLIST"

i=0
added=0
while true; do
  raw=$(/usr/libexec/PlistBuddy -c "Print :com.apple.developer.associated-domains:${i}" "$ENTITLEMENTS_PATH" 2>/dev/null) || break

  if [[ "$raw" == applinks:* ]]; then
    domain="${raw#applinks:}"
    /usr/libexec/PlistBuddy -c "Add :applinks:$added string $domain" "$OUTPUT_PLIST"
    added=$((added+1))
  fi

  i=$((i+1))
done
```

{% endcode %}
{% endtab %}
{% endtabs %}

### SDK 초기화하기

시스템 방식에 따라 SDK 초기화 방법이 다릅니다. SceneDelegate Lifecycle 또는 AppDelegate Lifecycle은 AppDelegate를 참고해 주세요. SwiftUI Lifecycle는 SwiftUI를 참고해 주세요.

YOUR\_APP\_ID와 YOUR\_MOBILE\_APP\_API\_KEY은 핑거푸시 링크 대시보드의 \[모바일 앱] > \[앱 관리] > \[API 키] 에서 확인할 수 있습니다.

{% tabs %}
{% tab title="AppDelegate (Swift)" %}

```swift
import UIKit
import fplink

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        Fplink.initialize(appID:"YOUR_APP_ID", apiKey:"YOUR_MOBILE_APP_API_KEY")
        return true
    }
}
```

{% endtab %}

{% tab title="AppDelegate (Objective-C)" %}

```objective-c
#import "AppDelegate.h"
#import <fplink/fplink-Swift.h>

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [Fplink initializeWithAppID:@"YOUR_APP_ID" apiKey:@"YOUR_MOBILE_APP_API_KEY"];
    return YES;
}

@end
```

{% endtab %}

{% tab title="SwiftUI" %}

```swift
import SwiftUI
import fplink

@main
struct ExampleApp: App {
    init() {
        Fplink.initialize(appID: "YOUR_APP_ID", apiKey: "YOUR_MOBILE_APP_API_KEY")
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %} <mark style="color:$danger;">**주의하세요**</mark>

<mark style="color:$danger;">`Fplink.initialize`</mark> 함수를 <mark style="color:$danger;">`AppDelegate`</mark> 의 <mark style="color:$danger;">`application(_:didFinishLaunchingWithOptions:)`</mark> 시점에 호출해야 올바르게 동작합니다.
{% endhint %}

## **딥링크**

<sup>이 문서에서 FINGERPUSH.LINK 딥링크는 이하 '</sup><sup>**FP 딥링크**</sup><sup>'로 표기합니다.</sup>

링크 생성 시 모바일 딥링크를 설정하면, 사용자가 해당 링크를 클릭했을 때 앱이 실행되며 지정한 화면으로 이동하도록 할 수 있습니다.

### **딥링크 설정하기**

FP 딥링크를 사용하기 위해 먼저  핑거푸시 링크 대시보드에서 앱을 추가하고, 딥링크 설정을 진행합니다.

<details>

<summary>1. 앱 추가하기</summary>

[핑거푸시 링크 대시보드](https://console.fingerpush.link/console)에서 아래 경로로 이동하여 앱을 추가합니다.

\[모바일 앱] > \[앱 관리] > \[새 앱 추가] > iOS 플랫폼 선택

**필수 정보 입력**

Team ID : [애플 개발자 대시보드](https://developer.apple.com/account/resources)의 멤버십 세부 사항에서 <mark style="color:blue;">`팀 ID`</mark> 값을 가져와서 입력하거나, [애플 개발자 프로그램 리소스](https://developer.apple.com/account/resources)의 앱의 \[Identifier]에서 <mark style="color:blue;">`App ID Prefix(팀 ID)`</mark>  값을 가져와서 입력해주세요.

Bundle ID : [애플 개발자 프로그램 리소스](https://developer.apple.com/account/resources)의 앱의 \[Identifier]에서 <mark style="color:blue;">`Bundle ID`</mark> 값을 가져와서 입력해주세요.

앱 스킴(App Scheme) : 앱에서 사용하는 URL 스킴을 입력합니다.

앱 스토어 URL : 앱이 설치되지 않은 경우 이동할 App Store 주소를 입력합니다.

</details>

FP 딥링크로 앱이 실행될 수 있도록, 앱에서 딥링크 설정을 진행합니다.

<details>

<summary>2  딥링크 설정하기</summary>

#### **스킴 딥링크 앱 설정**

1\. Xcode에서 \[YOUR\_PROJECT] > \[Info] > \[URL Types]로 이동합니다.

2\. '+'를 클릭한 후에 URL Schemes에 핑거푸시 링크 대시보드에서 입력한 iOS URL 스킴을 입력합니다.

{% hint style="danger" %} <mark style="color:$danger;">**주의하세요**</mark>

<mark style="color:$danger;">`://`</mark>를 제외한 iOS URL 스킴을 입력해야 합니다.
{% endhint %}

#### **유니버셜 링크 앱 설정**

1\. Xcode에서 \[YOUR\_PROJECT]>\[Signing & Capabilities]로 이동합니다.

2\. '+ Capability'를 클릭하면 Associated Domains를 추가할 수 있습니다.

3\. Associated Domains에 핑거푸시 링크 대시보드의 \[도메인 & 인프라] > \[커스텀 도메인] 에서 사용하고자 하는 모든 도메인을 applinks:\[도메인 이름] 형태로 추가합니다.

</details>

***

### **딥링크 처리하기**

딥링크로 앱이 실행될 때,  <mark style="color:blue;">`handleDeeplink`</mark> 를 호출해 딥링크를 SDK로 전달하고 FP 딥링크 여부를 확인해주세요. <mark style="color:blue;">`handleDeeplink`</mark> 를 통해 SDK는 딥링크 오픈 이벤트를 수집하며, FP 딥링크인 경우 해당 딥링크를 처리합니다. &#x20;

FP 딥링크인 경우, SDK는 설정된 링크 정보를 조회하여 url과 schemeUrl을 가져옵니다. \
가져온 값은 <mark style="color:blue;">`setDeeplinkCallback`</mark> 으로 설정한 콜백으로 전달됩니다.\
콜백으로 전달된 url 또는 schemeUrl을 이용해 유저를 원하는 화면으로 이동시켜주세요.

#### 딥링크 처리 흐름

<mark style="color:blue;">`handleDeeplink`</mark> 의 반환값 isFingerpushDeeplink 값이 true이면 FP 딥링크이며, 처리 성공/실패 여부는 onSuccess/onFailure 콜백으로 전달됩니다.\
반환값이 false이면 FP 딥링크가 아니며, 이 경우 <mark style="color:blue;">`setDeeplinkCallback`</mark> 및 성공/실패 콜백은 호출되지 않습니다.

이를 활용하면 FP 딥링크와 그 외 딥링크를 분리하여 처리할 수 있습니다 &#x20;

#### 콜백 설정

<mark style="color:blue;">`setDeeplinkCallback`</mark> 은 앱 시작 시점에 설정해야 합니다.

* SceneDelegate와 AppDelegate가 모두 있는 경우: AppDelegate에서 설정 &#x20;
* AppDelegate만 있는 경우: AppDelegate에서 설정 &#x20;
* SwiftUI를 사용하는 경우: App 클래스에서 설정&#x20;

{% tabs %}
{% tab title="AppDelegate (Swift)" %}

```swift
import UIKit
import fplink

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // SDK 초기화 이후 작성
        Fplink.instance().setDeeplinkCallback { url, schemeUrl in
            if let url {
                //  url을 활용해 유저를 설정한 목적지로 이동하는 로직 작성
            }
        }
        return true
    }
    ...
}
```

{% endtab %}

{% tab title="AppDelegate (Objective-C)" %}

```objective-c
#import "AppDelegate.h"
#import <fplink/fplink-Swift.h>

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // SDK 초기화 이후 작성
    [[Fplink instance] setDeeplinkCallback:^(NSURL * _Nullable url, NSURL * _Nullable schemeUrl) {
        //  url을 활용해 유저를 설정한 목적지로 이동하는 로직 작성
    }];
    return YES;
}
...
@end
```

{% endtab %}

{% tab title="SwiftUI" %}

```swift
import SwiftUI
import fplink

@main
struct ExampleApp: App {
    init() {
        // SDK 초기화 이후 작성
        Fplink.instance().setDeeplinkCallback { url, schemeUrl in
            if let url {
                //  url을 활용해 유저를 설정한 목적지로 이동하는 로직 작성
            }
        }
    }
    ...
}
```

{% endtab %}
{% endtabs %}

#### handleDeeplink 호출

<mark style="color:blue;">`handleDeeplink`</mark> 는 딥링크로 앱이 실행될 때 호출해야 합니다.

* SceneDelegate와 AppDelegate가 모두 있는 경우: SceneDelegate에서 호출 &#x20;
* AppDelegate만 있는 경우: AppDelegate에서 호출 &#x20;
* SwiftUI를 사용하는 경우: App 클래스(onOpenURL)에서 호출

{% tabs fullWidth="false" %}
{% tab title="AppDelegate (swift)" %}
**URL Scheme**으로 오픈되는 경우   <mark style="color:blue;">`application:open:options:`</mark> &#x20;

**유니버셜 링크**로 오픈되는 경우   <mark style="color:blue;">`application:continue:restorationHandler:`</mark> &#x20;

해당 콜백에서 <mark style="color:blue;">`handleDeeplink`</mark> 함수를 호출하여 딥링크 오픈 이벤트를 수집하고 <mark style="color:blue;">`setDeeplinkCallback`</mark> 함수를 통해서 유저를 이동시키세요.

{% code expandable="true" %}

```swift
import UIKit
import fplink

class AppDelegate: UIResponder, UIApplicationDelegate {
    ...
    func application(
        _ app: UIApplication,
        open url: URL,
        options: [UIApplication.OpenURLOptionsKey : Any] = [:]
    ) -> Bool {
        // 핑거푸시 딥링크를 사용여부 확인
        var isFingerpushDeeplink = Fplink.instance().handleDeeplink(open: url)
        if isFingerpushDeeplink { return true }
        
        // 다른 딥링크로 앱 실행 시 기존 로직 사용
        
        return true
    }
    
    func application(
        _ application: UIApplication,
        continue userActivity: NSUserActivity,
        restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
    ) -> Bool {
        // 핑거푸시 딥링크를 사용여부 확인
        var isFingerpushDeeplink = Fplink.instance().handleDeeplink(continue: userActivity)
        if isFingerpushDeeplink { return true }
        
        // 다른 딥링크로 앱 실행 시 기존 로직 사용
        
        return true
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="SceneDelegate (swift)" %}
앱이 꺼지거나 백그라운드에 있는 상태에서 \
**URL Scheme** 또는 **유니버셜 링크**로 오픈되는 경우   <mark style="color:blue;">`scene:willConnectTo:options:`</mark> &#x20;

앱이 백그라운드에 있는 상태에서\
**URL 스킴**으로 오픈되는 경우   <mark style="color:blue;">`scene:openURLContexts:`</mark>  \
**유니버셜링크**로 오픈되는 경우   <mark style="color:blue;">`scene:continue:`</mark> &#x20;

해당 콜백에서 <mark style="color:blue;">`handleDeeplink`</mark> 함수를 호출하여 딥링크 오픈 이벤트를 수집하고 <mark style="color:blue;">`setDeeplinkCallback`</mark> 함수를 통해서 유저를 이동시키세요.

{% code expandable="true" %}

```swift
import UIKit
import fplink

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        ...
        
        // 핑거푸시 딥링크를 사용여부 확인
        var isFingerpushDeeplink = Fplink.instance().handleDeeplink(options: connectionOptions) 
        if isFingerpushDeeplink { return }
        
        // 다른 딥링크로 앱 실행 시 기존 로직 사용
    }
    
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        // 핑거푸시 딥링크를 사용여부 확인
        var isFingerpushDeeplink = Fplink.instance().handleDeeplink(openURLContexts: URLContexts)
        if isFingerpushDeeplink { return }
        
        // 다른 딥링크로 앱 실행 시 기존 로직 사용
    }
    
    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        // 핑거푸시 딥링크를 사용여부 확인
        var isFingerpushDeeplink = Fplink.instance().handleDeeplink(continue: userActivity)
        if isFingerpushDeeplink { return }
        
        // 다른 딥링크로 앱 실행 시 기존 로직 사용
    }
    ...
}
```

{% endcode %}
{% endtab %}

{% tab title="AppDelegate (Objective-C)" %}
**URL Scheme**으로 오픈되는 경우   <mark style="color:blue;">`application:openURL:options:`</mark> &#x20;

**유니버셜 링크**로 오픈되는 경우   <mark style="color:blue;">`application:continueUserActivity:restorationHandler:`</mark> &#x20;

해당 콜백에서  <mark style="color:blue;">`handleDeeplink`</mark> 함수를 호출하여 딥링크 오픈 이벤트를 수집하고 <mark style="color:blue;">`setDeeplinkCallback`</mark> 함수를 통해서 유저를 이동시키세요.

{% code expandable="true" %}

```swift
#import "AppDelegate.h"
#import <fplink/fplink-Swift.h>

@interface AppDelegate ()

@end

@implementation AppDelegate
...
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
   // 핑거푸시 딥링크를 사용여부 확인
    BOOL isFingerpushDeeplink = [[Fplink instance] handleDeeplinkWithOpen:url onSuccess:nil onFailure:nil];
    if (isFingerpushDeeplink) { return YES; }
    
    // 다른 딥링크로 앱 실행 시 기존 로직 사용
    
    return isFingerpushDeeplink;
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
   // 핑거푸시 딥링크를 사용여부 확인
    BOOL isFingerpushDeeplink = [[Fplink instance] handleDeeplinkWithContinue:userActivity onSuccess:nil onFailure:nil];
    if (isFingerpushDeeplink) { return YES; }
    
    // 다른 딥링크로 앱 실행 시 기존 로직 사용
    
    return isFingerpushDeeplink;
}
@end
```

{% endcode %}
{% endtab %}

{% tab title="SceneDelegate (Objective-C)" %}
앱이 꺼지거나 백그라운드에 있는 상태에서 \
**URL Scheme** 또는 **유니버셜 링크**로 오픈되는 경우   <mark style="color:blue;">`scene:willConnectToSession:options:`</mark> &#x20;

앱이 백그라운드에 있는 상태에서\
**URL 스킴**으로 오픈되는 경우   <mark style="color:blue;">`scene:openURLContexts:`</mark>  \
**유니버셜링크**로 오픈되는 경우   <mark style="color:blue;">`scene:continueUserActivity:`</mark> &#x20;

해당 콜백에서 <mark style="color:blue;">`handleDeeplink`</mark> 함수를 호출하여 딥링크 오픈 이벤트를 수집하고 <mark style="color:blue;">`setDeeplinkCallback`</mark> 함수를 통해서 유저를 이동시키세요.

{% code expandable="true" %}

```swift
#import "SceneDelegate.h"
#import <fplink/fplink-Swift.h>

@interface SceneDelegate ()

@end

@implementation SceneDelegate
...
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    // 핑거푸시 딥링크를 사용여부 확인
    BOOL isFingerpushDeeplink = [[Fplink instance] handleDeeplinkWithOptions:connectionOptions onSuccess:nil onFailure:nil];
    if (isFingerpushDeeplink) { return; }
    
    // 다른 딥링크로 앱 실행 시 기존 로직 사용
}

- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
    // 핑거푸시 딥링크를 사용여부 확인
    BOOL isFingerpushDeeplink = [[Fplink instance] handleDeeplinkWithOpenURLContexts:URLContexts onSuccess:nil onFailure:nil];
    if (isFingerpushDeeplink) { return; }
    
    // 다른 딥링크로 앱 실행 시 기존 로직 사용
}

- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {
    // 핑거푸시 딥링크를 사용여부 확인
    BOOL isFingerpushDeeplink = [[Fplink instance] handleDeeplinkWithContinue:userActivity onSuccess:nil onFailure:nil];
    if (isFingerpushDeeplink) { return; }
    
    // 다른 딥링크로 앱 실행 시 기존 로직 사용
}
...
@end
```

{% endcode %}
{% endtab %}

{% tab title="SwiftUI" %}
앱이 꺼지거나 백그라운드에 있는 상태에서\
**URL Scheme** 또는 **유니버셜 링크** 로 오픈되는 경우   <mark style="color:blue;">`onOpenURL`</mark>&#x20;

해당 콜백에서 <mark style="color:blue;">`handleDeeplink`</mark> 함수를 호출하여 딥링크 오픈 이벤트를 수집하고 <mark style="color:blue;">`setDeeplinkCallback`</mark> 함수를 통해서 유저를 이동시킬 수 있습니다.

```swift
import SwiftUI
import fplink

@main
struct ExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { url in
                    let isFingerpushDeeplink = Fplink.instance().handleDeeplink(url: url)
                    if isFingerpushDeeplink { return }
                }
        }
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %} <mark style="color:$tint;">**Notice**</mark>

<mark style="color:blue;">`handleDeeplink`</mark> 는 FP 딥링크인 경우 true를 반환하고, 변환된 링크 정보를 <mark style="color:blue;">`setDeeplinkCallback`</mark> 함수로 전달합니다.&#x20;

FP 딥링크가 아닌 경우 false를 반환하며, SDK 처리는 수행되지 않습니다.

<mark style="color:blue;">`setDeeplinkCallback`</mark>  고객 화면 이동을 자동으로 수행하지 않습니다.

콜백으로 전달된 링크 정보를 기반으로 앱에서 직접 화면 이동을 구현해야 합니다.
{% endhint %}

***

### 디퍼드 딥링크 설정하기

앱이 설치되지 않은 상태에서 디퍼드 딥링크가 설정된 FP 딥링크를 클릭하면, 해당 딥링크 정보가 서버에 저장됩니다.  이후 앱이 설치되고 처음 실행될 때, SDK를 통해 저장된 딥링크 정보를 전달받을 수 있습니다.

<mark style="color:blue;">`handleDeferredDeeplink`</mark> 를 호출하면, 저장된 딥링크 정보를 확인하고 콜백으로 전달합니다. 콜백으로 전달된 링크 정보를 이용해 유저를 원하는 화면으로 이동시켜주세요.

{% tabs %}
{% tab title="AppDelegate (Swift)" %}

```swift
import UIKit
import fplink

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        ...
        // SDK 초기화 이후 작성
        let isFirstCalled = Fplink.instance().handleDeferredDeeplink { url, schemeUrl in
            // 앱 설치 후 handleDeferredDeeplink가 호출 될 때
            if let url {
                //  url을 활용해 유저를 설정한 목적지로 이동하는 로직 작성
            }
        }
        return true
    }
}
```

{% endtab %}

{% tab title="AppDelegate (Objective-C)" %}

```objective-c
#import "AppDelegate.h"
#import <fplink/fplink-Swift.h>

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // SDK 초기화 이후 작성
    BOOL isFirstCalled = [[Fplink instance] handleDeferredDeeplinkOnSuccess:^(NSURL * _Nullable url, NSURL * _Nullable schemeUrl) {
            // 앱 설치 후 handleDeferredDeeplink가 호출 될 때
            if let url {
                //  url을 활용해 유저를 설정한 목적지로 이동하는 로직 작성
            }
        } onFailure:nil];
        
    return YES;
}

@end
```

{% endtab %}

{% tab title="SwiftUI" %}

```swift
import SwiftUI
import fplink

@main
struct ExampleApp: App {
    init() {
        // SDK 초기화 이후 작성
        let isFirstCalled = Fplink.instance().handleDeferredDeeplink { url, schemeUrl in
            // 앱 설치 후 handleDeferredDeeplink가 호출 될 때
            if let url {
                //  url을 활용해 유저를 설정한 목적지로 이동하는 로직 작성
            }
        }
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
```

{% endtab %}
{% endtabs %}

<mark style="color:blue;">`handleDeferredDeeplink`</mark> 함수는 앱이 설치되고 처음으로 호출되었으면 true를 반환하고, SDK가 초기화되지 않았거나 <mark style="color:blue;">`handleDeferredDeeplink`</mark> 함수를 처음으로 호출하는 것이 아닌 경우 false를 전달합니다.

{% hint style="danger" %} <mark style="color:$danger;">**Warning**</mark>

디퍼드 딥링크로 앱을 설치하고, 실행없이 딥링크로 앱을 열면 FP 딥링크는 디퍼드 딥링크 유무에 관계없이 null을 onSuccess에 전달해서 딥링크만 처리되도록 합니다.
{% endhint %}

## 추가 설정하기

#### 앱 내에서 FP 딥링크 활용하기 &#x20;

웹뷰 또는 푸시 메시지 URL 로드와 같이 링크를 여는 방식에 따라, FP 딥링크가 정상적으로 동작하지 않을 수 있습니다. (중간 페이지 이동, 앱스토어 연결, 클릭 추적 등) &#x20;

이 경우 <mark style="color:blue;">`click`</mark> 함수를 사용하여 앱 내에서 FP 딥링크를 정상적으로 처리할 수 있습니다 .

### click 함수 사용 방법&#x20;

<mark style="color:blue;">`click`</mark> 함수는 전달된 URL이 FP 딥링크인지 확인하고, FP 딥링크인 경우 SDK를 통해 처리합니다.

<mark style="color:blue;">`click`</mark> 함수는 두 가지 방식으로 결과를 제공합니다.

1. <mark style="color:blue;">`onSuccess`</mark> 콜백으로 결과를 받는 방식&#x20;
   * 입력된 URL이 FP 딥링크인 경우 true 반환
   * 처리 완료 시 <mark style="color:blue;">`onSuccess`</mark> 콜백으로 최종 URL 전달
   * 처리 실패 시 <mark style="color:blue;">`onFailure`</mark> 콜백 호출
2. <mark style="color:blue;">`setDeeplinkCallback`</mark> 을 통해 결과를 받는 방식 &#x20;
   * 입력된 URL이 FP 딥링크인 경우 true 반환&#x20;
   * 처리 완료 시 <mark style="color:blue;">`setDeeplinkCallback`</mark> 으로 설정한 콜백을 통해 url과 schemeUrl 전달
   * 처리 실패 시 <mark style="color:blue;">`onFailure`</mark> 콜백 호출

입력된 URL이 FP 딥링크가 아닌 경우 false를 반환하며, SDK에서 처리를 수행하지 않습니다.

{% tabs %}
{% tab title="Swift" %}
{% code title="결과를 onSuccess 콜백으로 직접 받는 방식" overflow="wrap" expandable="true" %}

```swift
import UIKit
import fplink

...
let isHandled = Fplink.instance().click(url: url) { url, schemeUrl in
    // url이 FP 링크일 때, 처리에 성공한 경우 url / schemeUrl 처리
} onFailure: {
    // url이 FP링크 일때, 처리에 실패한 경우
} 
if isHandled {
    // url이 FP 링크일 때
}
...
```

{% endcode %}

{% code title="setDeeplinkCallback을 통해 결과를 받는 방식" overflow="wrap" expandable="true" %}

```swift
import UIKit
import fplink

...
let isHandled = Fplink.instance().click(url: url) {
    // url이 FP링크 일때, 처리에 성공한 경우
} onFailure: {
    // url이 FP링크 일때, 처리에 실패한 경우
}
if isHandled {     
 // url이 FP 링크일 때
}
...
```

{% endcode %}
{% endtab %}

{% tab title="Objective-C" %}
{% code title="결과를 onSuccess 콜백으로 직접 받는 방식" overflow="wrap" expandable="true" %}

```objective-c
#import <fplink/fplink-Swift.h>

...
BOOL isHandled = [[Fplink instance] clickWithUrl:url onSuccessWithResult:^(NSURL * _Nullable url, NSURL * _Nullable schemeUrl) {
    // url이 FP 링크일 때, 처리에 성공한 경우 url / schemeUrl 처리
} onFailure:^{
    // url이 FP 링크일 때, 처리에 실패한 경우
}];

if (isHandled) { 
    // url이 FP 링크일 때
}
```

{% endcode %}

{% code title="setDeeplinkCallback을 통해 결과를 받는 방식" overflow="wrap" expandable="true" %}

```objective-c
#import <fplink/fplink-Swift.h>

...
BOOL isHandled = [[Fplink instance] clickWithUrl:url onSuccess:^{
    // url이 FP 링크일 때, 처리에 성공한 경우
} onFailure:^{
    // url이 FP 링크일 때, 처리에 실패한 경우
}];
if (isHandled) {  
    // url이 FP 링크일 때
}  
...
```

{% endcode %}
{% endtab %}
{% endtabs %}

***

### 웹뷰에서 딥링크 처리하기

웹뷰는 기본적으로 딥링크 실행을 지원하지 않기 때문에, 웹뷰 내에서 FP 딥링크를 클릭하는 경우 의도와 다르게 동작할 수 있습니다.

이 경우 <mark style="color:blue;">`click`</mark>  함수를 호출하여 SDK가 딥링크 처리를 대신 수행하도록 설정해야 합니다.

{% tabs %}
{% tab title="Swift" %} <mark style="color:blue;">`WKWebView`</mark>에서 <mark style="color:blue;">`webView(_:decidePolicyFor:decisionHandler:)`</mark> 를 구현하면, 특정 URL이 로드되는 시점에 해당 URL을 확인하고 로딩 여부를 제어할 수 있습니다.

이 메서드에서 <mark style="color:blue;">`click`</mark> 함수를 호출해 FP 딥링크 여부를 확인하고, FP 딥링크인 경우 웹뷰 로딩을 중단하고 앱 내 이동을 처리합니다.

{% code title="결과를 onSuccess 콜백으로 직접 받는 방식" overflow="wrap" expandable="true" %}

```swift
import UIKit
import fplink

...
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping @MainActor (WKNavigationActionPolicy) -> Void) {
    let request: URLRequest = navigationAction.request
    if let url = navigationAction.request.url {
        let isHandled = Fplink.instance().click(url: url) { url, schemeUrl in
            // url이 FP링크 일때, 처리에 성공한 경우 url 처리
        } onFailure: {
            // url이 FP링크 일때, 처리에 실패한 경우
        } 
        if isHandled {
            decisionHandler(.cancel)
            return
        }
    }
    // url이 FP링크가 아닌 경우 처리
    decisionHandler(.allow)
}
...
```

{% endcode %}

{% code title="setDeeplinkCallback을 통해 결과를 받는 방식" overflow="wrap" expandable="true" %}

```swift
import UIKit
import fplink

...
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping @MainActor (WKNavigationActionPolicy) -> Void) {
    let request: URLRequest = navigationAction.request
    if let url = navigationAction.request.url {
        let isHandled = Fplink.instance().click(url: url) {
            // url이 FP링크 일때, 처리에 성공한 경우
        } onFailure: {
            // url이 FP링크 일때, 처리에 실패한 경우
        }
        if isHandled {
            decisionHandler(.cancel)
            return
        }
    }
    // url이 FP링크가 아닌 경우 처리
    decisionHandler(.allow)
}
...
```

{% endcode %}
{% endtab %}

{% tab title="Objective-C" %} <mark style="color:blue;">`WWKWebView`</mark>에서 <mark style="color:blue;">`webView(_:decidePolicyFor:decisionHandler:)`</mark> 를 구현하면, 특정 URL이 로드되는 시점에 해당 URL을 확인하고 로딩 여부를 제어할 수 있습니다.

이 메서드에서 <mark style="color:blue;">`click`</mark> 함수를 호출해 FP 딥링크 여부를 확인하고, FP 딥링크인 경우 웹뷰 로딩을 중단하고 앱 내 이동을 처리합니다.

{% code title="결과를 onSuccess 콜백으로 직접 받는 방식" overflow="wrap" expandable="true" %}

```objective-c
@import WebKit;
#import <fplink/fplink-Swift.h>

...
- (void)webView:(WKWebView *)webView 
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

    NSURL *url = navigationAction.request.URL;
    if (url) {
        BOOL isHandled = [[Fplink instance] clickWithUrl:url onSuccessWithResult:^(NSURL * _Nullable url, NSURL * _Nullable schemeUrl) {
            // url이 FP 링크일 때, 처리에 성공한 경우 url / schemeUrl 처리
        } onFailure:^{
            // url이 FP 링크일 때, 처리에 실패한 경우
        }];
        
        if (isHandled) {
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    }
    // url이 FP 링크가 아닌 경우 처리
    decisionHandler(WKNavigationActionPolicyAllow);
}
...
```

{% endcode %}

{% code title="setDeeplinkCallback을 통해 결과를 받는 방식" overflow="wrap" expandable="true" %}

```objective-c
@import WebKit;
#import <fplink/fplink-Swift.h>

...
- (void)webView:(WKWebView *)webView 
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

    NSURL *url = navigationAction.request.URL;
    if (url) {
        BOOL isHandled = [[Fplink instance] clickWithUrl:url onSuccess:^{
            // url이 FP 링크일 때, 처리에 성공한 경우
        } onFailure:^{
            // url이 FP 링크일 때, 처리에 실패한 경우
        }];
        if (isHandled) {
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    }
    // url이 FP 링크가 아닌 경우 처리
    decisionHandler(WKNavigationActionPolicyAllow);
}
...
```

{% endcode %}
{% endtab %}
{% endtabs %}
