64비트 아키텍처 지원

2019년 8월 1일부터 Google Play에 게시되는 앱에서는 64비트 아키텍처를 지원해야 합니다. 64비트 CPU는 사용자에게 더 빠르고 풍부한 환경을 제공합니다. 앱의 64비트 버전을 추가하면 성능이 향상되고 향후 혁신을 이룰 가능성이 높아지며 64비트 전용 하드웨어가 장착된 기기에 대응할 수 있습니다.

이 가이드에서는 32비트 앱에서 64비트 기기를 지원할 준비가 되었는지 확인하기 위해 현재 취할 수 있는 단계를 설명합니다.

앱 액세스

앱에서 모든 라이브러리나 SDK를 포함하여 자바 프로그래밍 언어나 Kotlin으로 작성된 코드만 사용한다면 이미 64비트 기기를 사용할 준비가 된 것입니다. 앱에서 네이티브 코드를 사용하거나 사용 여부를 잘 모르는 경우, 앱을 분석하고 조치를 취해야 합니다.

빠른 상태 확인

앱이 64비트 요구사항을 충족할 준비가 되었는지 확인하는 빠른 방법은 Play Console로 이동하여 기존 출시를 살펴보고 호환되는지 확인하는 것입니다.

Play Console에서는 64비트 요구사항과 관련된 문제가 있다면 임시 버전에 적용되는 경고도 표시합니다. 다음 예를 참조하세요.

알림이 표시되면 다음 단계에 따라 앱을 준비합니다.

앱에서 네이티브 코드를 사용하는지 확인

첫 번째 할 일은 앱에서 네이티브 코드를 사용하는지 확인하는 것입니다. 다음과 같은 경우 앱에서 네이티브 코드를 이용하는 것입니다.

  • 앱에서 C/C++(네이티브) 코드를 사용합니다.
  • 타사 네이티브 라이브러리와 연결됩니다.
  • 네이티브 라이브러리를 사용하는 타사 앱 빌더로 빌드했습니다.

앱에 64비트 라이브러리가 포함되어 있는지 확인

64비트 라이브러리가 있는지 확인하는 가장 간단한 방법은 APK 파일의 구조를 검사하는 것입니다. APK는 빌드될 때 앱에 필요한 네이티브 라이브러리와 함께 패키징됩니다. 네이티브 라이브러리는 ABI에 따라 다양한 폴더에 저장됩니다. 모든 64비트 아키텍처를 지원할 필요는 없지만, 지원하는 각 네이티브 32비트 아키텍처에 해당하는 64비트 아키텍처를 포함해야 합니다.

ARM 아키텍처의 경우 32비트 라이브러리는 armeabi-v7a에 있으며 이때 64비트에 해당하는 라이브러리는 arm64-v8a입니다.

x86 아키텍처의 경우 32비트용 x86과 64비트용 x86_64를 찾아보세요.

가장 먼저 해야 할 일은 이러한 두 폴더에 네이티브 라이브러리가 있는지 확인하는 것입니다. 요약하면 다음과 같습니다.

플랫폼 32비트 라이브러리 폴더 64비트 라이브러리 폴더
ARM lib/armeabi-v7a lib/arm64-v8a
x86 lib/x86 lib/x86_64

앱에 따라 각 폴더에 정확히 동일한 라이브러리 집합이 있을 수도 있고 그렇지 않을 수도 있습니다. 앱이 64비트 전용 환경에서 정상적으로 실행되게 하는 것이 목표입니다.

일반적인 경우 32비트와 64비트 아키텍처에 모두 사용할 수 있도록 빌드된 APK나 번들에는 두 ABI용 폴더가 있으며, 각 폴더에는 해당하는 네이티브 라이브러리 집합이 있습니다. 64비트를 지원하지 않는 경우 32비트 ABI 폴더는 있지만 64비트 폴더는 없을 가능성이 있습니다.

APK Analyzer로 네이티브 라이브러리 찾기

