> ## 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.

# 트러블 슈팅 - 리액트 네이티브 SDK (Deprecated)

<AccordionGroup>
  <Accordion title="[Xcode 27] SceneDelegate 전환 필수화 및 Airbridge 딥링크 추가 설정 안내">
    <Note>
      **알립니다**

      이 문서는 기존 AppDelegate 기반 앱을 UIScene(SceneDelegate)로 전환해야 하는 고객을 위한 트러블슈팅 가이드입니다.
    </Note>

    ### 문제 현상

    * Xcode 27에서 빌드한 앱을 실행하면 화면이 흰 화면으로 표시되거나, 앱이 정상적으로 그려지지 않습니다.
    * 스킴 딥링크(Scheme Deeplink) 또는 유니버설 링크(Universal Links)로 앱에 진입해도 Airbridge 딥링크 이벤트가 수집되지 않습니다.
    * 개발자 가이드의 [프로젝트 설정 > iOS](/ko/developers/deprecated-react-native-sdk-v2#ios)와 [딥링크 설정 > AppDelegate.m](/ko/developers/deprecated-react-native-sdk-v2#appdelegate-m-2) 예제대로 `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:` |

    ### 해결 방법

    | 상태 | 처리 방법 |
    | - | - |
    | 앱이 꺼진 상태에서 딥링크 | `scene:willConnectToSession:options:`의 `connectionOptions`에서 처리<br />- `URLContexts`에서 `URL`을 꺼내 `handleURLSchemeDeeplink:` 호출<br />- `userActivities`에서 `NSUserActivity`를 꺼내 `handleUserActivity:` 호출 |
    | 스킴 딥링크(백그라운드) | `URLContexts`에서 `URL`을 꺼내 `handleURLSchemeDeeplink:` 호출 |
    | 유니버설 링크(백그라운드) | `scene:continueUserActivity:`로 전달된 `NSUserActivity`를 `handleUserActivity:`에 전달 |

    #### 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 React
        import AirbridgeRN

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

            // when terminated app is opened with scheme deeplink or universal links
            func scene(_ scene: UIScene,
                       willConnectTo session: UISceneSession,
                       options connectionOptions: UIScene.ConnectionOptions) {
                guard let windowScene = scene as? UIWindowScene else { return }

                // Move the root view controller created by RCTAppDelegate in
                // didFinishLaunching to the Scene-owned window and display it.
                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()

                // track deeplink
                if let context = connectionOptions.urlContexts.first {
                    AirbridgeRN.deeplink().handleURLSchemeDeeplink(context.url)
                }
                if let userActivity = connectionOptions.userActivities.first {
                    AirbridgeRN.deeplink().handle(userActivity)
                }
            }

            // when backgrounded app is opened with scheme deeplink
            func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
                // track deeplink
                if let context = URLContexts.first {
                    AirbridgeRN.deeplink().handleURLSchemeDeeplink(context.url)
                }
            }

            // when backgrounded app is opened with universal links
            func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
                // track deeplink
                AirbridgeRN.deeplink().handle(userActivity)
            }
        }
        ```
      </Tab>

      <Tab title="Objective-C">
        `SceneDelegate.h` / `SceneDelegate.m` 파일을 추가합니다.

        ```objective-c lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
        // SceneDelegate.h
        #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"}}
        // SceneDelegate.m
        #import "SceneDelegate.h"
        #import "AppDelegate.h"
        #import <AirbridgeRN/AirbridgeRN.h>

        @implementation SceneDelegate

        // when terminated app is opened with scheme deeplink or universal links
        - (void)scene:(UIScene *)scene
                willConnectToSession:(UISceneSession *)session
                             options:(UISceneConnectionOptions *)connectionOptions
        {
            if (![scene isKindOfClass:[UIWindowScene class]]) {
                return;
            }
            UIWindowScene *windowScene = (UIWindowScene *)scene;

            // Move the root view controller created by RCTAppDelegate in
            // didFinishLaunching to the Scene-owned window and display it.
            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];

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

        // when backgrounded app is opened with scheme deeplink
        - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
        {
            // track deeplink
            UIOpenURLContext *context = URLContexts.allObjects.firstObject;
            if (context != nil) {
                [AirbridgeRN.deeplink handleURLSchemeDeeplink:context.URL];
            }
        }

        // when backgrounded app is opened with universal links
        - (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity
        {
            // track deeplink
            [AirbridgeRN.deeplink handleUserActivity:userActivity];
        }

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

    #### 3. AppDelegate 정리

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

  <Accordion title="Braze push notification">
    `Braze SDK` 를 사용하여 push notification 을 통해 deeplink 를 open 할 시 airbridge 에서 event 가 `DEEPLINK OPEN` 이 안잡히고 `OPEN` 이 발생합니다.

    `Airbridge SDK` 는 event 확인을 위해서 activity 의 action 과 intent 의 dataString 으로 전달 되는 값을 통해 `DEEPLINK OPEN` ,`OPEN` 등을 판별 하고 있습니다. 그러나 `Braze SDK` 에 push notification 을 생성시 `Braze SDK` 에 정의 된 `NotificationTrampolineActivity` 을 통해서 open 되는데 해당 activity Action 과 intent 에서 dataString 값을 확인 할 수 없어서 발생하게 됩니다.

    `airbridge react-native SDK v2.7.1` 에서 추가된 아래 interface 를 통해 해당 내용을 해결 할 수 있습니다.

    ##### MainApplication

    `android/app/src/main/java/.../MainApplication` 파일의 `onCreate` 함수에 아래와 같은 코드를 추가해주세요.

    <CodeGroup>
      ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
      import co.ab180.airbridge.reactnative.AirbridgeRN
      import co.ab180.airbridge.reactnative.AirbridgeLifecycleIntegration

      //...

      @Override
      public void onCreate() {
          super.onCreate()
          ...
          AirbridgeRN.init(this, "YOUR_APP_NAME", "YOUR_APP_TOKEN")
          AirbridgeRN.setLifecycleIntegration {
              if (it.javaClass.name.equals("com.braze.push.NotificationTrampolineActivity")) {
                  it.intent?.extras?.getString("uri")
              } else {
                  null
              }
          }
          ...
      }
      ```

      ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
      import co.ab180.airbridge.reactnative.AirbridgeRN;
      import co.ab180.airbridge.reactnative.AirbridgeLifecycleIntegration;

      //...

      @Override
      public void onCreate() {
          super.onCreate();
          ...
          AirbridgeRN.init(this, "YOUR_APP_NAME", "YOUR_APP_TOKEN");
          AirbridgeRN.setLifecycleIntegration(new AirbridgeLifecycleIntegration() {
            @Override
            public String getDataString(Activity activity) {
              if (activity.getClass().getName().equals("com.braze.push.NotificationTrampolineActivity")
                && activity.getIntent() != null
                && activity.getIntent().getExtras() != null) {
                return activity.getIntent().getExtras().getString("uri");
              }
              return null;
            }
          });
          ...
      }
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Bitcode 컴파일 에러">
    `react-native SDK 1.5.0` 이상의 버전으로 iOS 빌드 시 Bitcode 를 지원하지 않아서 아래와 같이 에러가 발생 할 수 있습니다.

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

    `react-native SDK 1.5.0` 버전 부터 `Airbridge iOS SDK 1.28.0` 버전 으로 업데이트 되었습니다. `Airbridge iOS SDK 는 1.28.0` 버전 부터 Bitcode 를 지원하지 않습니다. 해당 에러 발생 시 아래 가이드를 참고 바랍니다.

    * [Bitcode 컴파일 에러 가이드](/ko/developers/troubleshooting-deprecated-ios-sdk-v1#bitcode-컴파일-에러)
  </Accordion>

  <Accordion title="에어브릿지 SDK 백업 규칙 병합 충돌 문제">
    * 참조 : [Android SDK Auto Backup](/ko/developers/troubleshooting-deprecated-android-sdk-v2#auto-backup)

    에어브릿지 SDK 백업 규칙과 서드파티 SDK 백업 규칙 중복 적용으로 인해 빌드 에러가 발생하는 경우 해결 방법은 아래를 참고해주세요.

    예) 에어브릿지 SDK 백업 규칙과 Appsflyer SDK 백업 규칙이 중복 적용되는 경우 아래와 같은 빌드 에러가 표시됩니다.

    ```html lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    Attribute application@fullBackupContent value=(@xml/appsflyer_backup_rules) from [com.appsflyer:af-android-sdk:6.6.1] AndroidManifest.xml:14:18-73
    is also present at [io.airbridge:sdk-android:2.14.0] AndroidManifest.xml:27:18-78 value=(@xml/airbridge_auto_backup_rules).
    Suggestion: add 'tools:replace="android:fullBackupContent"' to <application> element at AndroidManifest.xml:7:5-13:19 to override.
    ```

    이 문제를 해결하기 위해서는 아래와 같이 설정해주세요.

    <AccordionGroup>
      <Accordion title="backup_rules.xml 설정">
        1. `android/app/src/main/res/xml` 폴더를 생성해주세요.
        2. 생성된 xml 폴더 내부에 (e.g. `custom_backup_rules.xml`) 파일을 생성해주세요.
        3. 에어브릿지 SDK에서 정의하는 데이터 백업 규칙을 다음과 같이 추가해 주세요.

        ```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
        <?xml version="1.0" encoding="utf-8"?>
        <full-backup-content>
            <!-- Airbridge Backup Rules -->
            <exclude domain="sharedpref" path="airbridge-internal" />
            <exclude domain="sharedpref" path="airbridge-install" />
            <exclude domain="sharedpref" path="airbridge-user-info" />
            <exclude domain="sharedpref" path="airbridge-user-alias" />
            <exclude domain="sharedpref" path="airbridge-user-attributes" />
            <exclude domain="sharedpref" path="airbridge-device-alias" />
            <exclude domain="database" path="airbridge.db" />

            <!-- Appsflyer Backup Rules -->
            <exclude domain="sharedpref" path="appsflyer-data"/>

            <!-- Your Custom Backup Rules -->
        </full-backup-content>
        ```
      </Accordion>

      <Accordion title="AndroidManifest.xml 설정">
        ```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
        <manifest
            ...
            xmlns:tools="http://schemas.android.com/tools">

            <application
                ...
                android:allowBackup="true"
                android:fullBackupContent="@xml/custom_backup_rules"
                tools:replace="android:fullBackupContent">
        ```
      </Accordion>
    </AccordionGroup>
  </Accordion>
</AccordionGroup>
