트러블 슈팅 - 언리얼 SDK

iOS

문제 현상

Password AutoFill 기능으로 저장된 암호의 도메인이 airbridge.io 또는 abr.ge로 보이는 현상이 앱을 사용하는 유저에게 발생할 수 있습니다.

발생 원인

에어브릿지 SDK의 딥링크를 설정한 후에 Password AutoFill 기능을 활용하면 도메인이 에어브릿지 딥링크의 앱 링크(applinks) 도메인 airbridge.io 또는 abr.ge로 저장됩니다.

해결 방법

Password AutoFill에 사용하는 webcredentials 도메인을 설정하면 문제를 해결할 수 있습니다.

1. 암호를 저장하는 도메인을 준비해주세요.

2. 아래 JSON을 https://YOUR_DOMAIN/.well-known/apple-app-site-associationContent-Type: application/json으로 호스팅합니다. 준비한 도메인이 YOUR_DOMAIN입니다.

애플 개발자 대시보드의 [Identifiers]>[YOUR_APP]에서 App ID Prefix, Bundle ID를 확인할 수 있습니다.

12345
{
    "webcredentials": {
        "apps": ["YOUR_APP_ID_PREFIX.YOUR_BUNDLE_ID"]
    }
}

3. Xcode의 [YOUR_PROJECT]>[Signing & Capabilities]로 이동합니다.

4. '+ Capability'를 클릭해 Associated Domains를 추가합니다. Associated Domains에 webcredentials:YOUR_DOMAIN을 입력합니다.

문제 현상

App Store에 앱 업로드 시 Xcode에 Airbridge framework에 dSYM이 포함되어 있지 않다는 경고 메세지가 나타나는 현상

발생 원인

Airbridge iOS SDK에서 dSYM을 지원하고 있지 않습니다.

해결 방법

다음 버전에서 dSYM 지원을 개발 중에 있습니다. 해당 경고는 무시해 주세요.

안드로이드

문제 현상

빌드하면 아래 메시지와 함께 Dependencies coroutines 오류가 발생합니다.

Text
1234
java.lang.NoClassDefFoundError: kotlin/coroutines/AbstractCoroutineContextKey
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
  ...

발생 원인

kotlinx-coroutines-core 라이브러리 버전이 v1.3.5 이상이면 kotlin-stdlib 라이브러리 버전이 일정 레벨 이상이어야 합니다.

해결 방법

gradlew dependencies 커멘드로 kotlin-stdlib 라이브러리 버전이 v1.3.70 이상인지 확인해 주세요. 해당 버전 미만이라면 업데이트를 진행해야 합니다.

문제 현상

브레이즈 SDK를 사용한 푸시 알림으로 발생한 딥링크 실행(Deeplink Open) 이벤트가 수집되지 않습니다. 대신 실행(Open) 이벤트가 수집됩니다.

발생 원인

에어브릿지 안드로이드 SDK는 activity의 action에 있는 dataString과 intent의 dataString으로 딥링크 실행 이벤트와 실행 이벤트를 판별합니다.

브레이즈 SDK를 사용한 푸시 알림으로 앱을 실행하면 NotificationTrampolineActivity을 사용합니다. 브레이즈 SDK를 사용한 푸시 알림으로 앱을 실행하면 NotificationTrampolineActivity의 activity의 action과 intent로부터 dataString을 확인할 수 없습니다. 이로 인해 딥링크 실행 이벤트와 실행 이벤트를 판별할 수 없습니다.

해결 방법

커스텀 애플리케이션 클래스 (CustomApplication.java) 파일을 아래와 같이 추가해주세요.

12345678910111213141516171819202122232425262728293031323334
package com.company.product;

import android.app.Activity;

import com.epicgames.ue4.GameApplication;

import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;

import co.ab180.airbridge.AirbridgeLifecycleIntegration;
import co.ab180.airbridge.ue.AirbridgeUnreal;

public class CustomApplication extends GameApplication {

