(원문: 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 개발자 김태우
,

(원문: 

http://developer.android.com/guide/components/fundamentals.html)

(위치: Develop > API Guides > App Fundamentals)

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


안드로이드 앱의 기본 개념


안드로이드 앱은 자바 언어로 개발됩니다. 안드로이드 SDK가 자바 소스코드와 레이아웃 xml파일 및 이미지 등의 리소스 파일들을 APK 파일로 만들어 줍니다. APK파일은 Android package를 가리키며 확장자가 .apk 입니다. 하나의 APK파일이 하나의 앱이며, 안드로이드 디바이스에 설치되는 파일입니다.

디바이스에 앱이 설치되고 나면, 각각의 앱은 각각의 환경에서 보안이 유지된 상태로 실행됩니다.

  • 안드로이드 OS는 멀티유저 리눅스 시스템이라서, 각각의 앱은 각각 다른 유저가 됩니다.
  • 기본적으로 각각의 앱은 시스템으로부터 유니크한 리눅스 유저ID를 할당 받습니다 (리눅스 유저ID는 시스템에서 내부적으로 관리하는 값이며, 앱은 그 값을 알지 못하고 알 필요도 없습니다). 앱의 모든 파일들은 퍼미션이 설정되어 해당 유저ID를 갖는 앱 만이 접근할 수 있습니다.
  • 각 프로세스는 자신만의 가상머신(VM)을 갖기 때문에, 앱의 코드는 다른 앱들과 분리된 공간에서 실행됩니다.
  • 기본적으로 모든 앱은 각각의 리눅스 프로세스에서 실행됩니다. 안드로이드는 프로세스를 실행하여 앱의 컴포넌트를 실행하고, 프로세스가 더이상 필요 없다고 판단되거나, 프로세스가 실행 중이 아닐 때 다른 앱에서 메모리를 필요로 하면 해당 프로세스를 종료하여 메모리를 관리합니다.

위와 같이, 안드로이드 시스템은 최소 특권의 원리(principle of least privilege)에 따릅니다. 다시 말해서, 앱은 뭔가 할일이 있는 컴포넌트에게만 접근 권한을 부여하며, 이것은 권한이 없는 부분에는 접근하지 못하게 함으로써 매우 강한 보안 환경을 제공합니다.

그러나 다른 앱들과 데이터를 공유하거나, 시스템 서비스에 접근할 수 있는 방법들이 있습니다.

  • 두 개의 앱이 하나의 리눅스 유저ID를 공유하는 것이 가능합니다. 이러한 경우 두 개의 앱이 서로의 파일에 접근이 가능해집니다. 시스템 리소스를 아끼기 위해 이러한 두 개의 앱은 하나의 리눅스 프로세스에서 실행되고 하나의 가상머신을 공유합니다. (다만, 똑같이 signing되어야 합니다. 바꿔 말하면, 빌드할때 같은 sign key를 사용해야 합니다.)
  • 앱은 사용자의 주소록이나 SMS메시지, SD카드, 카메라, 블루투스 등을 사용하기 위해 접근 권한을 요청할 수 있습니다. 이런한 모든 권한은 앱을 설치하는 과정에서 사용자가 확인할 수 있으며, 해당 권한들을 사용하는 데에 동의함으로써 사용자가 직접 권한을 부여하게 됩니다.

위의 내용들은 안드로이드 앱이 시스템 내에서 어떻게 동작하는지에 대한 기본적인 내용을 설명했습니다. 아래 내용들에서 더 많은 개념들을 소개하겠습니다.

  • 앱을 개발하는데에 필요한 핵심적인 프레임웍 컴포넌트
  • 컴포넌트 및 필요한 기능들을 정의하는 manifest 파일
  • 소스코드와는 별도로 존재하는 리소스들과, 앱을 다양한 디바이스 환경에 최적화 시키는 방법들


앱의 컴포넌트 (App Components)


컴포넌트들은 안드로이드 앱의 필수적인 구성 요소입니다. 각각의 컴포넌트는 앱의 진입점이 될 수 있습니다. 모든 컴포넌트가 사용자에게 직접적인 진입점이 되는 것은 아니고 일부는 다른 컴포넌트에 의존적이기도 하지만, 각각은 독립적으로 그들만의 역할이 있는 앱의 구성원입니다.

앱의 컴포넌트에는 4가지가 있습니다. 각각은 그들만의 목적이 있고, 생성되어 소멸되기까지의 생명주기를 갖습니다.

4가지 앱 컴포넌트들은 아래와 같습니다.


액티비티 (Activities)

액티비티는 사용자 인터페이스를 제공하는 하나의 화면을 표현합니다. 예를 들어, 이메일 앱은 아직 읽지 않은 메일 목록을 보여주는 액티비티가 있을 수 있고, 이메일 내용을 보는 액티비티가 있을 수 있으며, 읽은 이메일 목록을 보여주는 액티비티가 있을 수 있습니다. 비록 이러한 액티비티들이 이메일이라는 하나의 목적을 갖고 사용자에게 하나와 같은 경험을 제공하기는 하지만, 그것들 각각은 서로 독립적으로 존재합니다. 따라서, (이메일 앱이 허용하고 있다면) 다른 앱이 이메일 앱의 액티비티들을 각각 따로 실행할 수도 있습니다. 예를 들어, 카메라 앱에서 사진을 공유하기 위해 이메일 앱의 새편지 쓰기 화면을 실행할 수 있습니다.

앱의 액티비티는 프레임웍의 Activity 클래스를 상속받아 구현할 수 있으며 자세한 내용은 Activity에 대하여에서 학습하실 수 있습니다.


서비스 (Services)

서비스는 시간이 오래 걸리는 작업이나 원격 프로세스 호출에 의한 작업을 백그라운드에서 실행할 수 있는 컴포넌트이며, 사용자 인터페이스를 제공하지 않습니다. 예를 들어, 다른 앱이 실행되는 동안에도 음악을 재생할 수 있고, 사용자가 앱에서 다른 행동을 하는 동안에 네트웍을 통해 데이터를 받아오는 일을 할 수도 있습니다. 서비스는 액티비티 및 다른 컴포넌트로부터 두 가지 방법으로 실행될 수 있습니다. 반환값이 없는 메소드 호출하듯이 그냥 호출하는 방법이 있고, 서비스를 바인드하여 객체의 메소드 호출하듯이 상호작용하는 방법이 있습니다. 

앱의 서비스는 프레임웍의 Service 클래스를 상속받아 구현할 수 있으며 자세한 내용은 Service에 대하여에서 학습하실 수 있습니다. 


컨텐트 프로바이더 (Content providers)

컨텐트 프로바이더는 앱의 데이터를 다른 앱에 공유할 수 있도록 해줍니다. 데이터는 파일 시스템 및 SQLite 데이터베이스로 저장 가능하고, 웹이나 그 외에도 앱이 접근할 수 있는 저장 공간이 있다면 저장 가능합니다. 다른 앱들은 (컨텐츠 프로바이더가 허용하고 있다면) 컨텐츠 프로바이더를 통하여 데이터를 질의하거나 수정할 수 있습니다. 예를 들어, 안드로이드 시스템은 주소록 정보를 관리하는 컨텐트 프로바이더를 제공하며, 관련 퍼미션을 갖고 있는 앱들이라면 주소록 정보를 읽거나 수정할 수 있습니다. 

컨텐트 프로바이더는 외부에 공유하지 않는 자체 데이터를 읽거나 수정하는데에도 사용할 수 있습니다. 예를 들어, Note Pad 샘플앱은 노트를 저장할 때 컨텐트 프로바이더를 사용합니다.

앱의 컨텐트 프로바이더는 프레임웍의 ContentProvider 클래스를 상속받아서 다른 앱들이 요청하는 것들에 필요한 표준화된 API들을 구현하면 됩니다. 자세한 내용은 Content Provider에 대하여에서 학습하실 수 있습니다. 


브로드캐스트 리시버 (Broadcast Receivers)

브로드캐스트 리시버는 시스템 전체에 대해 발송(broadcast)된 알림을 수신하는 컴포넌트입니다. 알림의 상당수는 시스템에서 발송되는 것들인데, 예를 들면, 화면이 꺼졌을 때나 배터리가 얼마 남지 않았을 때, 사진을 찍었을 때 관련된 알림이 발송됩니다. 앱은 어떤 데이터를 모두 다운로드 했고 사용 가능해졌다는 것을 다른 앱들에게 알리기 위해 알림을 발송할 수 있습니다. 브로드캐스트 리시버는 사용자 인터페이스가 없지만, 알림을 수신하여 노티피케이션바에 내용을 표시하는 방식으로 사용자에게 보여줄 수 있습니다. 그러나 알림을 받아서 다른 컴포넌트를 실행시켜 주는 게이트웨이의 역할을 수행하는 것이 더 일반적입니다. 

앱의 브로드캐스트 리시버는 프레임웍의 BroadcastReceiver 클래스를 상속받아서 구현할 수 있으며 Intent를 통해 데이터를 전달 받습니다. 자세한 내용은 BroadcastReceiver에 대하여에서 학습하실 수 있습니다.


안드로이드 시스템 디자인의 독특한 점 중 한가지는 어떤 앱이던 다른 앱의 컴포넌트를 실행할 수 있다는 것입니다. 예를 들어, 앱에 사진 찍는 기능이 필요하다면 사진 찍는 액티비티를 따로 구현할 필요 없이 카메라 앱의 액티비티를 실행할 수 있습니다. 이때 카메라 앱을 내 앱에 포함하거나 카메라 관련 객체를 불러다 사용할 필요가 없습니다. 대신에 단순히 카메라 앱의 사진 찍는 액티비티를 실행하면 됩니다. 그리고 사진을 찍고 나면 데이터를 리턴 받아 사용할 수 있습니다. 이것은 사용자에게 마치 카메라 앱이 내 앱의 일부인 것처럼 보이게 합니다. 

시스템은 컴포넌트를 실행할 때 (이미 프로세스가 실행되고 있지 않다면) 해당 앱의 프로세스를 구동시키며 필요한 클래스들을 준비합니다. 예를 들어, 내 앱에서 사진을 찍기 위해 카메라 앱의 액티비티를 실행한다면 이것은 내 앱의 프로세스가 아니라 카메라 앱의 프로세스에서 실행됩니다. 달리 말하자면 안드로이드 시스템은 다른 시스템과 달리 진입점이 유일하지 않다는 것입니다( main()함수가 없다는 의미입니다 ). 

시스템은 앱의 파일들이 다른 앱에서 사용되는 것을 막기 위해 각 앱은 각각의 프로세스에서 실행되도록 하기 때문에, 내 앱이 다른 앱의 컴포넌트를 직접적으로 실행하지는 못합니다. 대신에 컴포넌트를 실행시키기 위한 인텐트(intent)를 만들어서 시스템에 전달해 주면 시스템이 해당 컴포넌트를 실행시켜 줍니다. 


컴포넌트 실행시키기

4가지의 컴포넌트 중 3가지(액티비티, 서비스, 브로드캐스트 리시버)는 인텐트라 불리는 비동기 메시지를 통해 실행됩니다. 인텐트는 런타임에 컴포넌트를 실행하여 그것들을 서로 연결시켜 주며, 실행된 컴포넌트를 내 앱 또는 해당 앱에 포함시킵니다. 

인텐트는 Intent 클래스의 객체로 생성되며 컴포넌트를 실행하기 위한 메시지를 정의합니다. 인텐트는 명시적(explicit)이거나 암묵적(implicit)일 수 있는데, 인텐트에 실행할 컴포넌트가 정의되어 있으면 명시적이라 하고, 컴포넌트 대신에 다른 속성이 정의되어 있으면 암묵적이라고 합니다.

액티비티와 서비스를 실행하기 위해 인텐트는 "view"나 "send"와 같은 액션값을 정의하고, 필요한 데이터의 URI를 추가하기도 합니다. 예를 들어, 이미지를 보거나 웹페이지를 열기 위한 요청을 액티비티에 전달하기도 합니다. 어떤 경우에는 원하는 결과값을 얻기 위해 액티비티를 실행하기도 하는데 이때 결과값을 인텐트를 통해 전달 받습니다. 예를 들어, 주소록 액티비티를 실행하여 친구를 선택하면 선택된 친구의 정보를 가리키는 URI 값을 인텐트를 통해 받을 수 있습니다. 

브로드캐스트 리시버에서 전달받은 인텐트에는 발송된 알림이 정의되어 있습니다. 예를 들어, 배터리가 얼마 남지 않았을 때 발송되는 인텐트에는 "배터리가 얼마 남지 않았다"를 의미하는 액션값이 정의되어 있습니다.

4가지의 컴포넌트 중 나머지 1가지인 컨텐트 프로바이더는 인텐트로 실행되지 않습니다. 대신에 컨텐트 리졸버(ContentResolver)로부터 요청 받을 때 실행됩니다. 컨텐트 리졸버는 컨텐트 프로바이더가 제공하는 데이터들을 요청할 때 사용합니다. 다시 말해서 데이터를 요청하는 컴포넌트가 프로바이더에게 직접 요청하지 않고 컨텐트 리졸버를 통해서 요청하는 것입니다. 이것은 보안상의 이유로 데이터를 요청하는 컴포넌트와 데이터를 제공하는 컨텐트 프로바이더 사이에 추상적인 레이어를 하나 뒀다고 생각하면 됩니다.

아래는 각 컴포넌트를 실행하는 메소드들입니다.

  • 액티비티 실행: startActivity() 또는 startActivityForResult()에 인텐트를 전달하여 액티비티를 실행할 수 있습니다. (결과값을 리턴 받고자 할 때 startActivityForResult()를 호출합니다.)
  • 서비스 실행: startService() 또는 bindService()에 인텐트를 전달하여 서비스를 실행할 수 있습니다. 
  • 브로드캐스트 리시버 실행: sendBroadcast() 또는 sendOrderedBroadcast() 또는 sendStickyBroadcast()에 인텐트를 전달하여 알림을 발송할 수 있고, 알림이 발송되면 그 알림을 받도록 정의된 브로드캐스트 리시버가 실행됩니다.
  • 컨텐트 프로바이더 실행: 컨텐트 리졸버의 query() 메소드를 통해 컨텐트 프로바이더를 실행하고 데이터를 질의할 수 있습니다.

관련하여 더 자세한 내용은 아래 링크된 문서들을 통해 학습하실 수 있습니다.

Intent와 Intent Filter

Activity에 대하여

Service에 대하여

BroadcastReceiver에 대하여

Content Provider에 대하여 


매니페스트 파일 (The Manifest File)


안드로이드 시스템은 앱 컴포넌트를 실행하기 전에 매니페스트 파일 (AndroidManifest.xml)을 읽어보면서 해당 컴포넌트가 존재하는지 확인합니다. 따라서 앱의 모든 컴포넌트는 매니페스트 파일에 선언되어 있어야 하며, 매니페스트 파일은 앱 프로젝트의 루트 디렉토리에 있어야 합니다.

매니페스트 파일은 앱 컴포넌트를 선언하는 것 외에도 몇 가지 할 일이 더 있습니다.

  • 앱이 필요로 하는 퍼미션들을 선언합니다. 예를 들면, 인터넷 접속이나 주소록 정보 접근 권한 등이 있습니다. (<uses-permission>)
  • 최소 API 레벨을 선언합니다. 이것은 앱이 사용하는 API들이 API 레벨 몇부터 지원되는 것인지를 의미합니다. (<uses-sdk>)
  • 앱이 필요로 하는 하드웨어 및 소프트웨어 기능들을 선언합니다. 예를 들면, 카메라나 블루투스, 멀티터치 기능 등이 있습니다. (<uses-feature>)
  • 앱이 필요로 하는 API 라이브러리를 선언합니다. 예를 들면, 구글 맵스 라이브러리가 있습니다. (<uses-library>)


컴포넌트 선언하기

매니페스트의 가장 주된 일은 앱의 컴포넌트들을 시스템에게 알려주는 것입니다. 예를 들면, 매니페스트 파일에서 액티비티를 선언하는 방법은 아래와 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
   
<application android:icon="@drawable/app_icon.png" ... >
       
<activity android:name="com.example.project.ExampleActivity"
                 
android:label="@string/example_label" ... >
       
</activity>
        ...
   
</application>
</manifest>

<application> 요소 안에 있는 android:icon 속성값은 앱의 아이콘 이미지를 가리킵니다.

<activity> 요소 안에 있는 android:name 속성값은 패키지명을 포함한 액티비티의 클래스 이름이고, android:label 속성값은 액티비티의 제목이며 보통 액티비티의 타이틀바에 표시됩니다.

앱의 각 컴포넌트에 대응되는 요소는 다음과 같습니다.

액티비티, 서비스, 컨텐트 프로바이더는 클래스를 만들었다 하더라도 매니페스트 파일에 선언하지 않으면 안드로이드 시스템이 인식하지 못하기 때문에 실행되지 않습니다. 하지만 브로드캐스트 리시버는 조금 다릅니다. 다른 컴포넌트들과 마찬가지로 매니페스트 파일에 선언할 수도 있지만, 소스코드 내에서 동적으로 생성하고 registerReceiver() 메소드를 호출하여 시스템에 등록할 수 있습니다.

매니페스트 파일의 구성에 대한 자세한 내용은 안드로이드 매니페스트 파일에서 학습하실 수 있습니다.


컴포넌트의 역할을 선언하기

위의 컴포넌트 실행시키기에서 학습한 바에 따르면, 액티비티, 서비스, 브로드캐스트 리시버는 인텐트에 컴포넌트명을 넣어서 명시적(explicit)으로 실행할 수 있습니다. 하지만 인텐트의 진정한 힘(장점)은 암묵적(implicit)인 실행에 있습니다. 암묵적 인텐트는 컴포넌트명 없이 액션값을 갖고, 필요에 따라서는 데이터값을 가질 수도 있습니다. 그래서 액션값을 가지고 시스템으로 하여금 해당되는 컴포넌트를 찾아서 실행하게 할 수 있는 것입니다 (시스템은 컴포넌트가 선언한 역할들 중에 해당 액션값이 있는지를 찾습니다). 만약 액션값에 해당되는 컴포넌트가 2개 이상일 경우에는 사용자가 선택할 수 있도록 선택창이 뜹니다.

시스템은 설치된 앱들의 매니페스트 파일에 컴포넌트의 역할로서 선언된 인텐트 필터(intent filters) 중에서 해당 액션값이 있는지를 찾습니다.

매니페스트 파일에 액티비티를 선언할 때, 액티비티의 역할도 함께 선언하기 위해 인텐트 필터를 추가할 수 있습니다. 그러면 다른 앱들이 내 앱을 암묵적 인텐트를 이용하여 실행할 수 있습니다. 인텐트 필터는 그것을 추가하고자 하는 컴포넌트의 요소 안에 <intent-filter> 요소를 추가함으로써 선언할 수 있습니다. 

예를 들어, 이메일 쓰기 액티비티가 있는 이메일 앱을 만들었다면, 그 액티비티가 보내기 액션값(android.intent.action.SEND)이 있는 인텐트에 반응할 수 있도록 아래와 같이 인텐트 필터를 선언할 수 있습니다.

<manifest ... >
    ...
   
<application ... >
       
<activity android:name="com.example.project.ComposeEmailActivity">
           
<intent-filter>
               
<action android:name="android.intent.action.SEND" />
               
<data android:type="*/*" />
               
<category android:name="android.intent.category.DEFAULT" />
           
</intent-filter>
       
</activity>
   
</application>
</manifest>

위와 같이 선언된 액티비티는, 다른 앱이 보내기 액션값을 가진 인텐트를 만들어서 startActivity() 메소드를 호출할 경우 시스템이 찾아서 실행해 줍니다. (Intent클래스의 ACTION_SEND가 android.intent.action.SEND입니다.)

자세한 내용은 Intent와 Intent Filter에서 학습하실 수 있습니다.


앱의 요구조건 선언하기

안드로이드 디바이스의 종류는 다양하고, 제공되는 기능들이 모두 같지는 않습니다. 따라서, 필요로 하는 기능을 제공하지 않는 디바이스에 내 앱이 설치되는 것을 막기 위해서는 매니페스트 파일에 디바이스의 지원 기능과 소프트웨어 요구조건을 선언하는 것이 중요합니다. 하지만 이렇게 선언된 요구조건은 시스템에서 앱을 설치하거나 실행할 때 읽지 않습니다. 다시 말해서 앱을 설치하거나 실행할 때는 아무런 영향을 주지 않는 정보입니다. 그러나 이것은 구글플레이와 같은 외부 서비스에서 대상이 되는 사용자를 필터링하기 위해 사용됩니다. 바꿔 말하면, 어떤 앱에 대하여 필요한 기능이 없는 디바이스에서 구글플레이를 통해 검색하면 그 앱은 보이지 않는다는 말입니다.

예를 들어 카메라 기능을 필요로 하고 안드로이드 2.1버전(API 레벨 7)에서 추가된 API를 사용하는 앱의 경우 매니페스트 파일에 아래와 같이 요구조건을 선언해야 합니다.

<manifest ... >
   
<uses-feature android:name="android.hardware.camera.any"
                 
android:required="true" />
   
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
    ...
</manifest>

위와 같이 선언한 앱을 구글플레이에 출시했다면, 카메라 기능이 없거나 안드로이드 버전이 2.1 미만인 디바이스에서 구글플레이를 통해 그 앱을 설치할 수 없습니다. (발견할 수 없기 때문에 설치할 수도 없는 것입니다.)

카메라 기능을 사용하기는 하지만 그것이 필수는 아니라서 카메라 기능이 없는 디바이스에서도 앱을 사용할 수 있었으면 하는 경우가 있을 것입니다. 이러한 경우에는 android:requiredfalse로 설정하면 구글플레이를 통해서도 설치할 수 있으며, 시스템이 런타임에 카메라 기능의 지원 여부를 확인하여 적절히 비활성 처리를 해줍니다. 

다른 디바이스에서의 앱 호환성과 관련해서는 기기 호환성에서 학습하실 수 있습니다.


앱의 리소스 (App Resources)


안드로이드 앱은 자바 소스코드 외에도 이미지 파일, 오디오 파일, 애니메이션, 메뉴, 스타일, 컬러, 레이아웃 xml 파일 등의 리소스 파일들로 구성됩니다. 리소스를 사용함으로써 자바 소스코드를 수정하지 않고도 앱의 다양한 속성들을 업데이트할 수 있으며, 다양한 디바이스 환경에 대하여 각각에 최적화된 리소스 세트를 따로 정의할 수 있습니다. 예를 들면, 2개 이상의 언어를 지원해야 하는 경우나 다양한 스크린 사이즈를 지원해야 하는 경우 각각의 환경에 맞는 리소스 세트를 정의할 수 있습니다.

앱 프로젝트의 모든 리소스 파일들은 프로젝트가 빌드될 때 유니크한 정수형 ID로 정의되며, 그것들은 소스코드나 xml로 정의된 다른 리소스 파일에서 사용할 수 있습니다. 예를 들어 res/drawable/logo.png 파일이 있다고 가정하면, 빌드될 때 생성되는 R.java파일에 drawable 클래스의 정적 멤버 변수로 logo가 정의됩니다. 그러면 자바 소스코드에서는 R.drawable.logo 로 사용할 수 있고, 다른 리소스 xml파일에서는 @drawable/logo 로 사용할 수 있습니다. 

리소스를 소스코드와 분리해 놓은 것의 가장 큰 장점 중 하나는 다양한 환경에 최적화된 리소스를 따로 제공할 수 있다는 것입니다. 예를 들어 앱을 전세계 대상으로 런칭하려 한다면 한글과 영어를 모두 지원해야 할 것이고, 그러기 위해서 res/value/strings.xml 에는 영어 문자열들을 저장하고 res/value-kr/strings.xml 에는 한글 문자열들을 저장하면 됩니다. 그러면 안드로이드 시스템이 디바이스에 설정된 언어에 해당하는 문자열을 찾아서 사용자 UI에 출력해 줍니다.

위의 예에서 value뒤에 붙은 kr과 같은 것을 식별자(qualifier)라고 하는데, 안드로이드는 다양한 환경에 대하여 리소스를 제공할 수 있도록 많은 식별자들을 지원합니다. 다른 예로, 스크린의 가로/세로 여부 및 크기에 따라 다른 레이아웃을 생성할 수 있습니다. 스크린이 세로 모드라면 버튼들을 위아래로 나열하고 싶고 가로 모드라면 좌우로 나열하고 싶을 수 있겠죠. 이렇게 가로 및 세로 모드에 맞게 레이아웃이 변경되게 하고 싶다면 res/ 에 있는 layout 디렉토리에 적당한 식별자를 붙여주고 그에 해당하는 xml파일들을 저장하면 됩니다 (일반적으로 layout 디렉토리가 세로모드를 지원하고, layout-land 디렉토리가 가로모드를 지원합니다). 그러면 안드로이드 시스템이 현재 가로인지 세로인지를 확인하여 그에 맞는 레이아웃 xml파일을 적용하고 사용자에게 보여줍니다.

앱에 추가할 수 있는 다양한 종류의 리소스에 대해서나, 다양한 환경에 최적화된 리소스를 제공하는 방법에 대하여 더 자세한 내용은 리소스 제공하기에서 학습하실 수 있습니다. 


이어서 학습할 내용들:

Intent와 Intent Filter

인텐트를 사용하여 액티비티나 서비스와 같은 앱의 컴포넌트를 실행하는 방법과 다른 앱들이 내 앱의 컴포넌트를 실행할 수 있도록 하는 방법들에 대하여 자세히 학습합니다.

Activity에 대하여

액티비티를 만들고 화면에 사용자 인터페이스를 구현하는 방법에 대하여 자세히 학습합니다.

리소스 제공하기 (Providing Resources)

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


추가로 학습할 내용들:

기기 호환성 (Device Compativility)

다양한 종류의 디바이스들에서 안드로이드가 어떻게 동작하는지에 대해서와, 그러한 디바이스들의 제공 가능한 기능들과 관련하여 어떻게 최적화시킬 수 있는지에 대해 자세히 학습합니다.

시스템 퍼미션 (System Permissions)

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


Posted by 개발자 김태우
,

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

(위치: Develop > API Guides > Introduction)

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


안드로이드 입문


안드로이드는 모바일 디바이스용 앱과 게임의 개발을 지원하는 자바 언어 기반의 어플리케이션 프레임웍입니다. API가이드에서 제공하는 문서들은 안드로이드의 다양한 API들을 이용하여 앱을 개발하는 방법에 대해 설명해 드립니다. 

안드로이드 개발 초보분들은 안드로이드 프레임웍의 기본 개념을 이해하는 것이 중요합니다.

(앱이 어떻게 동작하는지를 알고 싶다면 기본 개념부터 학습하세요.)

(바로 코딩부터 시작하고 싶다면 나의 첫앱 만들기부터 학습하세요.)


앱의 시작점이 2개 이상일 수 있습니다.

안드로이드 앱은 독립적인 컴포넌트들의 조합으로 구성됩니다. 예를 들어, Activity는 사용자 인터페이스를 제공하는 하나의 독립적인 화면을 제공하고, Service는 백그라운드에서 독립적으로 실행됩니다.

컴포넌트에서 다른 컴포넌트를 실행할 때는 Intent를 사용합니다. 심지어는 서로 다른 앱 간에도 실행이 가능합니다. 지도앱이 그렇습니다. 지도앱은 독립적인 하나의 앱이지만 다른 앱들이 특정 주소를 지도위에서 보기 위해 지도앱을 실행할 수 있습니다.

관련 링크: 

앱의 기본 개념

Intent와 Intent Filter

Activity


앱은 다양한 디바이스에 대응해야 합니다.

안드로이드 프레임웍은 다양한 디바이스 환경에서 각각의 디바이스 환경에 맞는 리소스를 지정할 수 있도록 해줍니다. 예를 들어, 서로 다른 스크린 사이즈에 대응하는 XML 레이아웃 파일을 만들 수 있고, 해당 디바이스의 시스템이 자신의 스크린 사이즈에 맞는 XML 레이아웃 파일을 적용합니다.

앱이 카메라 같은 특정 하드웨어 기능을 필요로 할 경우 런타임에 해당 기능을 사용할 수 있는지 질의하여 확인할 수 있습니다. 앱을 설치한 디바이스에 카메라 모듈이 없는 경우 앱이 실행 중에 미리 알고 사용자에게 알려줄 수 있어야 하기 때문에 필요한 것입니다. 앱이 필요로 하는 기능들을 AndroidManifest.xml 에 정의해 두면, 구글 플레이 스토어에서 해당 기능을 지원하지 않는 디바이스에게는 앱을 보여주지 않도록 할 수 있습니다.

관련 링크: 

기기 호환성

리소스(Resource)

사용자 인터페이스

Posted by 개발자 김태우
,