> ## Documentation Index
> Fetch the complete documentation index at: https://help.airbridge.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 트러블 슈팅 - iOS SDK (Deprecated)

<AccordionGroup>
  <Accordion title="[Xcode 27] SceneDelegate 전환 필수화 및 Airbridge 딥링크 추가 설정 안내">
    <Note>
      이 문서는 기존 AppDelegate 기반 앱을 `SceneDelegate`(UIScene 생명주기)로 전환해야 하는 고객을 위한 트러블슈팅 가이드입니다.
    </Note>

    #### 문제 현상

    * Xcode 27에서 빌드한 앱을 실행하면 화면이 흰 화면으로 표시되거나, 앱이 정상적으로 그려지지 않습니다.
    * 스킴 딥링크(Scheme Deeplink) 또는 유니버설 링크(Universal Links)로 앱에 진입해도 Airbridge 딥링크 이벤트가 수집되지 않습니다.
    * 개발자 가이드의 [딥링크 설정 > AppDelegate.m](/ko/developers/deprecated-ios-sdk-v1#appdelegate를-사용하는-경우) 예제대로 `AppDelegate`에 코드를 작성했는데도 동작하지 않습니다.

    #### 발생 원인

    Apple은 앱 생명주기를 `UIApplicationDelegate`(AppDelegate) 단독 방식에서 `UIScene` 기반(SceneDelegate) 방식으로 전환하고 있으며, 최신 Xcode/iOS에서는 Scene 생명주기 채택이 사실상 필수가 되었습니다.

    앱이 `UIApplicationSceneManifest`를 통해 Scene 생명주기를 채택하면, 다음 `AppDelegate` 딥링크 콜백은 **더 이상 호출되지 않습니다.**

    | 기존 `AppDelegate` 콜백 | Scene 생명주기에서의 대체 콜백 (`SceneDelegate`) |
    | - | - |
    | `application:didFinishLaunchingWithOptions:`에서의 `window` 생성 | `scene:willConnectToSession:options:` |
    | 앱 콜드 스타트 시점의 딥링크 | `scene:willConnectToSession:options:`의 `connectionOptions` |
    | `application:openURL:options:` | `scene:openURLContexts:` |
    | `application:continueUserActivity:restorationHandler:` | `scene:continueUserActivity:` |

    #### 해결 방법

    ##### 1. Info.plist에 Scene Manifest 추가

    `Info.plist`에 아래 `UIApplicationSceneManifest`를 추가합니다.

    `UISceneDelegateClassName` 값은 사용하는 언어/모듈에 맞게 지정합니다.

    * Objective-C: `SceneDelegate`
    * Swift: `$(PRODUCT_MODULE_NAME).SceneDelegate`

    ```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    <key>UIApplicationSceneManifest</key>
    <dict>
        <key>UIApplicationSupportsMultipleScenes</key>
        <false/>
        <key>UISceneConfigurations</key>
        <dict>
            <key>UIWindowSceneSessionRoleApplication</key>
            <array>
                <dict>
                    <key>UISceneConfigurationName</key>
                    <string>Default Configuration</string>
                    <key>UISceneDelegateClassName</key>
                    <string>SceneDelegate</string>
                </dict>
            </array>
        </dict>
    </dict>
    ```

    ##### 2. SceneDelegate 생성 및 딥링크 수집 코드를 SceneDelegate로 이전

    <Tabs>
      <Tab title="Swift">
        ```swift lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
        import UIKit
        import AirBridge

        class SceneDelegate: UIResponder, UIWindowSceneDelegate {
            var window: UIWindow?

            func scene(_ scene: UIScene,
                       willConnectTo session: UISceneSession,
                       options connectionOptions: UIScene.ConnectionOptions) {
                guard let windowScene = scene as? UIWindowScene else { return }

                let appDelegate = UIApplication.shared.delegate as? AppDelegate
                let window = UIWindow(windowScene: windowScene)
                window.rootViewController = appDelegate?.window?.rootViewController
                self.window = window
                appDelegate?.window = window
                window.makeKeyAndVisible()

                if let context = connectionOptions.urlContexts.first {
                    AirBridge.deeplink()?.handleURLSchemeDeeplink(context.url)
                }
                if let userActivity = connectionOptions.userActivities.first {
                    AirBridge.deeplink()?.handle(userActivity)
                }
            }

            func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
                if let context = URLContexts.first {
                    AirBridge.deeplink()?.handleURLSchemeDeeplink(context.url)
                }
            }

            func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
                AirBridge.deeplink()?.handle(userActivity)
            }
        }
        ```
      </Tab>

      <Tab title="Objective-C">
        ```objective-c lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
        #import <UIKit/UIKit.h>

        API_AVAILABLE(ios(13.0))
        @interface SceneDelegate : UIResponder <UIWindowSceneDelegate>

        @property (strong, nonatomic) UIWindow *window;

        @end
        ```

        ```objective-c lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
        #import "SceneDelegate.h"
        #import "AppDelegate.h"
        #import <AirBridge/AirBridge.h>

        @implementation SceneDelegate

        - (void)scene:(UIScene *)scene
                willConnectToSession:(UISceneSession *)session
                                          options:(UISceneConnectionOptions *)connectionOptions
        {
            if (![scene isKindOfClass:[UIWindowScene class]]) {
                return;
            }
            UIWindowScene *windowScene = (UIWindowScene *)scene;
            AppDelegate *appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate;
            UIWindow *window = [[UIWindow alloc] initWithWindowScene:windowScene];
            window.rootViewController = appDelegate.window.rootViewController;
            self.window = window;
            appDelegate.window = window;
            [window makeKeyAndVisible];

            UIOpenURLContext *context = connectionOptions.URLContexts.allObjects.firstObject;
            if (context != nil) {
                [AirBridge.deeplink handleURLSchemeDeeplink:context.URL];
            }
            NSUserActivity *userActivity = connectionOptions.userActivities.allObjects.firstObject;
            if (userActivity != nil) {
                [AirBridge.deeplink handleUserActivity:userActivity];
            }
        }

        - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
        {
            UIOpenURLContext *context = URLContexts.allObjects.firstObject;
            if (context != nil) {
                [AirBridge.deeplink handleURLSchemeDeeplink:context.URL];
            }
        }

        - (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity
        {
            [AirBridge.deeplink handleUserActivity:userActivity];
        }

        @end
        ```
      </Tab>
    </Tabs>

    ##### 3. AppDelegate 정리

    * SDK 초기화 코드(Objective-C: `[AirBridge getInstance:appName:withLaunchOptions:]`, Swift: `AirBridge.getInstance(_:appName:withLaunchOptions:)`)는 `application:didFinishLaunchingWithOptions:`에 **그대로 둡니다.**
    * 딥링크 수집을 위해 작성했던 `application:openURL:options:`와 `application:continueUserActivity:restorationHandler:`는 Scene 생명주기에서 호출되지 않으므로, `SceneDelegate`로 이전한 뒤 `AppDelegate`에서는 삭제합니다.
  </Accordion>

  <Accordion title="Webcredentials">
    App 에서 [Autofill](https://developer.apple.com/documentation/security/password-autofill) 기능을 사용해 비밀번호를 저장하는 경우 `webcredentials:...` 설정이 되어 있지 않으면 비밀번호가 `applinks:YOUR_APP_NAME.airbridge.io` 또는 `applinks:YOUR_APP_NAME.abr.ge` 의 도메인에 저장됩니다.

    비밀번호가 저장되는 도메인을 변경하고 싶다면, `example.com` 을 `설정할 도메인` 으로 변경해서 아래와 같이 설정해주세요.

    1. `https://example.com/.well-known/apple-app-site-association`주소에서 아래 내용을 호스팅 합니다.

    ```json lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    {
        "webcredentials": {
            "apps": ["TEAM_ID.APP_BUNDLE_ID"]
        }
    }
    ```

    예) 9JA89QQLNQ.com.apple.wwdc

    2. Xcode > Project 파일 > Signing & Capabilities > Associated Domains 로 이동해주세요.
    3. `+`버튼을 눌러 `webcredentials:example.com`을 추가해주세요.
  </Accordion>

  <Accordion title="Bitcode 컴파일 에러">
    Airbridge iOS SDK 는 1.28.0 버전 부터 Bitcode 를 지원하지 않습니다. (Xcode 14 부터 Bitcode 가 deprecate 되었습니다.) 하지만 App 프로젝트에서 Bitcode 를 사용하는 경우 아래와 같은 컴파일에러가 발생할 수 있습니다.

    ```html Text lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    Textld: XCFrameworkIntermediates/AirBridge/AirBridge.framework/AirBridge(AirBridge-arm64-master.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE)
    ```

    이 문제를 해결하기 위해서는 Podfile 파일에 아래와 같은 내용을 추가하거나 Xcode 에서 `ENABLE_BITCODE` 설정을 `NO`로 설정해주시면 됩니다.

    ```html Podfile lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |configuration|
            configuration.build_settings['ENABLE_BITCODE'] = 'NO'
        end
    end
    ```

    Xcode 에서 ENABLE\_BITCODE 설정을 NO 로 설정해주시면 됩니다.

    <Note>
      Apple Appstore 에서는 Bitcode 를 Deprecate 하여 Bitcode 를 사용하는 `.ipa` 파일이 제출되어도 자동으로 Bitcode 를 제거합니다.
    </Note>
  </Accordion>

  <Accordion title="Xcode 13 에서 빌드가 안되는 문제">
    Airbridge iOS SDK 는 1.28.0 버전 부터 Xcode 13 및 iOS 9, 10 을 지원하지 않습니다. 해당 지원이 필요하신 경우, Airbridge iOS SDK 1.27.0 이하 버전을 사용해주셔야 합니다.
  </Accordion>

  <Accordion title="Tuist fetch 와 SPM 으로 설치하면 iOS 14.2 미만에서 크래시가 발생하는 문제">
    Airbridge iOS SDK 는 여러 iOS 내장 Framework 를 활용합니다. 그 중 AdServices 는 iOS 14.2 이상을 필요로 합니다. 그런데 Swift Package Manager 에는 `Link 될 Framework 의 Minimum OS Version` 이 `Target 의 Minimum OS Version` 보다 높으면 자동으로 `Optional` 로 Link 하는 기능이 있지만, Swift Package Manager 를 사용하지 않고 Metadata 만 가져와서 Swift Package Manager 의 동작을 대신하는 Tuist fetch 에는 무조건 `Required` 로 Link 해서 이 이슈가 발생합니다. ([문제가 되는 Tuist 코드](https://github.com/tuist/tuist/blob/93a06710b6ce738247436958a762c7ca282a790d/Sources/TuistDependencies/SwiftPackageManager/Utils/PackageInfoMapper.swift#L869))

    이 경우, Tuist 에서 제공하는 \`Xcode Native Package Manager Support\` [방법](https://docs.tuist.io/guides/third-party-dependencies)을 따라 SDK 를 설치하시거나, 아래와 같이 AirBridge.xcframework 직접 다운로드 받아 추가하시면 문제가 해결됩니다.

    ```swift lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    .xcframework(path: "${YOUR_PATH}/AirBridge.xcframework")
    .sdk(name: "AdSupport", type: .framework, status: .optional)
    .sdk(name: "iAd", type: .framework, status: .optional)
    .sdk(name: "AdServices", type: .framework, status: .optional)
    .sdk(name: "CoreTelephony", type: .framework, status: .optional)
    .sdk(name: "StoreKit", type: .framework, status: .optional)
    .sdk(name: "AppTrackingTransparency", type: .framework, status: .optional)
    .sdk(name: "WebKit", type: .framework, status: .optional)
    ```
  </Accordion>
</AccordionGroup>