    @Override
    public void onCreate() {
        super.onCreate();

        AirbridgeUnreal.setLifecycleIntegration(new AirbridgeLifecycleIntegration() {

            @Nullable
            @Override
            public String getDataString(@NotNull 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;
            }
        });
    }
}
12345678910111213141516171819202122232425262728293031323334
package com.company.product;

import android.app.Activity;

import com.epicgames.unreal.GameApplication;

import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;

import co.ab180.airbridge.AirbridgeLifecycleIntegration;
import co.ab180.airbridge.ue.AirbridgeUnreal;

public class CustomApplication extends GameApplication {

    @Override
    public void onCreate() {
        super.onCreate();

        AirbridgeUnreal.setLifecycleIntegration(new AirbridgeLifecycleIntegration() {

            @Nullable
            @Override
            public String getDataString(@NotNull 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;
            }
        });
    }
}

커스텀 애플리케이션 클래스를 Android Manifest 파일에 Unreal Plugin Language (UPL)를 이용하여 아래와 같이 추가해주세요.

123456789101112
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:android="http://schemas.android.com/apk/res/android">
	
    <prebuildCopies>
        <copyDir src="$S(PluginDir)/..." dst="$S(BuildDir)/src/com/company/product" />
    </prebuildCopies>
    
	<androidManifestUpdates>
		<addAttribute tag="application" name="android:name" value="com.company.product.CustomApplication"/>
	</androidManifestUpdates>
	
</root>

문제 현상

빌드하면 Manifest merger failed 오류가 발생합니다.

발생 원인

에어브릿지 SDK의 AndroidManifest.xml에는 공유 환경 설정 데이터 백업을 옵트아웃하는 규칙이 포함되어 있습니다. 이는 재설치 중에 동일한 에어브릿지 설정 값들을 유지하지 않도록 하여 새로운 설치 또는 재설치를 정확하게 감지하도록 하기 위해 수행됩니다.

에어브릿지 SDK 백업 규칙과 앱 백업 규칙의 병합 과정에서 충돌이 발생할 수 있습니다.

해결 방법

에어브릿지 SDK에서 정의하는 옵트아웃하는 규칙은 다음과 같습니다.

123456789101112131415161718192021
<?xml version="1.0" encoding="utf-8"?>
<data-extraction-rules>
    <cloud-backup>
        <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" />
    </cloud-backup>
    <device-transfer>
        <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" />
    </device-transfer>
</data-extraction-rules>
12345678910
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
    <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" />
</full-backup-content>

fullBackupContent="string"과의 충돌 방지

android:fullBackupContent="string"AndroidManifest.xml에 추가하면 다음과 같은 오류가 발생할 수 있습니다.

Build Output
1
Manifest merger failed : Attribute application@fullBackupContent value=(string) from AndroidManifest.xml

위 오류를 해결하려면

  • 언리얼 에디터 Project Settings 창의 Platforms - Android > Advanced APK Packaging > Extra Tags for <manifest> nodexmlns:tools="http://schemas.android.com/tools"를 추가 해주세요.

  • 언리얼 에디터 Project Settings 창의 Platforms > Android > Extra Tags for <application> nodetools:replace="android:fullBackupContent"를 추가 해주세요.

dataExtractionRules="string resource"과의 충돌 방지

android:dataExtractionRules="string resource"AndroidManifest.xml에 추가하면 다음과 같은 오류가 발생할 수 있습니다.

Build Output
12
Manifest merger failed : Attribute application@dataExtractionRules value=(string resource) from AndroidManifest.xml

위 오류를 해결하려면

  • 언리얼 에디터 Project Settings 창의 Platforms - Android > Advanced APK Packaging > Extra Tags for <manifest> nodexmlns:tools="http://schemas.android.com/tools"를 추가 해주세요.

  • 언리얼 에디터 Project Settings 창의 Platforms > Android > Extra Tags for <application> nodetools:replace="android:dataExtractionRules"를 추가 해주세요.

allowBackup="false"과의 충돌 방지