APK Analyzer는 빌드된 APK의 다양한 측면을 평가할 수 있는 도구입니다. 여기에서는 APK Analyzer를 사용해 모든 네이티브 라이브러리를 찾아보고 64비트 라이브러리가 있는지 확인해 보겠습니다.

  1. Android 스튜디오를 열고 프로젝트를 엽니다.
  2. 메뉴에서 Build > Analyze APK…를 선택합니다.

    APK Analyzer 시작

  3. 평가하려는 APK를 선택합니다.

  4. '.so' 파일이 있는 lib 폴더 내부를 살펴봅니다. 앱에서 '.so' 파일을 전혀 찾을 수 없다면 앱이 이미 준비된 것이므로 더 이상 조치를 취할 필요가 없습니다. armeabi-v7a 또는 x86이 표시되는 경우 32비트 라이브러리가 있는 것입니다.

  5. arm64-v8a 또는 x86_64 폴더에 유사한 '.so' 파일이 있는지 확인합니다.

    APK Analyzer 시작

  6. arm64-v8a 또는 x86_64 라이브러리가 없는 경우 빌드 프로세스를 업데이트하여 APK에 이러한 아티팩트를 빌드하고 패키징하기 시작해야 합니다.

  7. 두 라이브러리가 패키징된 것을 이미 확인했다면 64비트 하드웨어에서 앱 테스트로 건너뛰어도 됩니다.

APK의 압축을 풀어 네이티브 라이브러리 찾기

APK 파일의 구조는 zip 파일과 같아서 압축을 풀 수도 있습니다. 명령줄이나 다른 추출 도구를 사용하고 싶다면 APK 압축을 푸는 것이 좋습니다.

위 안내에 따라 APK 파일의 압축을 풀고(추출 도구에 따라 파일 이름을 .zip으로 바꿔야 할 수 있음) 추출된 파일을 살펴보면 64비트 기기를 사용할 준비가 되었는지 확인할 수 있습니다.

예를 들어 명령줄에서 다음 명령어를 실행할 수 있습니다.

:: Command Line
> zipinfo -1 YOUR_APK_FILE.apk | grep \.so$
lib/armeabi-v7a/libmain.so
lib/armeabi-v7a/libmono.so
lib/armeabi-v7a/libunity.so
lib/arm64-v8a/libmain.so
lib/arm64-v8a/libmono.so
lib/arm64-v8a/libunity.so

이 예에서는 armeabi-v7aarm64-v8a 라이브러리가 있으며, 이는 앱에서 64비트 아키텍처를 지원한다는 의미입니다.

64비트 라이브러리로 앱 빌드

다음은 64비트 라이브러리를 빌드하기 위한 안내입니다. 단, 여기에서는 소스 단계부터 빌드할 수 있는 코드와 라이브러리를 빌드하는 방법만 다룹니다.

외부 SDK나 라이브러리를 사용하는 경우 위 단계에 따라 64비트 버전을 사용 중인지 확인하세요. 64비트 버전을 사용할 수 없는 경우 SDK나 라이브러리 소유자에게 문의하고, 64비트 기기 지원을 계획할 때 이 점을 고려하시기 바랍니다.

Android 스튜디오 또는 Gradle로 빌드

대부분의 Android 스튜디오 프로젝트는 기본 빌드 시스템으로 Gradle을 사용하기 때문에 이 섹션은 두 경우 모두에 적용됩니다. 네이티브 코드에 맞게 빌드를 사용 설정하려면 지원하려는 아키텍처에 따라 앱의 'build.gradle' 파일에서 다음과 같이 ndk.abiFilters 설정에 arm64-v8a 또는 x86_64를 추가하기만 하면 됩니다.

Groovy

// Your app's build.gradle
plugins {
  id 'com.android.app'
}

