# Flutter SDK

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

**Flutter** 3.10.0+ | **Dart** 3.0.0+ | **Android** API 23+ | **iOS** 15.0+
{% endhint %}

## 플러터 SDK 설치하기

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

1. 자동 설치

```bash
 flutter pub add fplink_flutter
```

2. 수동 설치&#x20;

{% code title="pubspec.yaml" %}

```yaml
dependencies:
  flutter:
    sdk: flutter

  fplink_flutter: ^1.0.0-alpha01
```

{% endcode %}

아래 명령어를 실행하여 패키지를 설치합니다

```bash
flutter pub get
```

### SDK 초기화하기

iOS SDK와 Android SDK는 초기화 방법이 다릅니다. 아래 가이드를 참고해 주세요.

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

#### iOS

1. CocoaPods 의존성 설치 합니다.

**`ios`** 디렉터리로 이동한 뒤, 아래 명령어를 실행합니다.

```bash
pod install
```

2. Run Script 를 추가 합니다.

\[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 %}

4. ios/YOUR\_PROJECT\_NAME/AppDelegate.swift 파일에 아래와 같이 코드를 추가해 주세요.

{% code title="AppDelegate.swift" %}

```swift
import fplink_flutter

@main
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {

    FplinkFlutterPlugin.initialize(appId: "YOUR_APP_ID", apiKey: "YOUR_API_KEY")

    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}
```

{% endcode %}

#### Android

android/app/src/main/java/.../MainApplication.kt 파일에 아래와 같이 코드를 추가해 주세요.

{% code title="MainApplication.kt" %}

```kt
override fun onCreate() {
    super.onCreate()
    FplinkFlutter.initialize(this, "YOUR_APP_ID", "YOUR_API_KEY")
    ...
}
```

{% endcode %}

## 딥링크

딥링크를 설정하면 트래킹 링크가 있는 광고를 클릭한 유저를 원하는 앱의 특정 페이지로 이동시킬 수 있습니다.

{% hint style="danger" %} <mark style="color:$danger;">**알립니다.**</mark>

Flutter SDK 에서 딥링크를 직접 처리할 수 있어 딥링크 기능의 오작동 방지를 위해 플랫폼별로 다음 조치가 반드시 필요합니다.

* Android\
  AndroidManifest.xml 파일에서 `<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />` 로 설정하세요.
* iOS\
  Info.plist 파일에서 `FlutterDeepLinkingEnabled` 키 값을 `NO` 로 설정하세요.
  {% endhint %}

### 딥링크로 앱이 실행되도록 설정하기

유저가 트래킹 링크를 클릭한 후에 앱이 핑거푸시 딥링크로 실행되도록 설정합니다.

#### iOS

1\. 딥링크의 스킴 딥링크 앱 설정이 필요합니다. Xcode에서 \[YOUR\_PROJECT]>\[Info]>\[URL Types]로 이동합니다.

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

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

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

3\. 딥링크의 유니버셜 링크 앱 설정이 필요합니다. Xcode에서 \[YOUR\_PROJECT]>\[Signing & Capabilities]로 이동합니다.

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

5\. 핑거푸시 링크 대시보드의 \[커스텀 도메인] 에서 생성한 도메인 정보를 Associated Domains에 applinks:\[커스텀 도메인] 형태로 추가합니다.

#### Android

1\. 딥링크의 스킴 딥링크 앱 설정이 필요합니다. AndroidManifest.xml에 딥링크를 처리하는 Activity에 Intent Filter를 추가합니다.

추가하는 Intent Filter는 핑거푸시 링크 대시보드에 입력한 안드로이드 URI Scheme를 사용해야 합니다. ://를 제외한 안드로이드 URI 스킴을 입력합니다.

{% code title="AndroidManifest.xml" %}

```xml
<activity ...>
    ...
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="YOUR_SCHEME" />
    </intent-filter>
    ...
</activity>
```

{% endcode %}

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

반드시 분리된 <mark style="color:$danger;">\<intent-filter></mark> 태그로 추가하세요. 하나의 <mark style="color:$danger;">\<intent-filter></mark> 태그에 모든 <mark style="color:$danger;">\<data></mark> 태그를 추가하면 딥링크로 앱이 열리지 않을 수 있습니다.
{% endhint %}

2\. 딥링크의 앱 링크(App Links) 앱 설정이 필요합니다. AndroidManifest.xml에 딥링크를 처리하는 Activity 아래 Intent Filter를 추가합니다.

핑거푸시 링크 대시보드의 \[커스텀 도메인] 에서 생성한 도메인 정보를 추가합니다.

{% code title="AndroidManifest.xml" %}

```xml
<activity ...>
    ...
    <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:scheme="http" android:host="YOUR_DOMAIN_NAME" />
        <data android:scheme="https" android:host="YOUR_DOMAIN_NAME" />
    </intent-filter>
    ...
</activity>
```

{% endcode %}

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

