— Universal Links に対応する

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

参考:

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

🚧

サンプルコードについて

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

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

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

実装例

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

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

  // その他のURL等、SDKに移譲する場合は `true` を返す
  return true
}
- (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;
}

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

InAppMessaging.shared.delegate = instance
[[KRTInAppMessaging shared] setDelegate:instance];

プッシュ通知での対応

プッシュ通知をタップした際に、指定したURLを用いてアプリケーション側でUniversal Linksを受け取った時と同等の処理を行いたい場合、通知タップ時のコールバック上でURLを確認することで処理を行うことができます。
参考:プッシュ通知を受信する | 通知開封時の処理を実装する

実装例

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

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(url)
      completionHandler()
      return
    }

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

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

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

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

参考:カスタムURLスキームハンドラを追加する

実装例

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

func application(_ app: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
  if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
    KarteApp.application(app, open: userActivity.webpageURL!)
  }
  
  // 必要に応じた値を返してください
  return true
}
- (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;
}

なお iOS13 から利用可能な UISceneDelegate を実装している場合は、scene(_:willConnectTo:options:) および scene(_:continue:) メソッド内にハンドラを追加します。

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
  if let userActivity = connectionOptions.userActivities.first,
    userActivity.activityType == NSUserActivityTypeBrowsingWeb {
    KarteApp.application(UIApplication.shared, open: userActivity.webpageURL!)
  }
}

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
  if userActivity.activityType == NSUserActivityTypeBrowsingWeb {
    KarteApp.application(UIApplication.shared, open: userActivity.webpageURL!)
  }
}
- (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];
  }
}

Universal Links処理の実装については公式ドキュメントも参照してください。