android {
   compileSdkVersion 27
   defaultConfig {
       appId "com.google.example.64bit"
       minSdkVersion 15
       targetSdkVersion 28
       versionCode 1
       versionName "1.0"
       ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
// ...

Kotlin

// Your app's build.gradle
plugins {
    id("com.android.app")
}

android {
    compileSdkVersion(27)
    defaultConfig {
        appId = "com.google.example.64bit"
        minSdkVersion(15)
        targetSdkVersion(28)
        versionCode = 1
        versionName = "1.0"
        ndk {
            abiFilters += listOf("armeabi-v7a","arm64-v8a","x86","x86_64")
        }
// ...

CMake로 빌드

CMake를 사용해 앱을 빌드하는 경우 다음과 같이 '-DANDROID_ABI' 매개변수에 arm64-v8a를 전달하여 64비트 ABI용으로 빌드할 수 있습니다.

:: Command Line
> cmake -DANDROID_ABI=arm64-v8a … or
> cmake -DANDROID_ABI=x86_64 …

externalNativeBuild를 사용하는 경우에는 이 옵션이 효과가 없습니다. Gradle로 빌드 섹션을 참조하세요.

ndk-build로 빌드

ndk-build로 앱을 빌드하는 경우 다음과 같이 APP_ABI 변수를 사용해 'Application.mk' 파일을 수정하여 64비트 ABI용으로 빌드할 수 있습니다.

APP_ABI := armeabi-v7a arm64-v8a x86 x86_64

externalNativeBuild를 사용하는 경우에는 이 옵션이 효과가 없습니다. Gradle로 빌드 섹션을 참조하세요.

32비트 코드를 64비트로 포팅

코드가 이미 데스크톱 또는 iOS에서 실행된다면 Android를 위해 추가 작업을 할 필요가 없습니다. 64비트 시스템용으로 빌드된 첫 코드라면 해결해야 할 주요 문제는 포인터가 더 이상 32비트 정수 유형(예: int)에 적합하지 않다는 것입니다. 유형이 int, unsigned, uint32_t 등인 포인터를 저장하는 코드를 업데이트해야 합니다. Unix 시스템에서는 long이 포인터 크기와 일치하지만 Windows에서는 그렇지 않으므로 인텐트 표시 유형 uintptr_t 또는 intptr_t를 대신 사용해야 합니다. ptrdiff_t 유형을 사용하여 두 포인터 사이의 차이점을 저장하세요.

포인터가 아닌 경우에도 int 또는 long과 같은 기존 유형이 아닌 <stdint.h>에서 정의된 특정 고정 너비의 정수 유형을 항상 사용해야 합니다.

다음 컴파일러 플래그를 사용하여 코드가 포인터와 정수 사이에서 잘못 변환되는 경우를 포착하세요.

-Werror=pointer-to-int-cast
-Werror=int-to-pointer-cast
-Werror=shorten-64-to-32

C/C++ 객체 포인터를 보유하는 int 필드가 있는 자바 클래스에도 동일한 문제가 있습니다. JNI 소스에서 jint를 검색하여 자바 측면에서는 long, C++ 측면에서는 jlong으로 전환하도록 합니다.

암시적 함수 선언은 64비트 코드에 훨씬 더 위험합니다. C/C++에서는 암시적으로 선언된 함수(즉, 컴파일러가 선언을 확인하지 못한 함수)의 반환 유형을 int라고 가정합니다. 함수의 실제 반환 유형이 포인터인 경우 포인터가 int에 적합한 32비트 시스템에서는 제대로 작동하지만 64비트 시스템에서는 컴파일러가 포인터의 상위 절반을 무시합니다. 예:

// This function returns a pointer:
// extern char* foo();

// If you don't include a header that declares it,
// when the compiler sees this:
char* result = foo();

// Instead of compiling that to:
result = foo();

// It compiles to something equivalent to:
result = foo() & 0xffffffff;

// Which will then cause a SIGSEGV if you try to dereference `result`.

다음 컴파일러 플래그는 암시적 함수 선언 경고를 오류로 전환하여 이 문제를 더 쉽게 찾아서 해결할 수 있도록 합니다.

-Werror=implicit-function-declaration

인라인 어셈블러가 있다면 다시 작성하거나 일반 C/C++ 구현을 사용해야 합니다.

하드 코딩된 크기의 유형(예: 8 또는 16바이트)이 있으면 sizeof(void*)와 같은 동등한 sizeof(T) 표현식으로 교체합니다.

64비트가 아닌 32비트에서 다른 코드를 조건부로 컴파일해야 한다면 일반적인 32/64 차이에는 #if defined(__LP64__) 또는 __arm__, __aarch64__(arm64), __i386__(x86)을, Android에서 지원하는 특정 아키텍처에는 __x86_64__를 사용할 수 있습니다.

printf 또는 scanf와 같은 함수의 형식 문자열을 조정해야 하는데 이는 기존 형식 지정자가 32비트 기기와 64비트 기기 모두에 올바른 방식으로 64비트 유형을 지정하도록 허용하지 않기 때문입니다. <inttypes.h>PRISCN 매크로가 이 문제를 해결하며, PRIxPTRSCNxPTR은 16진수 포인터의 읽기/쓰기, PRId64SCNd64는 64비트 값 읽기/쓰기를 위한 것입니다.

시프팅할 때 32비트일 뿐인 1을 사용하는 대신 1ULL을 사용하여 시프팅할 64비트 상수를 얻어야 할 수 있습니다.

Android App Bundle로 크기 증가 완화

앱에 64비트 아키텍처 지원을 추가하면 APK 크기가 커질 수 있습니다. 이 경우 동일한 APK에 32비트와 64비트 네이티브 코드를 포함하여 발생하는 크기의 영향을 최소화하려면 Android App Bundle 기능을 활용하는 것이 좋습니다.

Android App Bundle을 사용하도록 앱을 전환하면 실제로 APK 크기가 개선되어 현재 크기보다 작아질 수 있습니다.

게임 개발자

타사 게임 엔진을 이전하는 작업은 리드 타임이 오래 걸리는 집약적인 프로세스입니다. 다행히 가장 많이 사용되는 다음 세 가지 엔진은 현재 모두 64비트를 지원합니다.

  • Unreal(2015년 이후)
  • Cocos2d(2015년 이후)
  • Unity(2018년 이후)

Unity 개발자

가능한 버전으로 업그레이드

Unity에서는 2018.22017.4.16 버전에서 64비트 지원을 제공하기 시작했습니다.

64비트를 지원하지 않는 Unity 버전을 사용하고 있다면 업그레이드하려는 버전을 확인한 후 Unity에서 제공하는 가이드에 따라 환경을 이전하여 64비트 라이브러리를 빌드할 수 있는 버전으로 앱을 업그레이드해야 합니다. Unity에서는 편집기의 최신 LTS 버전으로 업그레이드하여 최신 기능과 업데이트를 이용할 것을 권장합니다.

다음은 다양한 Unity 버전과 해야 할 작업을 요약한 차트입니다.

Unity 버전 버전의 64비트 지원 여부 권장 조치

2020.x

✔️

빌드 설정에서 64비트 라이브러리를 출력하는지 확인합니다.

2019.x

✔️

빌드 설정에서 64비트 라이브러리를 출력하는지 확인합니다.

2018.4(LTS)

✔️

빌드 설정에서 64비트 라이브러리를 출력하는지 확인합니다.

2018.3

✔️

빌드 설정에서 64비트 라이브러리를 출력하는지 확인합니다.

2018.2

✔️

빌드 설정에서 64비트 라이브러리를 출력하는지 확인합니다.

2018.1

실험적인 64비트 지원 기능이 포함되어 있습니다.

2017.4(LTS)

✔️

2017.4.16 버전부터 지원됩니다. 빌드 설정에서 64비트 라이브러리를 출력하는지 확인합니다.

2017.3

✖️

64비트를 지원하는 버전으로 업그레이드합니다.

2017.2

✖️

64비트를 지원하는 버전으로 업그레이드합니다.

2017.1

✖️

64비트를 지원하는 버전으로 업그레이드합니다.

5.6 이하

✖️

64비트를 지원하는 버전으로 업그레이드합니다.

64비트 라이브러리 출력을 위한 빌드 설정 변경

64비트 Android 라이브러리를 지원하는 Unity 버전을 사용하는 경우 빌드 설정을 조정하여 64비트 버전의 앱을 생성할 수 있습니다. 또한 IL2CPP 백엔드를 스크립팅 백엔드로 사용해야 합니다(자세한 내용은 여기 참조). 64비트 아키텍처를 빌드하도록 Unity 프로젝트를 설정하려면 다음 단계를 따르세요.

  1. Build Settings(빌드 설정)에서 플랫폼Android 옆에 Unity 기호가 있는지 확인하여 Android용으로 빌드하고 있는지 확인합니다.
    1. Android 플랫폼 옆에 Unity 기호가 없으면 Android를 선택한 다음 Switch Platform(플랫폼 전환)을 클릭합니다.
  2. Player Settings(플레이어 설정)를 클릭합니다.

    Unity의 플레이어 설정

  3. Player Settings Panel(플레이어 설정 패널) > Settings for Android(Android용 설정) > Other settings(기타 설정) > Configuration(구성)으로 이동합니다.

  4. Scripting Backend(스크립팅 백엔드)IL2CPP로 설정합니다.

  5. Target Architecture(대상 아키텍처) > ARM64 체크박스를 선택합니다.

    Unity에서 대상 아키텍처 설정

  6. 평소대로 빌드합니다.

ARM64용으로 빌드하려면 모든 애셋을 이 플랫폼용으로 특별히 빌드해야 합니다. APK 크기 축소와 관련한 Unity의 안내를 따르고 Android App Bundle 기능을 활용하여 크기 증가를 완화해 보세요.

다중 APK 및 64비트 규정 준수

Google Play의 다중 APK 지원을 사용하여 앱을 게시하고 있다면 출시 레벨에서 64비트 요구사항이 준수되는지 평가합니다. 그러나 64비트 요구사항은 Android 9 Pie 이상을 실행하는 기기에 배포되지 않은 APK나 App Bundle에는 적용되지 않습니다.

APK 중 하나가 준수되지 않는 것으로 표시되었지만 오래되어 준수할 수 없는 경우 한 가지 전략은 APK 매니페스트의 uses-sdk 요소에 maxSdkVersion="27" 속성을 추가하는 것입니다. 이 APK는 Android 9 Pie 이상을 실행하는 기기에는 전송되지 않으며 더 이상 규정 준수를 차단하지 않습니다.

RenderScript 및 64비트 규정 준수

RenderScript를 사용하는 앱이 이전 버전의 Android 도구로 빌드된 경우 앱에 64비트 규정 준수 문제가 발생할 수 있습니다. 21.0.0 이전의 빌드 도구를 사용하면 컴파일러에서 외부 .bc 파일에 비트코드를 생성할 수 있습니다. 이러한 기존 .bc 파일은 64비트 아키텍처에서 더 이상 지원되지 않으므로 APK에 파일이 있으면 규정 준수 문제가 발생합니다.

문제를 해결하려면 프로젝트에서 .bc 파일을 모두 삭제하고 환경을 build-tools-21.0.0 이상으로 업그레이드한 다음 Android 스튜디오의 renderscriptTargetApi를 21+로 설정하여 컴파일러에서 .bc 파일을 내보내지 않도록 지시합니다. 그런 다음 앱을 다시 빌드하고 .bc 파일을 검사한 후 Play Console에 업로드하세요.

64비트 하드웨어에서 앱 테스트

64비트 버전의 앱은 32비트 버전의 앱과 동일한 품질과 기능을 제공해야 합니다. 앱을 테스트하여 최신 64비트 기기 사용자가 앱에서 뛰어난 환경을 이용할 수 있는지 확인하세요.

앱 테스트를 시작하려면 64비트 지원 기기가 있어야 합니다. Google Pixel 및 기타 플래그십 기기와 같이 많이 사용되는 다양한 기기에서 64비트가 지원됩니다.

APK를 테스트하는 가장 쉬운 방법은 adb를 사용해 앱을 설치하는 것입니다. 대부분의 경우 --abi를 매개변수로 제공하여 기기에 설치할 라이브러리를 지정할 수 있습니다. 그러면 64비트 라이브러리만 포함된 앱이 기기에 설치됩니다.

:: Command Line
# A successful install:
> adb install --abi armeabi-v7a YOUR_APK_FILE.apk
Success

# If your APK does not have the 64-bit libraries:
> adb install --abi arm64-v8a YOUR_APK_FILE.apk
adb: failed to install YOUR_APK_FILE.apk: Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]

# If your device does not support 64-bit, an emulator, for example:
> adb install --abi arm64-v8a YOUR_APK_FILE.apk
ABI arm64-v8a not supported on this device

설치가 완료되면 평소대로 앱을 테스트하여 32비트 버전과 품질이 같은지 확인하세요.

게시

앱이 준비가 되었다고 생각되면 평소대로 게시하고, 늘 그렇듯 앱 배포 권장사항을 계속 따릅니다. 앱의 품질을 일관되게 유지하려면 비공개 테스트 트랙을 활용하여 한정된 수의 사용자를 대상으로 출시하는 것이 좋습니다.

주요 업데이트를 배포할 때는 64비트 지원 기기에서 철저하게 테스트한 후에 대규모 사용자층을 대상으로 게시해야 합니다.