(원문: http://developer.android.com/guide/practices/compatibility.html)

(위치: Develop > API Guides > Device Compatibility)

(전체 번역 글 목록으로 이동하기)


기기 호환성   


안드로이드는 다양한 종류의 디바이스에서 구동될 수 있도록 디자인 되었습니다 (폰, 태블릿, 텔레비전 등). 내 앱이 다양한 종류의 디바이스에서 실행될 수 있다면 그만큼 더 많은 잠재적 고객을 실제 고객으로 유도할 수 있을 것입니다. 이렇게 다양한 디바이스에서 성공적으로 실행되려면, 일부 기능들은 제한될 수 있고 다양한 환경들에 맞게 사용자 인터페이스도 융통성이 있어야 합니다.

그러기 위하여 안드로이드는, 다양한 환경에서 각 환경에 적합한 앱 리소스를 제공할 수 있는 프레임웍을 제공합니다 (예를 들어, 각기 다른 스크린 사이즈에 대하여 각각에 맞는 레이아웃 xml파일을 제공하도록 할 수 있습니다). 앱 프로젝트에서 각 환경에 맞게 리소스들을 잘 배치했다면, 런타임에 안드로이드가 디바이스의 현재 환경을 확인하여 그 환경에 맞는 리소스를 로드합니다. 따라서, 다양한 환경에 대한 리소스들을 미리 잘 준비한다면 하나의 APK파일로 그러한 환경들에 최적화시켜 출시할 수 있습니다.

그러나 필요에 따라서는 앱이 필요로 하는 기능을 명시하여, 구글플레이를 통해 설치할 수 있는 디바이스 종류를 제한할 수 있습니다. 여기서는 내 앱을 설치할 수 있는 디바이스의 종류를 어떻게 조정할 수 있는지와, 타겟 사용자들이 내 앱을 잘 이용할 수 있도록 무엇을 준비해야 하는지에 대해서 설명하도록 하겠습니다. 다양한 디바이스에서 잘 동작하는 앱을 만들기 위한 자세한 내용은 다양한 디바이스 지원하기에서 학습하실 수 있습니다.


"호환성(Compatibility)"이란?


안드로이드 개발과 관련하여 학습을 하고 계시다면, "호환성"이라는 단어를 많이 접하셨을 것입니다. 호환성은 크게 기기 호환성과 앱 호환성으로 나뉩니다.

안드로이드는 오픈 소스 프로젝트이기 때문에 하드웨어 제조업체들이 안드로이드 OS를 탑재한 디바이스를 만들 수 있습니다. 안드로이드 실행환경 (Android execution environment)에서 실행되도록 만들어진 앱을 디바이스에서 실행시킬 수 있다면, 그 디바이스는 "안드로이드와 호환된다"라고 표현합니다. 안드로이드 실행환경은 안드로이드 호환성 프로그램(Android compatibility program)에서 구체적으로 정의되어 있으며, 안드로이드와 호환되고자 하는 모든 디바이스는 호환성 테스트 수트(Compatibility Test Suite, CTS)를 통과해야 합니다.

앱 개발자들은 어떤 디바이스가 안드로이드와 호환되고 호환되지 않는지에 대하여 고민할 필요가 없습니다. 왜냐하면 오직 안드로이드와 호환되는 디바이스에만 구글플레이 스토어가 설치되어 있기 때문입니다. 따라서 안드로이드와 호환되지 않는 디바이스에서는 앱을 설치할 수 없기 때문에 개발자는 안심해도 되는 것입니다.

그러나 앱 개발자들은 다양한 디바이스 환경에 대하여 앱이 호환되도록 노력해야 합니다. 안드로이드와 호환되는 디바이스의 종류가 상당히 많고, 그 중에서는 앱이 필요로 하는 일부 기능이 없는 디바이스도 있을 수 있기 때문입니다. 예를 들어, 내 앱의 핵심 기능이 나침반 센서를 이용하고 있다면, 내 앱은 나침반 센서를 내장하고 있는 디바이스에서만 호환되는 것입니다.


내 앱의 설치 가능성 다루기

(Controlling Your App's Availability to Devices)


안드로이드는 내 앱이 다양한 기능을 구현할 수 있도록 플랫폼 API들을 제공합니다. 어떤 기능은 나침반 센서와 같은 하드웨어 기반의 API를 사용할 것이고, 또 어떤 기능은 앱 위젯과 같은 소프트웨어 기반의 API를 사용할 것입니다. 그리고 일부 기능들은 플랫폼의 버전에 의존적일 수 있습니다. 여기서 중요한 것은, 모든 디바이스가 이러한 모든 기능들을 지원하지는 않는다는 것입니다. 따라서 내 앱이 필요로 하는 기능에 따라 어떤 종류의 디바이스에서 설치될 수 있고, 또 어떤 종류의 디바이스에서 설치될 수 없는지를 정의하는 것이 필요합니다.

개발자는 최대한의 사용자를 확보하기 위하여, APK파일이 최대한 많은 종류의 디바이스에서 실행될 수 있도록 노력해야 합니다. 대부분의 경우, 런타임때 옵셔널한 기능은 비활성화하고, 다양한 환경에 최적화된 앱 리소스를 제공하도록 합니다 (예를 들면, 각각의 스크린 사이즈에 맞는 각각의 레이아웃 제공). 하지만 구글플레이 스토어를 통한 앱의 설치 가능성을 제한해야할 필요가 있는 경우도 있습니다. 그러한 경우 아래 세가지 속성을 잘 이용해야 합니다.


디바이스 기능 (Device Features)

디바이스가 지원하는 기능들에 따라 내 앱의 설치 가능성을 관리할 수 있도록 하기 위하여, 안드로이드는 하드웨어 및 소프트웨어 기능에 기능ID (feature IDs)를 정의해 놨습니다. 예를 들면, 나침반 센서의 기능ID는 FEATURE_SENSOR_COMPASS 이고, 앱 위젯의 기능ID는 FEATURE_APP_WIDGETS 입니다 (FEATURE_SENSOR_COMPASS과 FEATURE_APP_WIDGETS는 PackageManager 클래스의 정적 멤버 변수입니다).

필요하다면 매니페스트 파일<uses-feature> 요소를 추가함으로써 해당 기능을 지원하지 않는 디바이스에 내 앱이 (구글플레이 스토어를 통해서) 설치되는 것을 방지할 수 있습니다.

예를 들어, 내 앱이 나침반 센서가 없는 디바이스에 설치되지 않기를 원한다면 매니페스트 파일에 아래와 같이 추가하면 됩니다.

<manifest ... >
   
<uses-feature android:name="android.hardware.sensor.compass"
                 
android:required="true" />
    ...
</manifest>

구글플레이 스토어는 내 앱의 매니페스트에 선언된 기능들과 사용자의 디바이스에서 지원하는 기능들을 비교하여 내 앱이 그 디바이스와 호환되는지를 판단합니다. 그래서 내 앱이 필요로 하는 기능 중에 하나라도 지원하지 않는 것이 있다면, 구글플레이 스토어는 해당 디바이스에게 내 앱을 보여주지 않습니다.

하지만 디바이스의 어떤 기능을 내 앱에서 사용하기는 하지만 그 기능이 없어도 대세에 지장을 주지는 않는다고 한다면, android:required"false"로 하여 설치 가능하게 하고, 런타임에서 그 디바이스 기능을 체크하여 그 기능만 사용하지 못하게 막으면 됩니다. 예를 들면, 아래와 같이 hasSystemFeature() 메소드를 호출하여 디바이스 기능의 가능여부를 체크할 수 있습니다.

PackageManager pm = getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) {
   
// This device does not have a compass, turn off the compass feature
    disableCompassFeature
();
}

내 앱이 구글플레이 스토어에서 타겟 사용자들을 필터링하는 방법에 대한 더 자세한 내용은 구글플레이에서의 앱 필터링에서 학습하실 수 있습니다.

  • 노트: 일부 시스템 퍼미션은 암묵적으로 디바이스의 특정 기능을 필요로 하기도 합니다. 예를 들면, 내 앱이 BLUETOOTH 퍼미션을 요청한다면 이것은 암묵적으로 디바이스 기능 중 FEATURE_BLUETOOTH를 필요로 하는 것입니다. 이러한 경우, 블루투스 기능이 없는 디바이스에서도 내 앱이 설치되도록 하려면, <uses-features>요소의 android:required 속성을 "false"로 하여 필터링을 없애면 됩니다. 이렇게 암묵적으로 디바이스 기능을 필요로 하는 경우들에 대하여 더 자세한 내용은 암묵적으로 기능을 요구하는 퍼미션들에서 학습하실 수 있습니다. 


플랫폼 버전 (Platform version)

디바이스들은 서로 다른 버전의 안드로이드 플랫폼 상에서 구동될 수 있습니다. 안드로이드 플랫폼은 기능 추가 등의 이유로 계속해서 버전 업데이트가 이뤄지고 있는데, 이러다보면 당연히 후속 버전에 추가된 API들을 이전 버전에서는 사용할 수 없는 경우가 많습니다. 그래서 API들의 셋을 구분하기 위하여 각 플랫폼은 API 레벨을 지정해 둡니다. 예를 들어, 안드로이드 버전1.0은 API 레벨 1이고 안드로이드 버전4.4는 API 레벨 19입니다.

내 앱이 실행될 수 있는 최소 버전을 지정할 때 <uses-sdk> 요소의 android:minSdkVersion 속성에 API 레벨값을 넣어 줍니다.

예를 들어, 캘린더 프로바이더(Calendar Provider)의 API들은 안드로이드 버전 4.0 (API레벨 14)에서 추가되었는데, 만약 내 앱이 그 API들 없이는 동작하지 않는다면 minSdkVersion을 14로 설정해야 합니다.

<manifest ... >
   
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
    ...
</manifest>

minSdkVersion 속성에는 내 앱이 호환되는 최소 버전을 선언하고, targetSdkVersion 속성에는 내 앱에 최적화된 버전 중 가장 높은 것을 선언합니다.

후속 버전에서는 이전 버전에서 만들어진 앱이 호환됩니다 (하위호환). 따라서 내 앱이 API들을 매뉴얼대로 사용했다면, 안드로이드 버전이 계속 업데이트 되더라도 항상 최신 버전과 호환됩니다.

  • 노트: targetSdkVersion 속성에 버전을 설정한다고 해서 그보다 높은 버전의 플랫폼에 설치되지 않는 것은 아닙니다. 그러나, 보다 높은 버전에서 변경된 내용들에 대하여 시스템에게 인지시켜 준다는 점에서 중요합니다. 만약, 실제로는 최신 버전의 API들을 사용하여 개발을 해놓고 targetSdkVersion은 그보다 낮은 버전으로 선언해 뒀다면, 내 앱이 최신 버전에서 구동될 때 시스템은 내 앱에 대하여 하위호환이 필요하다고 판단해 버립니다. 안드로이드 버전 4.4에서 변경된 내용 중 하나를 예로 들겠습니다. 알람 매니저(AlarmManager) API에 의해 생성된 알람은 기본적으로 약간 부정확합니다. 그래서 버전 4.4인 시스템은 앱의 알람들을 일괄처리하고 시스템 전원을 절약하는데, 만약 targetSdkVersion이 19보다 더 낮게 선언되어 있으면 앱이 낮은 버전에 맞춰져 있다고 가정하여 4.4에서 개선된대로 실행하지 않고 이전처럼 실행하게 됩니다. 바꿔 말하면, 플랫폼이 업데이트 되면서 로직을 개선했더라도 이전 버전에 맞춰진 앱은 새로운 로직에 대해 문제를 일으킬 수도 있기 때문에 예전 방식으로 실행하게 되는 것입니다.

하지만, 내 앱이 안드로이드 최신 버전의 API를 사용하는데 그게 꼭 필요한 기능은 아니라고 한다면, 낮은 버전의 플랫폼에서 실행되도록 하기 위해 런타임에서 API 레벨을 체크하여 비활성화할 수 있습니다. 그리고 이러한 경우, minSdkVersion에 지원 가능한 최소 버전을 선언해 줘야 하고, 소스코드에서 Build.VERSION.SDK_INT(현재 시스템의 버전)과 Build.VERSION_CODES.XXX(비교하고자 하는 코드명)을 비교하면 됩니다. 예를 들면 아래와 같습니다.

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
   
// Running on something older than API level 11, so disable
   
// the drag/drop features that use ClipboardManager APIs
    disableDragAndDrop
();
}


