# \[iOS]Universal Links に対応する

KARTE iOS SDKのアプリ内メッセージやプッシュ通知では、標準的な実装を行った時、クリック時の遷移先にリンクを指定すると、 `UIApplication` クラスの `open(_:options:completionHandler:)` を呼び出し外部アプリを起動します。\
`http` または `https` から始まるリンクの場合は Safari等のブラウザが起動します。\
そのため、ボタンのリンク等にアプリ内遷移用の Universal Links を設定していても、標準の挙動ではブラウザアプリを起動してしまいます。

参考：

* [アプリ内メッセージのリンクを制御する | リンククリック時の挙動](https://app.developers.karte.io/ios-sdk-appendix/pages/iyytFunZrCVFzRXz0YRL#リンククリック時の挙動)
* [プッシュ通知を受信する | 通知開封時の処理を実装する](https://app.developers.karte.io/ios-sdk-appendix/pages/F3XEGlW5igUpZFWHqJNM#2-通知開封時の処理を実装する)

KARTEのアクションにおいて Universal Links を利用したアプリ内処理を行いたい場合は、独自にアプリ内処理を実装する必要があります。\
また、アプリがUniversal Linksを受け取った時にKARTE SDKの機能を使用したい場合、アプリのハンドリング実装に加えKARTE SDKのハンドラを呼び出していただく必要があります。

{% hint style="warning" %}
**サンプルコードについて**

サンプルコードはエラーハンドリングなどは、最低限の記述になっています。\
必要であればより厳密な値・型チェックを追加し、リリース前に必ず動作確認をしてください。
{% endhint %}

## アプリ内メッセージのリンクでの対応

アプリ内メッセージ上のリンククリック後、指定したURLを用いてアプリケーション側でUniversal Linksを受け取った時と同等の処理を行いたい場合、`InAppMessagingDelegate` プロトコルの `inAppMessaging(_:shouldOpenURL:)` を実装し、URLを確認することで処理を行うことができます。\
※ shouldOpenURLはUniversal Linksに限らず、アクション上で発生する全てのリンク遷移のパターンで動作します。

### 実装例

{% tabs %}
{% tab title="Swift" %}
{% code overflow="wrap" %}

```swift
func inAppMessaging(_ inAppMessaging: InAppMessaging, shouldOpenURL url: URL) -> Bool {

  // 特定のホスト・パス等でuniversal linksで起動された際と同じ処理を行う
  if url.host == "your-app-domain.example.com" {
    // handleUniversalLinksは、任意のUniversal Linksを処理するアプリ側の処理を想定しています
    handleUniversalLinks(url)
    // SDKの処理を止める場合は `false` を返す
    return false
  }

  // その他のURL等、SDKに移譲する場合は `true` を返す
  return true
}
```

{% endcode %}
{% endtab %}

{% tab title="Objective-C" %}
{% code overflow="wrap" %}

```objc
- (BOOL)inAppMessaging:(KRTInAppMessaging *)inAppMessaging shouldOpenURL:(NSURL *)url {

    // 特定のホスト・パス等でuniversal linksで起動された際と同じ処理を行う
    if ([url.host isEqualToString:@"your-app-domain.example.com"]) {
        handleUniversalLinks(url);
        // SDKの処理を止める場合は `NO` を返す
        return NO;
    }

    // その他のURL等、SDKに移譲する場合は `YES` を返す
    return YES;
}
```

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

また委譲先のインスタンスの登録は、以下のように実装します。

{% tabs %}
{% tab title="Swift" %}
{% code overflow="wrap" %}

```swift
InAppMessaging.shared.delegate = instance
```

{% endcode %}
{% endtab %}

{% tab title="Objective-C" %}
{% code overflow="wrap" %}

```objc
[[KRTInAppMessaging shared] setDelegate:instance];
```

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

## プッシュ通知での対応

プッシュ通知をタップした際に、指定したURLを用いてアプリケーション側でUniversal Linksを受け取った時と同等の処理を行いたい場合、通知タップ時のコールバック上でURLを確認することで処理を行うことができます。\
参考：[プッシュ通知を受信する | 通知開封時の処理を実装する](https://app.developers.karte.io/ios-sdk-appendix/pages/F3XEGlW5igUpZFWHqJNM#2-通知開封時の処理を実装する)

### 実装例

#### UserNotifications.frameworkを利用するアプリケーションの場合

{% tabs %}
{% tab title="Swift" %}
{% code overflow="wrap" %}

```swift
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
  let userInfo = response.notification.request.content.userInfo

  // KARTE経由のプッシュ通知であるか判定
  if let notification = RemoteNotification(userInfo: userInfo) {

    // 特定のホスト・パス等でuniversal linksで起動された際と同じ処理を行う
    if url?.host == "your-app-domain.example.com" {
      // handleUniversalLinksは、任意のUniversal Linksを処理するアプリ側の処理を想定しています
      handleUniversalLinks(url)
      completionHandler()
      return
    }

    // その他の場合はSDKの機能を用いて外部アプリを開く
    notification.handle()
  } else {
    // KARTE以外のシステムから送信されたプッシュ通知
  }
  completionHandler()
}
```

{% endcode %}
{% endtab %}

{% tab title="Objective-C" %}
{% code overflow="wrap" %}

```objc
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
  NSDictionary *userInfo = response.notification.request.content.userInfo;

  // KARTE経由のプッシュ通知であるか判定
  KRTRemoteNotification *notification = [[KRTRemoteNotification alloc] initWithUserInfo:userInfo];
  if (notification) {

    // 特定のホスト・パス等でuniversal linksで起動された際と同じ処理を行う
    NSURL *url = [notification url];
    if (url && [url.host isEqualToString:@"your-app-domain.example.com"]) {
        handleUniversalLinks(url);
        completionHandler();
        return;
    }

    // その他の場合はSDKの機能を用いて外部アプリを開く
    [notification handle];
  } else {
    // KARTE以外のシステムから送信されたプッシュ通知
  }
  completionHandler();
}
```

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

## ディープリンクを利用したKARTE SDK機能

下記のようなディープリンクを利用したKARTE SDKの機能を、カスタムURLスキーム同様にUniversal Links経由でも利用するためには、ディープリンク経由での起動時にSDKのハンドラを呼び出す必要があります。

* ディープリンク経由での起動イベント (`deep_link_app_open`)

参考：[カスタムURLスキームハンドラを追加する](https://app.developers.karte.io/ios-sdk-appendix/pages/GRf2qVego5fENzB8W2cu#カスタムurlスキームハンドラを追加する)

### 実装例

UIApplicationDelegateの `application(_:continue:restorationHandler:)` メソッド内にハンドラを追加します。

{% tabs %}
{% tab title="Swift" %}
{% code title="AppDelegate.swift" overflow="wrap" %}

```swift
func application(_ app: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
  if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
    KarteApp.application(app, open: userActivity.webpageURL!)
  }

  // 必要に応じた値を返してください
  return true
}
```

{% endcode %}
{% endtab %}

{% tab title="Objective-C" %}
{% code title="AppDelegate.m" overflow="wrap" %}

```objc
- (BOOL)application:(UIApplication *)app continueUserActivity:(NSUserActivity *)userActivity
 restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
  if ([[userActivity activityType] isEqualToString:NSUserActivityTypeBrowsingWeb]) {
    NSURL *url = [userActivity webpageURL];
    [KRTApp application:app openURL:url];
  }

  // 必要に応じた値を返してください
  return YES;
}
```

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

なお iOS13 から利用可能な `UISceneDelegate` を実装している場合は、`scene(_:willConnectTo:options:)` および `scene(_:openURLContexts:)` メソッド内にハンドラを追加します。**UISceneDelegateの設定が有効な場合は上記のUIApplicationDelegateのメソッドは呼ばれません。**

{% tabs %}
{% tab title="Swift" %}
{% code overflow="wrap" %}

```swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
  if let context = connectionOptions.urlContexts.first {
    KarteApp.application(UIApplication.shared, open: context.url)
  }
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
  if let context = URLContexts.first {
    KarteApp.application(UIApplication.shared, open: context.url)
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="Objective-C" %}
{% code overflow="wrap" %}

```objc
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
  NSUserActivity *userActivity = connectionOptions.userActivities.anyObject;
  if (userActivity) {
    NSURL *url = [userActivity webpageURL];
    [KRTApp application:[UIApplication sharedApplication] openURL:url];
  }
}

- (void)scene:(UIScene *)scene
continueUserActivity:(NSUserActivity *)userActivity {
  if ([[userActivity activityType] isEqualToString:NSUserActivityTypeBrowsingWeb]) {
    NSURL *url = [userActivity webpageURL];
    [KRTApp application:[UIApplication sharedApplication] openURL:url];
  }
}
```

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

ディープリンク及びUniversal Links処理の実装については公式ドキュメントも参照してください。

* [Defining a custom URL scheme for your app](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app)
* [Supporting Universal Links in Your App | Apple Developer Documentation](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app)


---

# 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://app.developers.karte.io/ios-sdk-appendix/appendix-universal-links-ios-sdk.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.