android:allowBackup="false"AndroidManifest.xml에 추가하면 다음과 같은 오류가 발생할 수 있습니다.

Build Output
123
Manifest merger failed : Attribute application@allowBackup value=(false) from AndroidManifest.xml:32:9-36
	is also present at [:airbridge] AndroidManifest.xml:27:9-35 value=(true).
	Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:30:5-250:19 to override.

위 오류를 해결하려면

  • 언리얼 에디터 Project Settings 창의 Platforms - Android > Advanced APK Packaging > Extra Tags for <manifest> nodexmlns:tools="http://schemas.android.com/tools"를 추가 해주세요.

  • 언리얼 에디터 Project Settings 창의 Platforms > Android > Extra Tags for <application> nodetools:replace="android:allowBackup"를 추가 해주세요.

compileSdkVersion이 31 미만일 경우

android:dataExtractionRules 기능이 API Level 31 부터 추가되었기 때문에 compileSdkVersion이 31 미만일 경우, 다음과 같은 오류가 발생할 수 있습니다.

Build Output
1
AndroidManifest.xml: AAPT: error: attribute android:dataExtractionRules not found.

위 오류를 해결하려면

  • 언리얼 에디터 Project Settings 창의 Platforms - Android > Advanced APK Packaging > Extra Tags for <manifest> nodexmlns:tools="http://schemas.android.com/tools"를 추가 해주세요.

  • 언리얼 에디터 Project Settings 창의 Platforms > Android > Extra Tags for <application> nodetools:remove="android:dataExtractionRules"를 추가 해주세요.

아래 가이드를 함께 참고해 주세요.

문제 현상

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

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

발생 원인

에어브릿지 SDK 백업 규칙과 서드파티 SDK 백업 규칙 중복 적용으로 인해 빌드 에러가 발생할 수 있습니다.

해결 방법

backup_rules.xml 설정

  1. 모듈 디렉터리 내부에 (e.g. custom_backup_rules.xml) 파일을 생성해주세요.

  2. 에어브릿지 SDK에서 정의하는 데이터 백업 규칙을 다음과 같이 추가해 주세요.

    12345678910111213141516
    <?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>
  3. 언리얼 플러그인 언어(Unreal Plugin Language,UPL)를 이용하여 res/xml 폴더에 해당 파일을 다음과 같이 복사해 주세요.

    123456789
    <?xml version="1.0" encoding="utf-8"?>
    <root xmlns:android="http://schemas.android.com/apk/res/android">
        ...
        <resourceCopies>
            <copyFile src="{YOUR_XML_BACKUP_RULES_PATH}" dst="$S(BuildDir)/res/xml/custom_backup_rules.xml" />
            ...
        </resourceCopies>
        ...
    </root>

data_extraction_rules.xml 설정

  1. 모듈 디렉터리 내부에 (e.g. custom_data_extraction_rule.xml) 파일을 생성해주세요.

  2. 에어브릿지 SDK에서 정의하는 데이터 백업 규칙을 다음과 같이 추가해 주세요.

    123456789101112131415161718192021222324252627282930313233
    <?xml version="1.0" encoding="utf-8"?>
    <data-extraction-rules>
        <cloud-backup>
            <!-- 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 -->
        </cloud-backup>
        <device-transfer>
            <!-- 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 -->
        </device-transfer>
    </data-extraction-rules>
  3. 언리얼 플러그인 언어(Unreal Plugin Language,UPL)를 이용하여 res/xml 폴더에 해당 파일을 다음과 같이 복사해 주세요.

    123456789
    <?xml version="1.0" encoding="utf-8"?>
    <root xmlns:android="http://schemas.android.com/apk/res/android">
        ...
        <resourceCopies>
            <copyFile src="{YOUR_XML_BACKUP_RULES_PATH}" dst="$S(BuildDir)/res/xml/custom_data_extraction_rule.xml" />
            ...
        </resourceCopies>
        ...
    </root>

AndroidManifest.xml 설정