반드시 분리된 <mark style="color:$danger;">\<intent-filter></mark> 태그로 추가하세요. 하나의 <mark style="color:$danger;">\<intent-filter></mark> 태그에 모든 <mark style="color:$danger;">\<data></mark> 태그를 추가하면 딥링크로 앱이 열리지 않을 수 있습니다.
{% endhint %}

### 앱에서 딥링크 이벤트 수집하기

딥링크 이벤트를 핑거푸시 링크 SDK에 전달해 수집합니다. 딥링크로 앱이 열리면서 호출되는 OS 콜백의 가장 위에 FplinkFlutterPlugin.trackDeeplink 함수를 호출합니다.

전달받은 딥링크 데이터를 활용해 유저를 설정한 목적지도 보냅니다.

#### Flutter

{% code title="main.dart" %}

```dart
_deeplinkSubscription = Fplink.setOnDeeplinkReceived((data) {
    // 여기서 Navigator.push 등으로 화면 이동 수행
});
```

{% endcode %}

#### iOS

ios/YOUR\_PROJECT\_NAME/AppDelegate.swift 파일에 아래와 같이 코드를 추가해 주세요.

{% code title="AppDelegate.swift" %}

```swift
// when app is opened with scheme deeplink
override func application(
    _ app: UIApplication, 
    open url: URL, 
    options: [UIApplication.OpenURLOptionsKey : Any] = [:]
) -> Bool {
    FplinkFlutterPlugin.trackDeeplink(url: url)    
    return super.application(app, open: url, options: options)
}
...
// when app is opened with universal links
override func application(
    _ application: UIApplication, 
    continue userActivity: NSUserActivity, 
    restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
    FplinkFlutterPlugin.trackUniversalLink(userActivity: userActivity)
    return super.application(application, continue: userActivity, restorationHandler: restorationHandler)
    }
```

{% endcode %}

SceneDelegate를 사용하는 경우,

ios/YOUR\_PROJECT\_NAME/SceneDelegate.swift 파일에 아래와 같이 코드를 추가해 주세요.

{% code title="SceneDelegate.swift" %}

```swift
override func scene(
    _ scene: UIScene,
    willConnectTo session: UISceneSession,
    options connectionOptions: UIScene.ConnectionOptions
) {
    // Scheme Deeplink
    if let urlContext = connectionOptions.urlContexts.first {
        let url = urlContext.url
        FplinkFlutterPlugin.trackDeeplink(url: url)
    }

    // Universal Link
    if let userActivity = connectionOptions.userActivities.first,
       userActivity.activityType == NSUserActivityTypeBrowsingWeb {
       FplinkFlutterPlugin.trackUniversalLink(userActivity: userActivity)
    }
}
...
// when app is opened with scheme deeplink
override func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else { return }
    _ = FplinkFlutterPlugin.trackDeeplink(url: url)
}
...
// when app is opened with universal links
override func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    _ = FplinkFlutterPlugin.trackUniversalLink(userActivity: userActivity)
}

```

{% endcode %}

#### Android

android/app/src/main/java/.../MainActivity.kt 파일에 아래와 같이 코드를 추가해 주세요.

{% code title="MainActivity.kt" %}

```kotlin
override fun onResume() {
    super.onResume()
    FplinkFlutter.trackDeeplink(intent = intent)
}
...
override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    setIntent(intent)
}
```

{% endcode %}

#### 수집한 핑거푸시 링크 딥링크로 유저를 이동시키기&#x20;

핑거푸시 딥링크가 실행되면 [OnDeeplinkReceived](#undefined-1) 콜백에 전달됩니다.

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

디퍼드 딥링크는 자동으로 [OnDeeplinkReceived](#undefined-1)에 전달되기 때문에 별도의 설정이 필요하지 않습니다.

### 하이브리드 앱 설정하기

웹뷰는 기본적으로 딥링크를 지원하지 않습니다. 따라서 Fplink.click 함수로 SDK가 대신 트래킹 링크의 딥링크를 실행하도록 설정해야 합니다.

Fplink.click 함수는 입력된 주소가 핑거푸시 링크에서 생성한 링크면 True 를 반환합니다. 그리고 주소로 앱을 실행하면 onSuccess 함수를 호출합니다.&#x20;

입력된 주소가 다른 플랫폼의 딥링크가 실행되면 false 로 반환합니다.

{% code title="Flutter" %}

```dart
...
NavigationDelegate(
  onNavigationRequest: (NavigationRequest request) async {
    final String url = request.url;
    
    final bool isHandled = await Fplink.click(
      url,
      onSuccess: () {
        // 성공 콜
      });

     if (isHandled) {
       return NavigationDecision.prevent; // 핑거푸시 딥링크 주소로 웹뷰 로딩을 중단합니다.
     }
     
     return NavigationDecision.navigate; // 일반 링크는 로딩을 허용합니다.
   },
)
...
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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://developers.fingerpush.com/link/flutter.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.
