URLからiOSアプリを開いた時にURLについてるパラメーターを取得したかったので、Firebaseのダイナミックリンクを使って実装してみようとしたんですよ。

まぁダイナミックリンクを作るまでは難なくできた。 後はアプリ側でパラメーターを取得するコードを書いて
最後にログで確認してみる....



驚く少女

URL空っぽなんですけど〜!



Firebaseの公式サイトを読み尽くして、その通りに実装したのになぜかURLがハンドリングできない。
色んなところにNSLogを仕込んだのにどこにもURLがいない...!

数日苦しんだ挙句、やっと見つけました原因。 AppDelegateではなく、SceneDelegateにダイナミックリンクがいた!

公式サイトが「AppDelegateに書け!書け!」って言っているので、SceneDelegateは盲点でした。 SceneDelegateでダイナミックリンクを取得するコードを書けば解決しました。


※追記 2020/09/20
アプリを未インストール時はAppDelegateにダイナミックリンクがいたので、合わせて対応策を記載します。



恐らくここでつまずいている人が多いと思うので、私がやった解決方法を残しておきます。





解決策

遷移前のアプリの状態によってダイナミックリンクが現れる場所が異なるので、それぞれの状態に応じて対応策を書きます。

  • アプリが開いている状態
  • アプリを起動していない
  • アプリをインストールしていない

アプリが開いている状態

XcodeプロジェクトのAppDelegate.swiftと同じ階層にいるSceneDelegate.swiftを開きます。 sceneのcontinue userActivityに実装します。

SceneDelegate.swift
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {

        // urlを取得
        guard let url = userActivity.webpageURL else { return }
        NSLog("\(url)🌕")

        // パラメーターを取得
        if let query = url.query {
            NSLog("\(query)🌕")
        }
}

アプリをインストールしていない

XcodeプロジェクトのAppDelegate.swiftと同じ階層にいるSceneDelegate.swiftを開きます。 sceneのwillConnectToに実装します。

SceneDelegate.swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        guard let _ = (scene as? UIWindowScene) else { return }

        // URLを取得
        guard let userActivity
            = connectionOptions.userActivities
                .first(where: { $0.webpageURL != nil }) else { return }
        NSLog("\(userActivity.webpageURL!) 🌕")

        // パラメーターを取得
        if let query = userActivity.webpageURL!.query {
            NSLog("\(query) 🌕")
        }   

 }


アプリを起動していない

XcodeプロジェクトのAppDelegate.swiftを開きます。 open urlに実装します。

AppDelegate.swift
func application(
        _ app: UIApplication,
        open url: URL,
        options: [UIApplication.OpenURLOptionsKey : Any] = [:]
    ) -> Bool {

  // URLを取得
        NSLog("\(url)🌕")

        // パラメーターを取得
        if let query = url.query {
   NSLog("\(query)🌕")
        }

        // ちなみにダイナミックリンクのパラメーターのみ取得する場合
        if let link = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
              if let dynamicLink = link.url, let query = dynamicLink.query {
                      NSLog("\(query)🌕")
              }
        }
        return ApplicationDelegate.shared.application(
            app,
            open: url,
            sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
            annotation: options[UIApplication.OpenURLOptionsKey.annotation]
        )
    }

他のアプリの状態ではSceneDelegateで取得できたので、未インストール時もSceneDelegateにいるのかと思いきや、AppDelegateにいました😱
もう、ややこしい....笑

エラーが起こる環境

Scene Delegateがテンプレートととして使用され始めたのはXcode11、iOS13。
それ以降はプロジェクトの設定を何も変えていないと、AppDelegateでURLを取得する処理を書いても「無」なんですね。
Scene Delegateを削除してAppDelegateに向ける方法もあるみたいですが、怖かったので今回はこちらの方法で解決しました。

まとめ

ダイナミックリンクはAppDelegateではなく、Scene Delegateにいるよ。
アプリを起動した状態で遷移した時と、アプリを起動していない状態で遷移した時では処理が違うのでお気をつけください!