APK(Android Package Kit, 또는 Android Application Package)는 안드로이드 (운영체제) 위에서 앱을 배포하고 설치하는 데 쓰이는 파일 형식이다.[1] ZIP 아카이브 구조를 기반으로 하며, 앱 실행에 필요한 컴파일된 코드, 리소스, 매니페스트, 서명 정보를 하나의 파일에 담는다. 사용자가 기기에 앱을 설치할 때 실제로 기기에 전달되는 것이 APK이며, 이 파일 하나로 설치가 완결된다는 점에서 배포 중간 형식인 Android App Bundle과 구별된다.[6]

1. 파일 구조

APK는 .apk 확장자를 붙인 ZIP 아카이브다.[1] 더 정확하게는 JAR(Java Archive) 형식을 확장한 것이며, DEFLATE 압축을 기본으로 사용한다. 압축을 풀면 다음 구성 요소들이 나온다.

  • AndroidManifest.xml: 앱 이름, 버전, 선언된 권한, 컴포넌트(액티비티·서비스·브로드캐스트 리시버·콘텐트 프로바이더) 목록을 담은 메타데이터 파일. 설치 시스템이 가장 먼저 읽는 파일이다.
  • classes.dex: Java 또는 Kotlin 소스를 컴파일한 뒤 Dex(Dalvik Executable) 형식으로 변환한 바이트코드 파일. 앱 규모가 크면 classes2.dex, classes3.dex 등 여러 개로 분리된다. ART가 이 파일을 실행하거나 AOT 컴파일한다.[7]
  • resources.arsc: 문자열, 스타일, 레이아웃 참조 같은 컴파일된 리소스를 담는 바이너리 파일.
  • res/: 컴파일되지 않은 리소스(이미지, 레이아웃 XML 등)를 담는 디렉터리.
  • assets/: 폰트·미디어·데이터 파일처럼 앱이 AssetManager로 직접 읽는 원본 에셋 디렉터리.
  • META-INF/: APK 서명에 쓰이는 인증서(CERT.RSA), 서명 매니페스트(CERT.SF), 파일 해시 목록(MANIFEST.MF)을 담는 디렉터리.
  • lib/: 네이티브 라이브러리 (Android) .so 파일을 CPU 아키텍처별 하위 디렉터리(armeabi-v7a, arm64-v8a, x86_64 등)로 구분해 담는 공간.[7]

2. 서명 스킴의 진화

Android는 앱 설치 시 서명 검증을 통해 배포자 신원과 파일 무결성을 확인한다. 서명 스킴은 Android 버전과 함께 네 단계에 걸쳐 발전했다.[2][3][4]

v1 (JAR 서명): Android 초기부터 사용된 방식으로, Java의 표준 JAR 서명 메커니즘을 그대로 차용한다.[2] META-INF/ 내 파일 해시와 인증서로 검증하지만, ZIP 메타데이터 영역은 보호 범위에 포함되지 않아 해당 영역을 수정해도 서명이 통과될 수 있다는 한계가 있다.

v2 (Android 7.0, 2016년): APK 파일 전체를 단일 블롭으로 간주하고 해시·서명한 뒤 결과를 APK 내 별도 블록에 삽입하는 방식이다.[2] ZIP 메타데이터를 포함해 파일 어느 부분이든 수정되면 검증이 실패한다.

v3 (Android 9, 2018년): v2 구조를 유지하면서 키 교체(key rotation) 기능을 추가했다.[3] 서명 블록에 이전 키와 새 키 사이의 신뢰 체인을 포함시켜, 같은 앱이 서명 키를 교체한 업데이트를 배포할 수 있게 됐다.

v4 (Android 11, 2020년): APK 전체 바이트에 대한 Merkle 해시 트리를 계산하고 서명을 별도 .apk.idsig 파일에 저장하는 스트리밍 호환 방식이다.[4] v2 또는 v3 서명을 보완하는 형태로 동작하며, 증분 설치(incremental install)를 지원한다.

3. 설치 과정

APK 설치는 안드로이드 (운영체제)PackageInstaller API와 PackageManagerService가 담당한다.[5] 설치 흐름은 크게 세 단계로 나뉜다.

첫 번째로 시스템은 APK의 서명을 검증한다. AndroidManifest.xml을 파싱해 패키지 이름과 버전을 확인하고, META-INF/의 인증서와 해시 값을 대조한다. 이미 같은 패키지가 설치되어 있다면 새 APK의 서명 키가 기존과 일치하는지도 확인하며, 키가 다르면 업데이트가 거부된다.

두 번째로 권한을 처리한다. AndroidManifest.xml에 선언된 권한 중 일반(normal) 권한은 자동으로 부여되고, 위험(dangerous) 권한은 런타임에 사용자 동의를 요청한다.

세 번째로 ART.dex 파일을 기기에 최적화된 형태로 컴파일하거나 인터프리트할 준비를 한다. 설치 완료 후 앱은 Application Sandbox 원칙에 따라 고유 UID와 격리된 프로세스 공간을 할당받는다.

4. 사이드로딩과 보안

사이드로딩(sideloading)은 Google Play 같은 공식 앱 스토어를 거치지 않고 APK 파일을 직접 설치하는 방식이다.[6] Android는 이를 기술적으로 허용하지만, 허가 방식은 버전에 따라 달라졌다.

Android 8.0(2017년)부터는 글로벌 스위치가 제거되고, 특정 앱에 한해 설치 권한을 개별적으로 부여하는 per-app 방식으로 변경됐다.[6] 앱이 다른 APK를 설치하려면 REQUEST_INSTALL_PACKAGES 권한을 선언해야 하며, Google Play는 이 권한을 고위험 권한으로 분류해 심사 대상으로 관리한다.

5. AAB와의 관계

Android App Bundle(AAB)은 APK를 대체하는 배포 형식이 아니라, APK 생성 전 단계의 중간 형식이다.[6] 개발자가 AAB를 Google Play에 업로드하면 Play 인프라가 각 기기의 CPU 아키텍처, 화면 밀도, 언어 설정에 맞는 APK 세트를 생성해 전달한다. 2021년 8월부터 Google Play에 새로 제출하는 앱은 AAB 형식을 사용해야 하지만, 이미 유통 중인 APK나 Play 이외 경로 배포에는 이 요건이 적용되지 않는다.

6. 관련 문서

7. 인용 및 각주

[1] App signing — Android Open Source Project. Ssource.android.com(새 탭에서 열림)

[2] APK signature scheme v2 — Android Open Source Project. Ssource.android.com(새 탭에서 열림)

[3] APK signature scheme v3 — Android Open Source Project. Ssource.android.com(새 탭에서 열림)

[4] App signing — Android Open Source Project (v4 scheme). Ssource.android.com(새 탭에서 열림)

[5] Sign your app — Android Developers. Ddeveloper.android.com(새 탭에서 열림)

[6] Android App Bundle frequently asked questions — Android Developers. Ddeveloper.android.com(새 탭에서 열림)

[7] Structure of an Android App Binary (.apk) — Appdome. Wwww.appdome.com(새 탭에서 열림)