Firebase Dynamic Linkでlink情報がnilでつまづいたお話

### はじめに
Firebase Dynamic Link導入時に苦戦したこと
調べても調べても解決策が見つからず、たどり着くまでかなり時間がかかったため、メモ

同じ事象の人の助けになれば、、


### 前提と実装したかったこと
・SwiftUI(SwiftUI App)で実装していた


DynamicLinkから来たユーザーで
①アプリを既にインストール済みのユーザーは、アプリ起動しdeeplink情報で画面遷移
②アプリ未インストールのユーザーはAppStore→DL後アプリ起動しdeeplink情報で画面遷移

### つまづいた箇所
②が必ずnilとなっていた。
（①のみであればSwiftUI onOpenURLでも実装可能）

### 解決策
~~SwiftUI AppからAppDelegateの呼び出しをやめ、AppDelegateのライフサイクルのみを利用するように変更し解決。~~
→SceneDelegate読み込みで検知できたので追記



### 内容をつらつら書く（SceneDelegateで解決できたので下に追記更新）
SwiftUI(SwiftUI App) でアプリ開発をしていて、ライフサイクルであるSwiftUI Appでできない箇所は、AppDelegateを呼び出して処理を実装していた。 Firebase Dynamic Linkでは数行のコードをAppDelegate内に記載する必要があったため、AppDelegate内に記載し、UIApplicationDelegateAdaptorで呼び出し利用できる想定でいたが実際は、該当のコードがデバッグでも引っかからず呼ばれていないかった（他のAppDelegate内のコードは呼ばれる）

そのため、AppDelegate 内にSence Delegateを呼び出して利用 SwiftUI App → AppDelegate → Sence Delegateのように呼び出しFirebase Dynamic LinkのコードをSence Delegateに記載するように変更後、無事初回起動時には呼ばれることを確認したが、 userActivity.webpageURLが必ずnilとなっていた...

公式ドキュメントとの違いといえば、Swift（AppDelegate)かSwiftUI（SwiftUI App)の違いだったため、SwiftUI(SwiftUI App)のライフサイクルではなく、SwiftUI(AppDelegate)一つに変更したことで無事、想定通り値が取得でき、AppStoreからのリンクも取得できた。

AppDelegateのみに変更時は、Info.plistのUIApplicationSceneManifestを削除して対応しました。

### SceneDelegate読み込みでできたのでメモ(2022/8/28 追記)
SwiftUI AppでUIApplicationDelegateAdaptorを利用しAppDelegate呼び出し
AppDelegate内でSenceDelegate呼び出し
SceneDelegate内で初回起動時に流入元URL情報取得しFirebase Dynamic Link問い合わせ
問い合わせ結果の中身を取得し処理
初回起動時ではなくアプリがバックグラウンド状態の場合のハンドリングはonOpenURL側で実施



```Swift
@main
struct TestApp:App {
    //appDelegate読み込み
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate 
    
    var body: some Scene {
        WindowGroup {
            RootView()
        }
    }
}

```

#### AppDelegate
```Swift
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:
                     [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        FirebaseOptions.defaultOptions()?.deepLinkURLScheme = customURLScheme
        FirebaseApp.configure()
        
        return true
    }

    //SceneDelegate呼び出し
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        let config = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
        config.delegateClass = SceneDelegate.self
        return config
    }

```


#### SceneDelegate
```Swift
//初回起動
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        guard let url = URLContexts.first?.url.absoluteString else { return }
        
        /*
            urlの中身からfirebase dynamic linkのURLを抽出/生成しhandleUniversalLinkに受け渡す
            ex）
            let dynamicId = urlからID抽出
            let dynamicUrl = "https://xxxx.page.link/\(dynamicId)"
        */
        DynamicLinks.dynamicLinks().handleUniversalLink(dynamicUrl) { dynamiclink, error in
            print(dynamiclink)
        }
        
    }

    //2回目以降の起動かつアプリがバックグラウンド状態でない場合
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        for userActivity in connectionOptions.userActivities {
            if let incomingURL = userActivity.webpageURL{
                DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { (dynamiclink, error) in
                    guard error == nil else{ return }
                    if let dynamiclink = dynamiclink {
                        print(dynamiclink)
                    }
                }
                break
            }
        }
    }

```



### 参考リンク

https://qiita.com/koogawa/items/3472398afd4d809148b0