API 수준: 18
Android 4.3 (JELLY_BEAN_MR2
)은 사용자와 앱 개발자에게 새로운 기능을 제공하는 Jelly Bean 버전의 업데이트입니다. 이 문서에서는 가장 주목할 만한 새 API를 소개합니다.
앱 개발자는 최대한 빨리 SDK Manager에서 Android 4.3 시스템 이미지와 SDK 플랫폼을 다운로드해야 합니다. 앱을 테스트할 Android 4.3을 실행하는 기기가 없는 경우 Android 4.3 시스템 이미지를 사용하여 Android 에뮬레이터에서 앱을 테스트합니다. 그런 다음 Android 4.3 플랫폼에서 앱을 빌드하여 최신 API를 사용할 수 있습니다.
대상 API 레벨 업데이트
Android 4.3을 실행하는 기기에서 앱을 더 효과적으로 최적화하려면 targetSdkVersion
를 "18"
로 설정하고 Android 4.3 시스템 이미지에 설치하고 테스트한 다음 이 변경사항으로 업데이트를 게시해야 합니다.
minSdkVersion
에서 지원하지 않는 API를 실행하기 전에 시스템 API 수준을 확인하는 조건을 코드에 추가하여 이전 버전을 지원하면서 Android 4.3에서 API를 사용할 수 있습니다.
이전 버전과의 호환성 유지에 관한 자세한 내용은 다양한 플랫폼 버전 지원을 참고하세요.
Android 지원 라이브러리에서도 다양한 API를 사용할 수 있으며, 이를 통해 이전 버전의 플랫폼에 새로운 기능을 구현할 수 있습니다.
API 수준의 작동 방식에 대한 자세한 내용은 API 수준이란 무엇인가요?를 참조하세요.
중요한 동작 변경 사항
이전에 Android용 앱을 게시한 적이 있다면 앱이 Android 4.3 변경사항의 영향을 받을 수 있다는 점에 유의하세요.
앱에서 암시적 인텐트를 사용하는 경우...
제한된 프로필 환경에서는 앱이 오작동할 수 있습니다.
제한된 프로필 환경의 사용자는 일부 표준 Android 앱을 사용하지 못할 수도 있습니다. 예를 들어 제한된 프로필의 경우 웹브라우저와 카메라 앱이 사용 중지될 수 있습니다. 따라서 앱이 사용 가능한 앱을 가정해서는 안 됩니다. 앱이 Intent
를 처리할 수 있는지 확인하지 않고 startActivity()
를 호출하면 제한된 프로필에서 앱이 비정상 종료될 수 있기 때문입니다.
암시적 인텐트를 사용할 때는 resolveActivity()
또는 queryIntentActivities()
를 호출하여 항상 앱이 인텐트를 처리할 수 있는지 확인해야 합니다. 예:
Kotlin
val intent = Intent(Intent.ACTION_SEND) ... if (intent.resolveActivity(packageManager) != null) { startActivity(intent) } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show() }
Java
Intent intent = new Intent(Intent.ACTION_SEND); ... if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show(); }
앱이 계정을 사용하는 경우...
제한된 프로필 환경에서는 앱이 오작동할 수 있습니다.
제한된 프로필 환경에 있는 사용자는 기본적으로 사용자 계정에 액세스할 수 없습니다.
앱이 Account
에 종속된 경우 제한된 프로필에서 사용하면 앱이 비정상 종료되거나 예기치 않은 동작이 발생할 수 있습니다.
앱이 민감한 계정 정보를 사용하므로 제한된 프로필이 앱을 완전히 사용하지 못하게 하려면 매니페스트의 <application>
요소에 android:requiredAccountType
속성을 지정합니다.
제한된 프로필이 자체 계정을 만들 수는 없더라도 앱을 계속 사용하도록 허용하려면 계정이 필요한 앱 기능을 사용 중지하거나 제한된 프로필이 기본 사용자가 만든 계정에 액세스하도록 허용할 수 있습니다. 자세한 내용은 제한된 프로필에서 계정 지원에 관한 아래 섹션을 참고하세요.
앱에서 VideoView를 사용하는 경우...
Android 4.3에서는 동영상이 더 작게 표시될 수 있습니다.
이전 버전의 Android에서 VideoView
위젯이 layout_height
및 layout_width
의 "wrap_content"
값을 "match_parent"
와 동일하게 잘못 계산했습니다. 따라서 높이 또는 너비에 "wrap_content"
를 사용하면 이전에 원하는 동영상 레이아웃을 제공했을 수도 있지만 그렇게 하면 Android 4.3 이상에서 동영상이 훨씬 작아질 수 있습니다. 이 문제를 해결하려면 "wrap_content"
를 "match_parent"
로 바꾸고 동영상이 Android 4.3과 이전 버전에서 예상대로 표시되는지 확인합니다.
제한된 프로필
이제 Android 태블릿에서 기본 사용자를 기준으로 제한된 프로필을 만들 수 있습니다. 사용자가 제한된 프로필을 만들 때 프로필에서 사용할 수 있는 앱과 같은 제한을 사용 설정할 수 있습니다. 또한 Android 4.3의 새로운 API 세트를 사용하면 개발하는 앱에 적용할 수 있는 세분화된 제한 설정을 빌드할 수 있습니다. 예를 들어 새로운 API를 사용하면 제한된 프로필 환경에서 실행할 때 사용자가 앱 내에서 사용할 수 있는 콘텐츠 유형을 제어할 수 있습니다.
빌드한 제한사항을 사용자가 제어할 수 있는 UI는 시스템의 설정 애플리케이션에서 관리합니다. 앱의 제한 설정을 사용자에게 표시하려면 ACTION_GET_RESTRICTION_ENTRIES
인텐트를 수신하는 BroadcastReceiver
를 만들어 앱이 제공하는 제한을 선언해야 합니다. 시스템은 이 인텐트를 호출하여 모든 앱에 사용 가능한 제한을 쿼리한 다음 기본 사용자가 제한된 각 프로필의 제한을 관리할 수 있도록 UI를 빌드합니다.
BroadcastReceiver
의 onReceive()
메서드에서 앱이 제공하는 각 제한에 관해 RestrictionEntry
를 만들어야 합니다. 각 RestrictionEntry
은 제한사항 제목, 설명, 다음 데이터 유형 중 하나를 정의합니다.
- true 또는 false인 제한의 경우
TYPE_BOOLEAN
- 상호 배타적인 여러 선택지가 있는 제한사항의 경우
TYPE_CHOICE
(라디오 버튼 선택) - 상호 배타적이지 않은 여러 선택지가 있는 제한사항의 경우
TYPE_MULTI_SELECT
(체크박스 선택)
그런 다음 모든 RestrictionEntry
객체를 ArrayList
에 넣고 broadcast receiver의 결과에 EXTRA_RESTRICTIONS_LIST
extra의 값으로 배치합니다.
시스템은 설정 앱에 앱 제한사항의 UI를 만들고 각 RestrictionEntry
객체에 제공된 고유 키로 각 제한사항을 저장합니다. 사용자가 앱을 열면 getApplicationRestrictions()
를 호출하여 현재 제한사항을 쿼리할 수 있습니다.
그러면 RestrictionEntry
객체로 정의한 각 제한사항의 키-값 쌍이 포함된 Bundle
가 반환됩니다.
불리언, 단일 선택, 다중 선택 값으로 처리할 수 없는 더 구체적인 제한사항을 제공하려면 사용자가 제한사항을 지정하고 사용자가 제한 설정에서 해당 활동을 열 수 있는 활동을 만들면 됩니다. broadcast receiver에서 결과 Bundle
에 EXTRA_RESTRICTIONS_INTENT
추가 항목을 포함합니다. 이 추가 항목은 실행할 Activity
클래스를 나타내는 Intent
를 지정해야 합니다 (putParcelable()
메서드를 사용하여 인텐트와 함께 EXTRA_RESTRICTIONS_INTENT
를 전달).
기본 사용자가 활동을 입력하여 맞춤 제한을 설정하면 활동은 각각 RestrictionEntry
객체 또는 키-값 쌍을 지정하는지 여부에 따라 EXTRA_RESTRICTIONS_LIST
또는 EXTRA_RESTRICTIONS_BUNDLE
키를 사용하여 제한 값이 포함된 결과를 추가로 반환해야 합니다.
제한된 프로필에서 계정 지원
기본 사용자에게 추가된 계정은 제한된 프로필에서 사용할 수 있지만 기본적으로 AccountManager
API에서 계정에 액세스할 수 없습니다.
제한된 프로필에서 AccountManager
를 사용하여 계정을 추가하려고 하면 실패 결과가 발생합니다. 이러한 제한사항으로 인해 다음 세 가지 옵션을 사용할 수 있습니다.
제한된 프로필에서 계정에 액세스하려면 android:restrictedAccountType
속성을 <application> 태그에 추가해야 합니다.
<application ... android:restrictedAccountType="com.example.account.type" >
주의: 이 속성을 사용 설정하면 제한된 프로필에서 기본 사용자 계정에 액세스할 수 있는 권한이 앱에 제공됩니다. 따라서 앱에서 표시하는 정보가 민감한 것으로 간주되는 개인 식별 정보 (PII)를 공개하지 않는 경우에만 이를 허용해야 합니다. 시스템 설정은 앱이 제한된 프로필을 계정에 부여한다는 것을 기본 사용자에게 알리므로 계정 액세스가 앱 기능에 중요하다는 것을 사용자가 명확히 알 수 있어야 합니다. 가능하면 앱에서 허용되는 계정 액세스 수준을 정의하는 기본 사용자에게 적절한 제한 컨트롤을 제공해야 합니다.
계정을 사용하고 싶지만 앱의 기본 기능을 위해 실제로 필요하지 않은 경우 계정 사용 가능 여부를 확인하고 사용할 수 없는 경우 기능을 사용 중지할 수 있습니다.
먼저 사용 가능한 기존 계정이 있는지 확인해야 합니다. 사용할 수 없으면 getUserRestrictions()
를 호출하여 새 계정을 만들 수 있는지 쿼리하고 결과에서 DISALLOW_MODIFY_ACCOUNTS
추가 항목을 확인합니다. true
인 경우 계정 액세스가 필요한 앱의 기능을 모두 사용 중지해야 합니다.
예:
Kotlin
val um = context.getSystemService(Context.USER_SERVICE) as UserManager val restrictions: Bundle = um.userRestrictions if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Java
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); Bundle restrictions = um.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
참고: 이 시나리오에서는 매니페스트 파일에서 새 속성을 선언해서는 안 됩니다.
대신 앱이 계정의 민감한 개인 정보를 사용하므로 제한된 프로필에는 앱을 사용할 수 없는 것이 중요하고 제한된 프로필은 현재 새 계정을 추가할 수 없으므로 android:requiredAccountType
속성을 <application> 태그에 추가합니다.
<application ... android:requiredAccountType="com.example.account.type" >
예를 들어 Gmail 앱은 소유자의 개인 이메일을 제한된 프로필에서 사용할 수 없어야 하므로 이 속성을 사용하여 제한된 프로필은 사용이 중지됩니다.
무선 및 연결
저전력 블루투스 (스마트 지원)
이제 Android는 android.bluetooth
의 새 API로 저전력 블루투스 (LE)를 지원합니다.
새 API를 사용하면 심박수 모니터 및 만보계와 같은 저전력 블루투스 주변기기와 통신하는 Android 앱을 빌드할 수 있습니다.
블루투스 LE는 일부 Android 지원 기기에서 사용할 수 없는 하드웨어 기능이므로 매니페스트 파일에서 "android.hardware.bluetooth_le"
의 <uses-feature>
요소를 선언해야 합니다.
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
Android의 기본 블루투스 API에 이미 익숙하다면 Bluetooth LE API를 사용하면 몇 가지 차이점이 있다는 점에 유의하세요. 가장 중요한 점은 이제 BluetoothAdapter
가져오기, 연결된 기기 목록 가져오기, 기기 상태 확인과 같은 상위 수준 작업에 사용해야 하는 BluetoothManager
클래스가 있다는 것입니다. 예를 들어 이제 BluetoothAdapter
를 가져오는 방법은 다음과 같습니다.
Kotlin
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager bluetoothAdapter = bluetoothManager.adapter
Java
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter();
블루투스 LE 주변기기를 검색하려면 BluetoothAdapter
에서 startLeScan()
를 호출하여 BluetoothAdapter.LeScanCallback
인터페이스의 구현에 전달합니다. 블루투스 어댑터가 블루투스 LE 주변기기를 감지하면 BluetoothAdapter.LeScanCallback
구현은 onLeScan()
메서드 호출을 수신합니다. 이 메서드는 감지된 기기를 나타내는 BluetoothDevice
객체, 기기의 RSSI 값, 기기의 광고 기록이 포함된 바이트 배열을 제공합니다.
특정 유형의 주변기기만 스캔하려면 대신 startLeScan()
를 호출하고 앱에서 지원하는 GATT 서비스를 지정하는 UUID
객체의 배열을 포함하면 됩니다.
참고: 블루투스 LE 기기 또는 이전 API를 사용하여 기존 블루투스 기기만 스캔할 수 있습니다. LE 및 클래식 블루투스 기기를 동시에 스캔할 수는 없습니다.
그런 다음 블루투스 LE 주변기기에 연결하려면 상응하는 BluetoothDevice
객체에서 connectGatt()
를 호출하여 BluetoothGattCallback
의 구현에 전달합니다. BluetoothGattCallback
의 구현은 기기 및 기타 이벤트와의 연결 상태에 관한 콜백을 수신합니다. 이 메서드는 onConnectionStateChange()
콜백 중에 메서드가 STATE_CONNECTED
를 새 상태로 전달하는 경우 기기와 통신을 시작할 수 있습니다.
또한 기기에서 블루투스 기능에 액세스하려면 앱이 특정 블루투스 사용자 권한을 요청해야 합니다. 자세한 내용은 저전력 블루투스 API 가이드를 참고하세요.
Wi-Fi 검색 전용 모드
사용자 위치를 식별하려고 할 때 Android는 Wi-Fi를 사용하여 근처 액세스 포인트를 스캔하여 위치를 파악할 수 있습니다. 그러나 사용자는 배터리를 절약하기 위해 Wi-Fi를 꺼두는 경우가 많으므로 위치 데이터의 정확도가 떨어집니다. 이제 Android에는 기기 Wi-Fi가 액세스 포인트에 연결하지 않고도 액세스 포인트를 스캔할 수 있는 검색 전용 모드가 포함되어 있으므로 배터리 사용량이 크게 줄어듭니다.
사용자의 위치를 가져오려고 하지만 현재 Wi-Fi가 꺼져 있다면 ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
작업으로 startActivity()
를 호출하여 사용자에게 Wi-Fi 검색 전용 모드를 사용 설정하도록 요청할 수 있습니다.
Wi-Fi 구성
새로운 WifiEnterpriseConfig
API를 사용하면 엔터프라이즈 지향 서비스가 관리 기기의 Wi-Fi 구성을 자동화할 수 있습니다.
수신 전화에 대한 빠른 응답
Android 4.0부터는 '빠른 응답'이라는 기능을 통해 사용자가 전화를 받거나 기기를 잠금 해제하지 않고도 즉시 문자 메시지로 수신 전화에 응답할 수 있습니다.
지금까지 이러한 빠른 메시지는 항상 기본 메시지 앱에서 처리되었습니다. 이제 모든 앱은 ACTION_RESPOND_VIA_MESSAGE
의 인텐트 필터와 함께 Service
를 생성하여 이러한 메시지를 처리하는 기능을 선언할 수 있습니다.
사용자가 수신 전화에 빠른 응답으로 응답하면 전화 앱은 수신자 (발신자)를 설명하는 URI와 함께 ACTION_RESPOND_VIA_MESSAGE
인텐트를 전송하고 사용자가 보내려는 메시지와 함께 EXTRA_TEXT
추가 항목을 전송합니다. 서비스가 인텐트를 수신하면 메시지를 전송하고 즉시 중지해야 합니다 (앱에서 활동을 표시해서는 안 됨).
이 인텐트를 수신하려면 SEND_RESPOND_VIA_MESSAGE
권한을 선언해야 합니다.
멀티미디어
MediaExtractor 및 MediaCodec 개선사항
이제 Android에서 ISO/IEC 23009-1 표준에 따라 MediaCodec
및 MediaExtractor
의 기존 API를 사용하여 자체 동적 적응형 스트리밍 (DASH) 플레이어를 작성할 수 있습니다. 이러한 API의 기반이 되는 프레임워크는 분할된 MP4 파일의 파싱을 지원하도록 업데이트되었지만 앱은 여전히 MPD 메타데이터를 파싱하고 개별 스트림을 MediaExtractor
에 전달해야 합니다.
암호화된 콘텐츠에 DASH를 사용하려면 getSampleCryptoInfo()
메서드가 암호화된 각 미디어 샘플의 구조를 설명하는 MediaCodec.CryptoInfo
메타데이터를 반환합니다. 또한 getPsshInfo()
메서드가 MediaExtractor
에 추가되었으므로 DASH 미디어의 PSSH 메타데이터에 액세스할 수 있습니다.
이 메서드는 UUID
객체의 맵을 바이트로 반환합니다. 여기서 UUID
는 암호화 스키마를 지정하고 바이트는 이 스키마와 관련된 데이터입니다.
미디어 DRM
새로운 MediaDrm
클래스는 DRM 문제를 미디어 재생에서 분리하여 미디어 콘텐츠의 디지털 권한 관리 (DRM)를 위한 모듈식 솔루션을 제공합니다. 예를 들어 이 API 분리를 사용하면 Widevine 미디어 형식을 사용하지 않고도 Widevine으로 암호화된 콘텐츠를 재생할 수 있습니다. 이 DRM 솔루션은 DASH 일반 암호화도 지원하므로 스트리밍 콘텐츠에 다양한 DRM 스키마를 사용할 수 있습니다.
MediaDrm
를 사용하여 불투명한 키 요청 메시지를 가져오고 라이선스 획득 및 프로비저닝을 위해 서버에서 키-응답 메시지를 처리할 수 있습니다. 앱은 서버와의 네트워크 통신을 처리합니다. MediaDrm
클래스는 메시지를 생성하고 처리하는 기능만 제공합니다.
MediaDrm
API는 Android 4.1 (API 수준 16)에서 도입된 MediaCodec
API와 함께 사용하도록 되어 있습니다. 여기에는 콘텐츠 인코딩 및 디코딩을 위한 MediaCodec
, 암호화된 콘텐츠 처리를 위한 MediaCrypto
, 콘텐츠 추출 및 디믹싱을 위한 MediaExtractor
가 포함됩니다.
먼저 MediaExtractor
및 MediaCodec
객체를 구성해야 합니다. 그런 다음 일반적으로 콘텐츠의 메타데이터에서 DRM 스키마 식별 UUID
에 액세스하고 이를 사용하여 생성자로 MediaDrm
객체의 인스턴스를 구성할 수 있습니다.
노출 영역에서 동영상 인코딩
Android 4.1 (API 수준 16)에는 미디어 콘텐츠의 하위 수준 인코딩 및 디코딩을 위한 MediaCodec
클래스가 추가되었습니다. 동영상을 인코딩할 때 Android 4.1에서는 미디어에 ByteBuffer
배열을 제공해야 했지만 이제 Android 4.3에서는 Surface
를 인코더에 대한 입력으로 사용할 수 있습니다. 예를 들어 이를 통해 기존 동영상 파일의 입력을 인코딩하거나 OpenGL ES에서 생성된 프레임을 사용할 수 있습니다.
Surface
를 인코더의 입력으로 사용하려면 먼저 MediaCodec
에 configure()
를 호출합니다.
그런 다음 createInputSurface()
를 호출하여 미디어를 스트리밍할 수 있는 Surface
를 수신합니다.
예를 들어, 주어진 Surface
을 eglCreateWindowSurface()
에 전달하여 OpenGL 컨텍스트의 창으로 사용할 수 있습니다. 그런 다음 노출 영역을 렌더링하는 동안 eglSwapBuffers()
를 호출하여 프레임을 MediaCodec
에 전달합니다.
인코딩을 시작하려면 MediaCodec
에서 start()
를 호출합니다. 완료되면 signalEndOfInputStream()
를 호출하여 인코딩을 종료하고 Surface
에서 release()
를 호출합니다.
미디어 Muxing
새로운 MediaMuxer
클래스는 하나의 오디오 스트림과 하나의 동영상 스트림 간의 멀티플렉싱을 사용 설정합니다. 이러한 API는 미디어 역다중화 (역다중화)를 위해 Android 4.2에 추가된 MediaExtractor
클래스에 상응하는 역할을 합니다.
지원되는 출력 형식은 MediaMuxer.OutputFormat
에 정의되어 있습니다. 현재 지원되는 유일한 출력 형식은 MP4이며 MediaMuxer
는 현재 한 번에 하나의 오디오 스트림 또는 하나의 동영상 스트림만 지원합니다.
MediaMuxer
는 대부분 MediaCodec
와 호환되도록 설계되었으므로 MediaCodec
를 통해 동영상 처리를 실행한 다음 MediaMuxer
를 통해 출력을 MP4 파일로 저장할 수 있습니다. MediaMuxer
를 MediaExtractor
와 함께 사용하여 인코딩 또는 디코딩 없이 미디어를 수정할 수도 있습니다.
RemoteControlClient의 재생 진행률 및 스크러빙
Android 4.0 (API 수준 14)에서는 잠금 화면에서 사용할 수 있는 컨트롤과 같은 원격 제어 클라이언트의 미디어 재생 컨트롤을 사용 설정하기 위해 RemoteControlClient
가 추가되었습니다. 이제 Android 4.3에서는 이러한 컨트롤러가 재생 위치와 재생 스크러빙 컨트롤을 표시하는 기능을 제공합니다. RemoteControlClient
API로 미디어 앱에 원격 제어를 사용 설정했다면 새로운 인터페이스 두 개를 구현하여 재생 스크러빙을 허용할 수 있습니다.
먼저 FLAG_KEY_MEDIA_POSITION_UPDATE
플래그를 setTransportControlsFlags()
에 전달하여 사용 설정해야 합니다.
그런 다음 아래의 새 인터페이스 두 개를 구현합니다.
RemoteControlClient.OnGetPlaybackPositionListener
- 여기에는 리모컨이 UI에서 진행률을 업데이트해야 할 때 미디어의 현재 위치를 요청하는 콜백
onGetPlaybackPosition()
가 포함됩니다. RemoteControlClient.OnPlaybackPositionUpdateListener
- 여기에는 사용자가 리모컨 UI로 재생을 스크러빙할 때 미디어의 새로운 시간 코드를 앱에 알려주는
onPlaybackPositionUpdate()
콜백이 포함됩니다.새 위치로 재생을 업데이트했다면
setPlaybackState()
를 호출하여 새 재생 상태, 위치 및 속도를 나타냅니다.
이러한 인터페이스를 정의한 후에는 setOnGetPlaybackPositionListener()
및 setPlaybackPositionUpdateListener()
를 각각 호출하여 RemoteControlClient
에 인터페이스를 설정할 수 있습니다.
그래픽
OpenGL ES 3.0 지원
Android 4.3은 Java 인터페이스와 OpenGL ES 3.0 기본 지원을 추가합니다. OpenGL ES 3.0에서 제공되는 주요 새로운 기능은 다음과 같습니다.
- 고급 시각 효과 가속화
- 표준 기능으로서의 고품질 ETC2/EAC 텍스처 압축
- 정수 및 32비트 부동 소수점을 지원하는 새로운 버전의 GLSL ES 셰이딩 언어
- 고급 텍스처 렌더링
- 텍스처 크기 및 렌더링 버퍼 형식의 광범위한 표준화
Android의 OpenGL ES 3.0용 자바 인터페이스는 GLES30
로 제공됩니다.
OpenGL ES 3.0을 사용할 때는 <uses-feature> 태그와 android:glEsVersion
속성을 사용하여 매니페스트 파일에서 이를 선언해야 합니다. 예:
<manifest> <uses-feature android:glEsVersion="0x00030000" /> ... </manifest>
또한 setEGLContextClientVersion()
를 호출하고 3
을 버전으로 전달하여 OpenGL ES 컨텍스트를 지정해야 합니다.
런타임 시 기기에서 지원되는 OpenGL ES 버전을 확인하는 방법을 포함하여 OpenGL ES 사용에 관한 자세한 내용은 OpenGL ES API 가이드를 참고하세요.
드로어블의 밉매핑
밉맵을 비트맵이나 드로어블의 소스로 사용하면 간단한 방법으로 고품질 이미지와 다양한 이미지 배율을 제공할 수 있습니다. 이는 애니메이션 중에 이미지 크기가 조절될 것으로 예상되는 경우에 특히 유용할 수 있습니다.
Android 4.2 (API 수준 17)의 Bitmap
클래스에서 밉맵 지원이 추가되었습니다. 밉맵 소스를 제공하고 setHasMipMap()
를 사용 설정한 경우 Android는 Bitmap
의 밉맵 이미지를 교체합니다. 이제 Android 4.3에서는 밉맵 애셋을 제공하고 비트맵 리소스 파일에 android:mipMap
속성을 설정하거나 hasMipMap()
를 호출하여 BitmapDrawable
객체에도 밉맵을 사용 설정할 수 있습니다.
사용자 인터페이스
뷰 오버레이
새 ViewOverlay
클래스는 View
위에 시각적 콘텐츠를 추가할 수 있고 레이아웃 계층 구조에 영향을 주지 않는 투명 레이어를 제공합니다. getOverlay()
를 호출하여 모든 View
의 ViewOverlay
를 가져올 수 있습니다. 오버레이는 항상 호스트 뷰 (생성된 뷰)와 크기와 위치가 같으므로 호스트 뷰 앞에 표시되지만 호스트 뷰의 경계를 확장할 수 없는 콘텐츠를 추가할 수 있습니다.
ViewOverlay
는 뷰 계층 구조에 영향을 주지 않고 컨테이너 외부로 뷰를 슬라이드하거나 화면에서 항목을 이동하는 등의 애니메이션을 만들려고 할 때 특히 유용합니다. 그러나 오버레이의 사용 가능한 영역은 호스트 뷰와 동일한 영역으로 제한되므로 레이아웃에서 해당 위치를 벗어나 움직이는 뷰를 애니메이션화하려면 원하는 레이아웃 경계가 있는 상위 뷰의 오버레이를 사용해야 합니다.
Button
와 같은 위젯 뷰의 오버레이를 만들 때 add(Drawable)
를 호출하여 Drawable
객체를 오버레이에 추가할 수 있습니다. RelativeLayout
와 같은 레이아웃 뷰에 getOverlay()
를 호출하면 반환되는 객체는 ViewGroupOverlay
입니다. ViewGroupOverlay
클래스는 ViewOverlay
의 서브클래스이며 add(View)
를 호출하여 View
객체를 추가할 수도 있습니다.
참고: 오버레이에 추가하는 모든 드로어블과 뷰는 시각적일 뿐입니다. 포커스 또는 입력 이벤트를 수신할 수 없습니다.
예를 들어 다음 코드는 상위 뷰의 오버레이에 뷰를 배치한 후 이 뷰에서 변환 애니메이션을 실행하여 오른쪽으로 슬라이드되는 뷰를 애니메이션합니다.
Kotlin
val view: View? = findViewById(R.id.view_to_remove) val container: ViewGroup? = view?.parent as ViewGroup container?.apply { overlay.add(view) ObjectAnimator.ofFloat(view, "translationX", right.toFloat()) .start() }
Java
View view = findViewById(R.id.view_to_remove); ViewGroup container = (ViewGroup) view.getParent(); container.getOverlay().add(view); ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight()); anim.start();
광학 경계 레이아웃
나인 패치 배경 이미지가 포함된 뷰의 경우 이제 뷰의 '클립' 경계가 아닌 배경 이미지의 '광학' 경계에 따라 인접한 뷰에 정렬되도록 지정할 수 있습니다.
예를 들어 그림 1과 그림 2는 각각 동일한 레이아웃을 표시하지만 그림 1의 버전은 클립 경계 (기본 동작)를 사용하지만 그림 2는 광학 경계를 사용합니다. 버튼과 디지털 액자에 사용된 나인 패치 이미지의 가장자리 주위에 패딩이 포함되어 있으므로 클립 경계를 사용할 때 서로 정렬되거나 텍스트와 정렬되지 않는 것처럼 보입니다.
참고: 그림 1과 2의 스크린샷에는 'Show layout bounds' 개발자 설정이 사용 설정되어 있습니다. 각 뷰에서 빨간색 선은 광학 경계를 나타내고 파란색 선은 클립 경계를 나타내며 분홍색 선은 여백을 나타냅니다.