스크린 형태 (Screen configuration)

안드로이드는 스마트폰, 태블릿, TV에 이르기까지 다양한 크기의 디바이스에 탑재되어 있습니다. 이렇게 다양한 스크린의 종류를 구분하기 위해, 안드로이드는 크게 두가지 특성에 따라 그룹화를 합니다. 한가지는 스크린의 (물리적인) 크기이고, 다른 한가지는 픽셀의 밀도(DPI, 1인치에 들어가 있는 픽셀수)입니다. 이러한 구분들을 단순화 및 그룹핑하여 붙여놓은 명칭들은 아래와 같습니다.

  • 스크린 크기: small, normal, large, xlarge
  • 픽셀의 밀도: mdpi (medium), hdpi (high), xhdpi (extra high), xxhdpi (extra-extra high) 등등

기본적으로, 내 앱은 특별히 신경쓰지 않아도 모든 스크린 크기와 픽셀 밀도에 호환됩니다. 그것은 시스템이 스크린 종류에 따라 UI 레이아웃과 이미지들을 적절히 조정해 주기 때문입니다. 그러나 그것이 완벽하지는 않기 때문에 최적화된 사용자 경험을 제공하기 위해서, 스크린 크기에 따라 그에 맞는 레이아웃 파일을 추가하고, 픽셀 밀도에 따라 그에 맞는 이미지들을 추가할 수 있습니다. (일반적으로, 스크린 종류 한가지를 주요 타겟으로 삼아 리소스 세트를 만들고, 부분적으로 최적화가 필요한 것들에 대하여 추가로 리소스를 추가하는 방식으로 개발을 진행합니다.)