언리얼 에디터 Project Settings 창의 Platforms - Android > Advanced APK Packaging > Extra Tags for <manifest> node 에 아래에 해당하는 요소들을 추가해 주세요.

  • xmlns:tools="http://schemas.android.com/tools"

언리얼 에디터 Project Settings 창의 Platforms - Android > Advanced APK Packaging > Extra Tags for <application> node 에 아래에 해당하는 요소들을 추가해 주세요.

  • android:allowBackup="true"

  • android:fullBackupContent="@xml/custom_backup_rules"

  • android:dataExtractionRules="@xml/custom_data_extraction_rules"

  • tools:replace="android:fullBackupContent, android:dataExtractionRules"

아래 가이드를 함께 참고해 주세요.

발생 현상

LAT(LimitAdTracking)를 비활성화한 상태에서 정상적으로 수집되어야 하는 GAID가 00000000-0000-0000-0000-000000000000으로 수집됩니다.

발생 원인

다른 서드파티 라이브러리 등으로 인해 AD_ID 권한이 제외되었습니다.

해결 방법

AD_ID 권한을 추가합니다.

12345
<manifest ...>
  ...
  <uses-permission android:name="com.google.android.gms.permission.AD_ID" />
  ...
</manifest>

문제 현상

Google Play Console에 앱을 업로드할 때 다음과 같은 경고 또는 거부 메시지를 받을 수 있습니다:

  • "Your app doesn't support 16 KB page size"

  • "16 KB page size compatibility required"

  • 앱 업로드가 거부되거나 경고 상태로 표시됩니다

이는 Android 15(API 수준 35) 이상을 타겟팅하는 앱이 16KB 페이지 크기를 지원해야 한다는 Google Play 정책 요구사항 때문입니다.

발생 원인

Airbridge SDK는 다음 버전부터 16KB 페이지 크기를 지원합니다:

Platform

SDK v4

SDK (previous)

Android

v4.6

v2.28.0

React Native

v4.6

v2.10.0

Cordova Ionic

v4.6

v2.7.0

Flutter

v4.6

x(지원 불가)

Expo

v4.6

v2.10.0

Unity

v4.6

v1.17.0

Unreal

v4.6

v1.4.0

하지만 SDK만 16KB를 지원한다고 해서 충분하지 않습니다. 앱 전체(APK/AAB)가 16KB zipalign으로 패키징되어야 Google Play 정책을 통과합니다.

APK/AAB가 16KB zipalign으로 빌드되지 않으면:

  • Google Play Console 업로드 시 경고 또는 거부 메시지를 받습니다

  • 2025년 11월 1일 이후에는 업로드가 완전히 차단됩니다

  • 16KB 페이지 크기 기기에서 향후 정상 작동하지 않을 수 있습니다

해결 방법

Step 1: Airbridge SDK 버전 확인

먼저 Airbridge SDK가 16KB를 지원하는 버전인지 확인하세요. 이전 버전을 사용 중이라면 반드시 최신 버전으로 업데이트해 주세요.

Step 2: Android Gradle Plugin(AGP) 버전 확인 및 설정

현재 프로젝트의 AGP 버전을 확인하세요.

AGP 8.5.1 이상을 사용하는 경우:

  • 별도의 추가 설정 없이 자동으로 16KB zipalign이 적용됩니다.

  • Step 3으로 바로 이동하세요.

AGP 8.5.0 이하를 사용하는 경우:

  • 옵션 A: AGP를 8.5.1 이상으로 업그레이드

  • 옵션 B: 현재 AGP 버전 유지 + 설정 추가

    12345678
    android {
        ...
        packagingOptions {
            jniLibs {
                useLegacyPackaging true
            }
        }
    }

Step 3: 앱 다시 빌드 및 확인

설정을 변경한 후 앱을 클린 빌드하세요.

Step 4: 16KB zipalign 적용 확인

빌드된 APK/AAB가 올바르게 16KB zipalign되었는지 확인하세요.

도움이 되었나요?

더 필요한 내용이 있나요?