그림 1. 클립 경계를 사용하는 레이아웃 (기본값)

그림 2. 광학 경계를 사용하는 레이아웃
광학 경계를 기반으로 뷰를 정렬하려면 상위 요소 레이아웃 중 하나에서 android:layoutMode
속성을 "opticalBounds"
로 설정합니다. 예:
<LinearLayout android:layoutMode="opticalBounds" ... >

그림 3. 광학 경계가 있는 Holo 버튼 나인 패치의 확대된 뷰
이 기능이 작동하려면 뷰의 배경에 적용된 나인 패치 이미지가 나인 패치 파일의 하단과 오른쪽을 따라 빨간색 선을 사용하여 광학 경계를 지정해야 합니다 (그림 3 참고). 빨간색 선은 이미지의 광학 경계를 벗어나 클립 경계에서 빼야 하는 영역을 나타냅니다.
레이아웃에서 ViewGroup
에 광학 경계를 사용 설정하면 android:layoutMode
를 "clipBounds"
로 설정하여 그룹에 관해 재정의하지 않는 한 모든 하위 뷰는 광학 경계 레이아웃 모드를 상속합니다. 또한 모든 레이아웃 요소는 하위 뷰의 광학 경계를 적용하여 뷰 내에 있는 뷰의 광학 경계를 기반으로 자체 경계를 조정합니다. 그러나 레이아웃 요소 (ViewGroup
의 서브클래스)는 현재 자체 배경에 적용된 나인 패치 이미지에 광학 경계를 지원하지 않습니다.
View
, ViewGroup
또는 그 서브클래스를 서브클래스로 분류하여 맞춤 뷰를 만들면 뷰가 이러한 광학 바인딩 동작을 상속합니다.
참고: Holo 테마에서 지원하는 모든 위젯은 Button
, Spinner
, EditText
등을 포함하여 광학 경계로 업데이트되었습니다. 따라서 앱에서 Holo 테마(Theme.Holo
, Theme.Holo.Light
등)를 적용하는 경우 android:layoutMode
속성을 "opticalBounds"
로 설정하면 즉시 이점을 얻을 수 있습니다.
9-패치 그리기 도구로 나인 패치 이미지의 광학 경계를 지정하려면 테두리 픽셀을 클릭할 때 Control 키를 길게 누릅니다.
Rect 값의 애니메이션
이제 새 RectEvaluator
를 사용하여 두 Rect
값 간에 애니메이션을 적용할 수 있습니다. 이 새로운 클래스는 ValueAnimator.setEvaluator()
에 전달할 수 있는 TypeEvaluator
의 구현입니다.
창 연결 및 포커스 리스너
이전에는 뷰가 창에 연결/분리된 시점 또는 포커스가 변경될 때를 수신 대기하려면 View
클래스를 재정의하여 각각 onAttachedToWindow()
및 onDetachedFromWindow()
또는 onWindowFocusChanged()
를 구현해야 했습니다.
이제 연결 및 분리 이벤트를 수신하려면 대신 ViewTreeObserver.OnWindowAttachListener
를 구현하고 addOnWindowAttachListener()
를 사용하여 뷰에서 설정하면 됩니다.
포커스 이벤트를 수신하려면 ViewTreeObserver.OnWindowFocusChangeListener
를 구현하고 addOnWindowFocusChangeListener()
를 사용하여 뷰에 설정하면 됩니다.
TV 오버스캔 지원
앱이 모든 텔레비전의 전체 화면을 채우도록 이제 앱 레이아웃에 오버스캔을 사용 설정할 수 있습니다. 오버스캔 모드는 FLAG_LAYOUT_IN_OVERSCAN
플래그에 따라 결정됩니다. 이 플래그는 Theme_DeviceDefault_NoActionBar_Overscan
와 같은 플랫폼 테마와 함께 사용 설정하거나 맞춤 테마에서 windowOverscan
스타일을 사용 설정하여 사용 설정할 수 있습니다.
화면 방향
이제 <activity>
태그의 screenOrientation
속성이 사용자의 자동 회전 환경설정을 준수하는 추가 값을 지원합니다.
"userLandscape"
"sensorLandscape"
와 동일하게 작동합니다. 단, 사용자가 자동 회전을 사용 중지한 경우 일반 가로 방향으로 잠기고 뒤집히지 않습니다."userPortrait"
"sensorPortrait"
와 동일하게 작동합니다. 단, 사용자가 자동 회전을 사용 중지하면 일반적인 세로 모드 방향으로 잠기고 뒤집히지 않습니다."fullUser"
"fullSensor"
와 동일하게 작동하며 4개 방향 모두에서 회전을 허용합니다. 단, 사용자가 자동 회전을 사용 중지하면 사용자가 원하는 방향으로 잠깁니다.
또한 이제 "locked"
를 선언하여 앱의 방향을 화면의 현재 방향으로 잠글 수도 있습니다.
회전 애니메이션
WindowManager
의 새로운 rotationAnimation
필드를 사용하면 시스템에서 화면 방향을 전환할 때 사용할 세 가지 애니메이션 중 하나를 선택할 수 있습니다. 세 가지 애니메이션은 다음과 같습니다.
참고: 이러한 애니메이션은 Theme.Holo.NoActionBar.Fullscreen
와 같은 테마로 사용 설정할 수 있는 '전체 화면' 모드를 사용하도록 활동을 설정한 경우에만 사용할 수 있습니다.
예를 들어 '크로스페이드' 애니메이션을 사용 설정하는 방법은 다음과 같습니다.
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val params: WindowManager.LayoutParams = window.attributes params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE window.attributes = params ... }
Java
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WindowManager.LayoutParams params = getWindow().getAttributes(); params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; getWindow().setAttributes(params); ... }
사용자 입력
새 센서 유형
새로운 TYPE_GAME_ROTATION_VECTOR
센서를 사용하면 자기 간섭에 대한 걱정 없이 기기 회전을 감지할 수 있습니다. TYPE_ROTATION_VECTOR
센서와 달리 TYPE_GAME_ROTATION_VECTOR
는 자북을 기반으로 하지 않습니다.
새로운 TYPE_GYROSCOPE_UNCALIBRATED
및 TYPE_MAGNETIC_FIELD_UNCALIBRATED
센서는 편향 추정을 고려하지 않고 원시 센서 데이터를 제공합니다. 즉, 기존 TYPE_GYROSCOPE
및 TYPE_MAGNETIC_FIELD
센서는 각각 기기의 자이로 드리프트 및 강철에서 추정된 바이어스를 고려하는 센서 데이터를 제공합니다. 반면에 이러한 센서의 새로운 '미보정' 버전은 원시 센서 데이터를 대신 제공하고 추정된 바이어스 값을 별도로 제공합니다. 이러한 센서를 사용하면 외부 데이터로 추정된 바이어스를 향상시켜 센서 데이터에 관한 자체 맞춤 보정을 제공할 수 있습니다.
알림 수신기
Android 4.3에는 시스템에서 게시하는 새 알림에 관한 정보를 앱이 수신할 수 있는 새로운 서비스 클래스 NotificationListenerService
가 추가되었습니다.
앱에서 현재 접근성 서비스 API를 사용하여 시스템 알림에 액세스하는 경우, 대신 이러한 API를 사용하도록 앱을 업데이트해야 합니다.
연락처 제공자
'연락 가능 기기' 쿼리
새로운 연락처 제공자 쿼리인 Contactables.CONTENT_URI
는 지정된 쿼리와 일치하는 모든 연락처에 속한 모든 이메일 주소와 전화번호가 포함된 하나의 Cursor
를 가져오는 효율적인 방법을 제공합니다.
연락처 델타 쿼리
연락처 제공자에 새로운 API가 추가되어 연락처 데이터의 최근 변경 사항을 효율적으로 쿼리할 수 있습니다. 이전에는 연락처 데이터의 무언가가 변경될 때 앱이 알림을 받을 수 있었지만 정확히 무엇이 변경되었는지 모르고 모든 연락처를 검색한 다음 이를 반복하여 변경사항을 찾아야 했습니다.
삽입 및 업데이트의 변경사항을 추적하기 위해 이제 CONTACT_LAST_UPDATED_TIMESTAMP
매개변수를 선택 항목과 함께 포함하여 마지막으로 제공자를 쿼리한 이후 변경된 연락처만 쿼리할 수 있습니다.
삭제된 연락처를 추적하기 위해 새 테이블 ContactsContract.DeletedContacts
에서는 삭제된 연락처의 로그를 제공합니다 (단, 삭제된 각 연락처는 제한된 기간 동안 이 테이블에 보관됩니다). CONTACT_LAST_UPDATED_TIMESTAMP
와 마찬가지로 새로운 선택 매개변수 CONTACT_DELETED_TIMESTAMP
를 사용하여 마지막으로 제공업체를 쿼리한 후 삭제된 연락처를 확인할 수 있습니다. 이 테이블에는 로그가 보관되는 일수 (밀리초)가 포함된 상수 DAYS_KEPT_MILLISECONDS
도 있습니다.
또한 이제 연락처 제공자는 사용자가 시스템 설정 메뉴를 통해 연락처 저장소를 지울 때 CONTACTS_DATABASE_CREATED
작업을 브로드캐스트하여 연락처 제공자 데이터베이스를 효과적으로 다시 만듭니다. 이는 앱이 저장한 모든 연락처 정보를 삭제하고 새 쿼리로 다시 로드해야 한다고 앱에 알리기 위한 것입니다.
이러한 API를 사용하여 연락처 변경사항을 확인하는 샘플 코드는 SDK 샘플 다운로드에서 제공되는 ApiDemos 샘플을 참고하세요.
현지화
양방향 텍스트에 대한 지원 개선
이전 버전의 Android는 오른쪽에서 왼쪽 (RTL) 방향 언어와 레이아웃을 지원하지만 방향이 혼합된 텍스트를 올바르게 처리하지 못하는 경우가 있습니다. 따라서 Android 4.3에는 텍스트의 일부를 왜곡하지 않고 반대 방향 콘텐츠로 올바르게 텍스트 서식을 지정할 수 있는 BidiFormatter
API가 추가되었습니다.
예를 들어 ' 귀하가 15 Bay Street, Laurel, CA'와 같은 문자열 변수가 포함된 문장을 만들려는 경우, 일반적으로 현지화된 문자열 리소스와 변수를 String.format()
에 전달합니다.
Kotlin
val suggestion = String.format(resources.getString(R.string.did_you_mean), address)
Java
Resources res = getResources(); String suggestion = String.format(res.getString(R.string.did_you_mean), address);
하지만 언어가 히브리어인 경우 형식이 지정된 문자열은 다음과 같이 표시됩니다.
האם התכוונת ל 15 Bay Street, Laurel, CA?
'15'가 'Bay Street'의 왼쪽에 위치해야 하므로 틀렸습니다. 해결 방법은 BidiFormatter
및 unicodeWrap()
메서드를 사용하는 것입니다. 예를 들어 위의 코드는 다음과 같습니다.
Kotlin
val bidiFormatter = BidiFormatter.getInstance() val suggestion = String.format( resources.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address) )
Java
Resources res = getResources(); BidiFormatter bidiFormatter = BidiFormatter.getInstance(); String suggestion = String.format(res.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address));
기본적으로 unicodeWrap()
는 텍스트 방향의 첫 번째 신호가 콘텐츠 전체에 적절한 방향을 나타내지 않으면 잘못될 수 있는 첫 번째 강력한 방향 추정 휴리스틱을 사용합니다.
필요한 경우 TextDirectionHeuristic
상수 중 하나를 TextDirectionHeuristics
에서 unicodeWrap()
로 전달하여 다른 휴리스틱을 지정할 수 있습니다.
참고: 이러한 새 API는 BidiFormatter
클래스 및 관련 API와 함께 Android 지원 라이브러리를 통해 이전 버전의 Android에도 사용할 수 있습니다.
접근성 서비스
키 이벤트 처리
이제 AccessibilityService
는 onKeyEvent()
콜백 메서드를 사용하여 키 입력 이벤트의 콜백을 수신할 수 있습니다. 이렇게 하면 접근성 서비스에서 키보드와 같은 키 기반 입력 기기의 입력을 처리하고 이러한 이벤트를 터치 입력 또는 기기의 방향 패드로만 가능했을 수 있는 특수한 작업으로 변환할 수 있습니다.
텍스트를 선택하고 복사/붙여넣기
AccessibilityNodeInfo
는 이제 AccessibilityService
가 노드에서 텍스트를 선택, 잘라내기, 복사, 붙여넣을 수 있는 API를 제공합니다.
잘라내거나 복사할 텍스트 선택을 지정하기 위해 접근성 서비스에서 새 작업 ACTION_SET_SELECTION
을 사용하여 ACTION_ARGUMENT_SELECTION_START_INT
및 ACTION_ARGUMENT_SELECTION_END_INT
와 함께 선택 시작 및 종료 위치를 전달하면 됩니다.
또는 기존 작업인 ACTION_NEXT_AT_MOVEMENT_GRANULARITY
(이전에는 커서 위치 이동용으로만 사용)을 사용하여 커서 위치를 조작하고 ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
인수를 추가하여 텍스트를 선택할 수 있습니다.
그런 다음 ACTION_CUT
, ACTION_COPY
를 사용하여 잘라내거나 복사한 후 나중에 ACTION_PASTE
를 사용하여 붙여넣을 수 있습니다.
참고: 이러한 새 API는 AccessibilityNodeInfoCompat
클래스와 함께 Android 지원 라이브러리를 통해 이전 버전의 Android에서도 사용할 수 있습니다.
접근성 기능 선언
Android 4.3부터 접근성 서비스는 특정 접근성 기능을 사용하려면 메타데이터 파일에서 접근성 기능을 선언해야 합니다. 메타데이터 파일에서 기능이 요청되지 않으면 기능이 작동하지 않습니다. 서비스의 접근성 기능을 선언하려면 AccessibilityServiceInfo
클래스의 다양한 '기능' 상수에 상응하는 XML 속성을 사용해야 합니다.
예를 들어 서비스가 flagRequestFilterKeyEvents
기능을 요청하지 않으면 키 이벤트를 수신하지 않습니다.
테스트 및 디버깅
자동화된 UI 테스트
새로운 UiAutomation
클래스는 테스트 자동화를 위해 사용자 작업을 시뮬레이션할 수 있는 API를 제공합니다. UiAutomation
API는 플랫폼의 AccessibilityService
API를 사용하여 화면 콘텐츠를 검사하고 임의의 키보드와 터치 이벤트를 삽입할 수 있도록 합니다.
UiAutomation
의 인스턴스를 가져오려면 Instrumentation.getUiAutomation()
를 호출합니다. 이렇게 하려면 adb shell
에서 InstrumentationTestCase
를 실행할 때 instrument
명령어와 함께 -w
옵션을 제공해야 합니다.
UiAutomation
인스턴스를 사용하면 executeAndWaitForEvent()
를 호출하고 실행할 Runnable
, 작업의 제한 시간, UiAutomation.AccessibilityEventFilter
인터페이스 구현을 전달하여 임의의 이벤트를 실행하여 앱을 테스트할 수 있습니다. 관심 있는 이벤트를 필터링하고 지정된 테스트 사례의 성공 또는 실패를 확인할 수 있는 호출을 수신하는 것은 UiAutomation.AccessibilityEventFilter
구현 내에서 이루어집니다.
테스트 중에 모든 이벤트를 관찰하려면 UiAutomation.OnAccessibilityEventListener
구현을 만들어 setOnAccessibilityEventListener()
에 전달합니다.
그러면 리스너 인터페이스는 이벤트가 발생할 때마다 onAccessibilityEvent()
호출을 수신하고 이벤트를 설명하는 AccessibilityEvent
객체를 수신합니다.
uiautomator와 같은 UI 테스트 도구의 개발을 장려하기 위해 UiAutomation
API는 매우 낮은 수준에서 노출하는 다양한 다른 작업이 있습니다. 예를 들어 UiAutomation
는 다음 작업도 할 수 있습니다.
- 입력 이벤트 삽입
- 화면 방향 변경
- 스크린샷 찍기
무엇보다도 UI 테스트 도구의 경우 UiAutomation
API는 Instrumentation
의 API와 달리 애플리케이션 경계에서 작동합니다.
앱의 Systrace 이벤트
Android 4.3에서는 systrace 보고서에 포함할 코드 블록을 정의할 수 있는 두 개의 정적 메서드인 beginSection()
및 endSection()
가 있는 Trace
클래스를 추가합니다. systrace 로그를 통해 앱에 추적 가능한 코드의 섹션을 만들면 앱 내에서 속도 저하가 발생하는 위치를 훨씬 자세히 분석할 수 있습니다.
Systrace 도구 사용에 관한 자세한 내용은 Systrace로 디스플레이 및 성능 분석을 참고하세요.
보안
앱 비공개 키를 위한 Android 키 저장소
이제 Android는 KeyStore
시설에서 Android Key Store라는 맞춤 자바 보안 제공자를 제공합니다. 이 기능을 사용하면 앱에서만 보고 사용할 수 있는 비공개 키를 생성하고 저장할 수 있습니다. Android 키 저장소를 로드하려면 "AndroidKeyStore"
를 KeyStore.getInstance()
에 전달합니다.
Android 키 저장소에서 앱의 비공개 사용자 인증 정보를 관리하려면 KeyPairGeneratorSpec
인 KeyPairGenerator
으로 새 키를 생성합니다. 먼저 getInstance()
를 호출하여 KeyPairGenerator
의 인스턴스를 가져옵니다. 그런 다음 initialize()
를 호출하여 KeyPairGeneratorSpec.Builder
를 사용하여 가져올 수 있는 KeyPairGeneratorSpec
의 인스턴스를 전달합니다.
마지막으로 generateKeyPair()
를 호출하여 KeyPair
를 가져옵니다.
하드웨어 사용자 인증 정보 저장소
또한 이제 Android는 KeyChain
사용자 인증 정보를 위한 하드웨어 지원 저장소를 지원하므로 키를 추출할 수 없도록 하여 보안을 강화합니다. 즉, 하드웨어 지원 키 저장소 (보안 요소, TPM 또는 TrustZone)에 키가 있으면 암호화 작업에 사용할 수 있지만 비공개 키 자료는 내보낼 수 없습니다. OS 커널도 이 키 자료에 액세스할 수 없습니다. 모든 Android 지원 기기가 하드웨어의 저장소를 지원하는 것은 아니지만 KeyChain.IsBoundKeyAlgorithm()
를 호출하여 하드웨어 지원 저장소를 사용할 수 있는지 런타임에 확인할 수 있습니다.
매니페스트 선언
선언이 필요한 기능
이제 다음 값이 <uses-feature>
요소에서 지원되므로 앱에 필요한 기능을 제공하는 기기에만 앱이 설치되도록 할 수 있습니다.
FEATURE_APP_WIDGETS
- 앱이 앱 위젯을 제공하고 사용자가 앱 위젯을 삽입할 수 있는 홈 화면 또는 유사한 위치를 포함하는 기기에만 설치되어야 한다고 선언합니다.
예를 들면 다음과 같습니다.
<uses-feature android:name="android.software.app_widgets" android:required="true" />
FEATURE_HOME_SCREEN
- 앱이 홈 화면 대체로 작동하고 서드 파티 홈 화면 앱을 지원하는 기기에만 설치되어야 한다고 선언합니다.
예를 들면 다음과 같습니다.
<uses-feature android:name="android.software.home_screen" android:required="true" />
FEATURE_INPUT_METHODS
- 앱이 맞춤 입력 방법 (
InputMethodService
로 빌드된 키보드)을 제공하고 서드 파티 입력 방법을 지원하는 기기에만 설치해야 한다고 선언합니다. 예를 들면 다음과 같습니다.<uses-feature android:name="android.software.input_methods" android:required="true" />
FEATURE_BLUETOOTH_LE
- 앱이 Bluetooth Low Energy API를 사용하고 Bluetooth Low Energy를 통해 다른 기기와 통신할 수 있는 기기에만 설치되어야 한다고 선언합니다.
예:
<uses-feature android:name="android.software.bluetooth_le" android:required="true" />
사용자 권한
이제 다음 값이 <uses-permission>
에서 지원되어 앱이 특정 API에 액세스하는 데 필요한 권한을 선언합니다.
BIND_NOTIFICATION_LISTENER_SERVICE
- 새
NotificationListenerService
API를 사용하는 데 필요합니다. SEND_RESPOND_VIA_MESSAGE
ACTION_RESPOND_VIA_MESSAGE
인텐트를 수신하는 데 필요합니다.
Android 4.3의 모든 API 변경사항에 관한 자세한 내용은 API 차이점 보고서를 참고하세요.