다양한 스크린 종류에 대응하기 위해 리소스를 만드는 방법과 내 앱이 특정 스크린 크기는 지원하지 않도록 하는 방법 등은 다양한 스크린 지원하기에서 학습하실 수 있습니다.


사업적 이유에 따른 설치 가능성 다루기

(Controlling Your App's Availability for Business Reasons)


위에서는 디바이스의 종류에 따라 앱이 설치 되고 안되고 하는 내용을 설명했습니다. 하지만 사업적인 이유나 법적인 이유로 인하여 앱의 설치 가능성을 조정해야 할 필요도 있습니다. 예를 들어 런던 지하철 시간표를 보여주는 앱을 만들었다면, 이것은 영국 사람들 이외에는 별로 필요하지 않을 것입니다. 이러한 경우, 구글플레이 스토어의 개발자 콘솔에서 출시국가를 조정할 수 있습니다. 다시 말해서, 출시국가나 이동통신사와 같이 비기술적인 이유로도 앱의 설치 대상을 필터링할 수 있다는 것입니다.

기술적인 이유(디바이스가 요구하는 기능들)로 인한 필터링은 항상 APK 파일의 매니페스트 파일을 참조하고, 비기술적인 이유(출시국가 등)로 인한 필터링은 항상 구글플레이 개발자 콘솔에서 조정합니다. 


이어서 학습할 내용들:

리소스 제공하기 (Providing Resources)

앱에서 리소스가 소스코드와 어떻게 분리되어 있는지와 다양한 디바이스 환경에 최적화된 리소스를 어떻게 제공할 수 있는지에 대하여 자세히 학습합니다.

구글플레이에서의 앱 필터링 (Filters on Google Play)

구글플레이 스토어를 통해 내 앱의 설치 가능성을 조정하는 방법에 대하여 자세히 학습합니다.


추가로 학습할 내용들:

시스템 퍼미션 (System Permissions)

사용자의 동의를 필요로 하는 API들에 대하여 안드로이드가 어떻게 접근 제한을 하는지에 대해 자세히 학습합니다.


Posted by 개발자 김태우
,