3일 전까지 문제없이 잘 돌아가던 안드로이드 프로젝트에서 갑자기 빌드가 안되는 문제가 발생하였습니다.
주말이 지났을 뿐인데 아래와 같은 로그와 함께 gradle sync도 안되는 문제였습니다.
org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':mymodule'. ... Caused by: groovy.lang.MissingPropertyException: Could not get unknown property 'assemble'for task ':mymodule:assembleDebug' of type org.gradle.api.DefaultTask.
혹시나 하는 마음에 소스를 1년 전 껄로 돌려보아도 동일하고, 딱히 형상관리에 문제도 없어 보였죠.
위 관련 내용에 따르면 속성 값이 높을수록 보안 수준이 높아지며, 2일 경우 usesCleartextTraffic의 기본 값이 false가 됨. 그래서 이 속성의 값을 1로 변경해야함. 다만 Android 8.0 (API 26) 이상을 타겟팅하는 Android Instant Apps의 경우 이 속성을 2로 설정해야 함.
뷰 포커스, CSS RGBA 값 처리, document 스크롤 처리, 일시 정지된 앱의 알림 등의 UI 변경
포그라운드 서비스
Android 9 이상 대상 앱에서 포그라운드 서비스를 사용하는 앱은 FOREGROUND_SERVICE 권한을 요청해야 함.
Android 9 이상에서 권한 요청 없이 포그라운드 서비스 생성 시도시 시스템이 SecurityException 발생함.
개인정보 보호 정책 변경사항
빌드 일련번호 지원 중단
Android 9에서는 Build.SERIAL 이 항상 "UNKNOWN"으로 설정됨.
기기 하드웨어 일련번호 액세스시 READ_PHONE_STATE 권한 요청 후 getSerial() 을 호출해야 함.
DNS 개인정보 보호
비공개 DNS API를 준수해야 함.
시스템 확인자가 TLS를 통한 DNS를 수행할 경우 내장 DNS 클라이언트가 동일한 호스트 이름에 대해 암호화된 DNS를 시스템으로 사용하거나 시스템 확인자를 위해 비활성화됨.
프레임워크 보안 변경사항
기본적으로 네트워크 TLS 사용
Android 9에서는 isCleartextTrafficPermitted() 메서드는 기본적으로 false를 반환함.
특정 도메인을 위해 일반 텍스트 사용할 필요 있을 경우 cleartextTrafficPermitted 앱의 네트워크 보안 구성에서 해당 도메인을 true로 명시적으로 설정해야 함.
프로세스 별로 구분되는 웹 기반 데이터 디렉토리
앱은 여러 프로세스 사이에서 단일 WebView 데이터 디렉토리를 공유할 수 없음.
이러한 데이터 디렉토리는 쿠키, HTTP 캐시 그리고 웹 검색과 관련된 다른 영구 저장소와 임시 저장소를 저장함.
대부분의 앱은 한 프로세스에서만 WebView와 CookieManager 같은 android.webkit 패키지의 클래스를 사용함.
앱이 두 개 이상의 프로세스에서 WebView 인스턴스를 사용해야 하는 경우 각 프로세스에서 WebView 의 인스턴스를 사용하기 전에 WebView.setDataDiretorySuffix() 메서드를 사용하여 해당 프로세스에 대한 고유한 데이터 디렉토리 접미사를 지정해야 함.
이 메서드는 각 프로세스의 웹 데이터를 앱의 데이터 디렉토리 내에 있는 자체 디렉토리에 넣음.
앱별 SELinux 도메인
Android 9 이상 앱은 어디서든 액세스 가능한 Unix 권한을 사용하는 다른 앱과 데이터를 공유할 수 없음.
다른 앱과 파일을 공유하려면 콘텐츠 프로바이더를 사용해야 함.
연결 변경사항
연결 데이터 카운트 및 다중 경로
시스템은 현재 기본값이 아닌 네트워크 상의 네트워크 트래픽을 측정하고 NetworkStatsManager 클래스에 메서드를 제공하여 해당 트래픽에 대해 쿼리함.
getMultipathPreference()도 네트워크 트래픽에 기반하여 값을 반환함. Android 9부터 이 메서드는 이동통신 데이터에 대해 true를 반환하지만 하루 일정 수준 이상 트래픽이 누적되면 false를 반환함.
ConnectivityManager.NetworkCallback 클래스는 VPN에 대한 정보를 앱에 전송함.
Apache HTTP 클라이언트 지원 중단
Android 6.0에서 Apache HTTP 클라이언트에 대한 지원이 제거됨.
Android 9부터는 이 라이브러리가 bootclasspath에서 제거되고 기본적으로 사용할 수 없음.
android:required="false" 특성은 23 이하 최소 SDK가 있는 앱에 필요함. API 레벨이 24보다 낮은 기기에서는 org.apache.http.legacy 라이브러리가 제공되지 않기 때문.
(이 기기에서는 Apache HTTP 클래스가 bootclasspath에서 제공됨)
앱에서 런타임 Apache 라이브러리를 사용하는 대신 APK에 org.apache.http 라이브러리의 자체 버전을 번들링 할 수 있음. 이 경우 런타임에서 제공되는 클래스와의 호환성 문제를 피하기 위해 Jar 유틸리티 등의 라이브러리로 리패키징 해야 함.
UI 변경사항
뷰 포커스
너비나 높이가 0인 뷰는 포커스가 불가능함.
터치모드에서는 액티비티가 초기 포커스를 암시적으로 할당하지 않으므로, 원할 경우 명시적으로 요청해야 함.
CSS RGBA 16진수 값 처리
Android 9 이상에서는 4자리 및 8자리 16진수 CSS 색상을 처리 지원함. (CSS 색상 모듈 레벨 4)
CSS 색상 모듈 레벨 4는 릴리즈 52 이후로 Chrome에서 지원되었지만 현재는 WebView에서 기능이 비활성화 되어있음.
ex) API 27이하 앱의 경우 #80ff8080 색상이 WebView에서 불투명 연적색(#ff8080)이지만 API 28 이상으로 타겟을 바꾸면 #80ff8080은 50% 투명한 연녹색(#80ff80)으로 해석됨.
문서 스크롤 요소
문서의 루트 요소가 스크롤 요소일 경우 적절히 처리함.
이전 버전에서는 스크롤 위치가 본문 요소에만 설정되었으며, 루트 요소는 스크롤 값 0이었음.
document.body.scrollTop, document.body.scrollLeft, document.documentElement.scrollTop 또는 document.documentElement.scrollLeft에 직접 액세스하는 동작이 대상 SDK에 따라 달라짐.
Android 9에서는 Java 언어의 UTF-8 디코더가 더욱 엄격하며 Unicode 표준을 따름.
유휴 앱의 경우 카메라, 마이크 및 센서에 대한 액세스 차단
앱이 유휴 상태인 경우 카메라, 마이크 또는 SensorManager 센서에 더 이상 액세스할 수 없음.
대상 버전 업데이트 및 Android P 기능 사용
targetSdkVersion 을 28로 업데이트하고 Android 9의 새 기능을 추가하여 지원하는 방법.
Android 9 SDK 가져오기
Android Studio 3.1 이상을 사용시 Android 9 앱 빌드를 위한 SDK 패키지를 받을 수 있고 새 기능은 필요없고 컴파일만 수행하려는 경우 사용 가능함.
Android Studio 3.2에서는 Android 9 기능을 완벽하게 지원함.
Android 9 앱 테스트
targetSdkVersion 이 28로 설정된 경우 앱에 영향을 미치는 아래 내용들을 검토함.
변경사항
요약
포그라운드 서비스 권한
포그라운드 서비스를 사용시 FOREGROUND_SERVICE 권한을 요청해야 함. 이 권한 없이 포그라운드 서비스를 시작하면 SecurityException이 발생.
Bouncy Castle 암호화 지원 중단
Android 9에서는 Bouncy Castle 제공자가 제공하는 여러 암호화가 지원 중단되고 Conscrypt 제공자가 제공하는 암호화가 대신 사용됨. Bouncy Castle 제공자를 요청하는 getInstance() 호출은 NoSuchAlgorithmException 오류를 생성함. 이 오류를 해결하려면 getInstance()에서 제공자를 지정하지 말아야 함.(즉, 기본 구현 요청).
Build.serial에 대한 직접 액세스 제거
Build.serial 식별자가 필요한 앱은 이제 READ_PHONE_STATE 권한을 요청한 다음 Android 9에 추가된 새 Build.getSerial() 메서드를 사용해야 함.
WebView 데이터 디렉토리의 공유 불가
앱이 더 이상 여러 프로세스에서 단일 WebView 데이터 디렉토리를 공유할 수 없음. 앱에 android.webkit 패키지의 WebView, CookieManager 또는 기타 API를 사용하는 프로세스가 2개 이상 있는 경우, 두 번째 프로세스에서 WebView 메서드를 호출하면 앱이 중단됨.
앱의 데이터 디렉토리에 대한 액세스가 SELinux에 의해 차단됨
시스템은 각 앱의 비공개 데이터 디렉토리에 대한 앱별 SELinux 제한과 함께 앱별 SELinux 샌드박스를 적용. 이제 경로를 통해 다른 앱의 데이터 디렉토리에 직접 액세스하는 것은 허용되지 않음. 앱이 FD 전달을 포함한 IPC 메커니즘을 사용하여 데이터를 계속 공유할 수도 있음.
아시아/하노이 시간대 인식 안됨. java.util.TimeZones.getAvailabeIds()는 값을 반환하지 않으며, java.util.TimeZone.getTimeZone()은 이를 인식 못함.
android.icu.text.NumberFormat.getInstance(ULocale, PLURALCURRENCYSTYLE).parse(String) 메서드의 경우 합법적 통화 텍스트를 파싱할 때도 ParseException 발생할 수 있음. 이 문제를 피하려면 스타일의 통화 텍스트에 NumberFormat.parseCurrency를 사용함. 이 메서드는 Android 7.0(API 24) 이후 버전에서 PLURALCURRENCYSTYLE을 사용할 수 있음.
Android 테스트 변경사항
프레임워크에서 라이브러리 제거
Android 9에서는 JUnit 기반 클래스를 android.test.base, android.test.runner, android.test.mock 세가지 라이브러리로 재 구성함.
테스트 모음 빌드 변경사함
TestSuiteBuilder 클래스의 addRequirements() 메서드가 제거되고 클래스가 지원 중단됨.
Java UTF 디코더
UTF-8은 Android 기본 문자 집합이며, UTF-8 바이트 시퀀스는 String 생성자에 의해 디코딩될 수 있음.
Android 9의 UTF-8 디코더는 이전보다 엄격하게 Unicode 표준을 준수함.
비최단(non-shortest) 형식의 UTF-8(예: <C0, AF>)은 잘못된 형식으로 간주됨.
대리(surrogate) 형식의 UTF-8(예: U+D800..U+DFFF)는 잘못된 형식으로 간주됨.
최대 서브파트는 단일 U+FFFD로 대체. 예를 들어, 바이트 시퀀스 "41 C0 AF 41 F4 80 80 41"에서 최대 서브파트는 "C0," "AF" 및 "F4 80 80". "F4 80 80"은 "F4 80 80 80"의 초기 서브시퀀스가 될 수 있지만, "C0"은 올바른 형식의 코드 단위 시퀀스의 초기 서브시퀀스가 될 수 없으므로 출력은 "A\ufffd\ufffdA\ufffdA"여야 함.
호스트 이름을 확인하기 위해 서버는 일치하는 SAN이 포함된 인증서를 제공해야 함. (CN을 사용한 대체 불가)
호스트 이름과 일치하지 않는 SAN이 포함된 인증서는 더 이상 신뢰할 수 없음.
네트워크 주소 조회시 네트워크 위반 발생 가능
이름 확인을 요구하는 네트워크 주소 조회에는 네트워크 I/O가 포함될 수 있으며 이 조회는 차단 작업으로 간주됨.
메인 스레드의 차단 작업은 일시 중지나 버벅거림 현상을 유발할 수 있음.
StrictMode 클래스는 개발자가 코드에서 문제를 감지하도록 돕는 개발도구.
Android 9 이상에서 StrictMode는 이름 확인을 요구하는 네트워크 주소 조회로부터 발생하는 네트워크 위반을 감지함.
StrictMode를 활성화한 상태로 앱을 출시하면 안됨.
숫자 IP 주소 확인은 차단 작업으로 간주되지 않음.
소켓 태그 지정
기존 Android에서는 setThreadStatsTag()메서드를 사용하여 소켓에 태그를 다는 경우 바인더 IPC를 ParcelFileDescriptor컨테이너와 함께 사용하여 또 다른 프로세스로 전송시 이 소켓의 태그가 해제됨.
Android 9 이상에서는 바인더 IPC 사용하여 또 다른 프로세스로 전송시 소켓 태그가 유지됨.
이러한 변경은 네트워크 트랙픽 통계에 영향을 미칠 수 있음. (queryDetailsforUidTag() 메서드 사용시)
다른 프로세스로 전송한 소켓의 태그를 제거하고 싶다면 untagSocket()을 호출.
소켓에서 사용 가능한 바이트 크기가 보고됨
shutdownInput() 메서드를 호출한 다음 available() 메서드를 호출하면 0이 반환됨.
xt_qtaguid 폴더의 파일을 더 이상 앱에 사용 불가함
Android 9부터는 앱에서 /porc/net/xt_qtaguid 폴더에 있는 파일을 직접 읽을 수 없음.
이러한 파일을 사용하는 공개 API는 계속 작동함. (TrafficStats, NetworkStatsManager 등)
qtaguid_tagSocket() 같은 지원되지 않는 cutils 함수는 작동하지 않을 수 있음.
FLAG_ACTIVITY_NEW_TASK 요구사항 적용됨.
Android 9에서는 인텐트 플래그 FLAG_ACTIVITY_NEW_TASK를 전달하지 않을 경우 비 액티비티 컨텍스트에서 액티비티를 시작할 수 없음.
이 플래그를 전달하지 않고 액티비티를 시작하려고 하면 액티비티가 시작되지 않고, 시스템이 로그 출력함.
참고 : Android 7.0(API 24) 이전 버전부터 적용되었으나 Android 7.0 버그로 인해 적용되지 않았음.
화면 회전 변경사항
Android 9 부터 세로 회전모드가 회전 잠금으로 변경되었고 이 모드는 자동 회전이 꺼진 경우 활성화됨.
기존에는 자동 회전 및 세로 회전 모드 였으며, 자동 회전 모드에는 변화 없음.
특정 방향을 요청하는 Activity(screenOrientation=landscape같은) 는 사용자 잠금 기본설정을 무시하고 동작됨.
화면 방향
동작
unspecified, user
자동 회전 및 회전 잠금 모드에서 Activity가 세로 모드 또는 가로 모드(및 반전)로 렌더링될 수 있습니다. 세로 모드 및 가로 모드 레이아웃을 모두 지원할 것으로 예상됩니다.
userLandscape
자동 회전 및 회전 잠금 모드에서 Activity가 가로 모드 또는 반전 가로 모드로 렌더링될 수 있습니다. 가로 모드 레이아웃만을 지원할 것으로 예상됩니다.
userPortrait
자동 회전 및 회전 잠금 모드에서 Activity가 세로 모드 또는 반전 세로 모드로 렌더링될 수 있습니다. 세로 모드 레이아웃만을 지원할 것으로 예상됩니다.
fullUser
자동 회전 및 회전 잠금 모드에서 Activity가 세로 모드 또는 가로 모드(및 반전)로 렌더링될 수 있습니다. 세로 모드 및 가로 모드 레이아웃을 모두 지원할 것으로 예상됩니다. 회전 잠금 모드 사용자에게는 반전 세로 모드(대개 180º 반전)로 잠글 수 있는 옵션이 제공됩니다.
HDR VP9 프로파일 2 지원, HEIF 이미지 인코딩 추가, MediaDRM/AAudio/AudioEffect 기능 추가
JobScheduler 네트워크 관련 기능 강화
Neural Networks API 1.1 확장 및 개선
자동 완성 프레임워크 개선
보안 강화 및 기능 추가
앱 내 중요한 의사 확인용 Android Protected Confirmation 추가
통합 생체 인식 다이얼로그 지원
HW 모듈인 StrongBox Keymaster 지원
Keystore로 키 가져오기 보홈
키 순환을 포함한 APK 서명 지원
잠금 해제된 장치에서만 키 암호 해독을 허용하는 옵션 추가
Triple Data Encryption Algorithm(Triple DEA) 지원
클라이언트 쪽 암호화된 백업 지원, 백업을 위한 기기 컨디션 지정
클라이언트 측 암호화 백업 및 백업에 필요한 기기 조건 정의 추가
접근성 관련 기능 추가 및 향상
탐색 의미 체계
접근성 창 제목
제목 기반 탐색
그룹 탐색 및 출력
도움말과 전역 작업 등 추가된 편의 작업
창 변경 세부 정보
회전을 고정 및 수동으로 제어할 수 있는 기능 추가(시스템바 버튼)
텍스트 관련하여 렌더링 개선, 돋보기, Smart Linkify 등의 기능을 플랫폼에서 지원
Wi-Fi RTT를 이용한 실내 위치추적
Android 9에서는 Wi-Fi Round-Trip-Time(RTT-) 로 알려진 IEEE 802.11mc Wi-Fi 프로토콜 지원.
앱에서 실내 위치 추적에 활용 가능.
하드웨어 지원이 되는 Android 9 기기는 RTT API를 사용하여 인근한 RTT 가능 Wi-Fi AP 까지의 거리를 측정할 수 있음. (위치 서비스 사용 설정되어 있어야 하고 앱에서 ACCESS_FINE_LOCATION 권한 필요)
RTT를 사용하기 위해 AP와 연결할 필요 없음. 기기만 AP와 거리를 측정할 뿐 AP에는 정보가 없음.
3개 이상의 AP의 거리를 측정하는 경우 약 1~2미터 내의 오차로 기기 위치를 측정할 수 있음.
이런 정확도를 이용하여 건물 내 탐색 및 미세 위치 기반 서비스 등의 새로운 경험 구현 가능함.
디스플레이 컷아웃 지원
Android 9에서는 카메라와 스피커를 위한 디스플레이 컷아웃이 포함된 edge-to-edge 스크린 지원함.
DisplayCutout 클래스를 사용하여 내용을 표시하지 않는 영역의 위치와 모양을 찾을 수 있음.
새 윈도우 레이아웃 속성인 layoutInDisplayCutoutMode 를 사용하여 기기 컷아웃 주변의 콘텐츠를 배치할 수 있음.
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
개발자 옵션에서 디스플레이 컷아웃 시뮬레이션 사용 가능.
Developer options -> Drawing -> Simulate a display with a cutout
알림
향상된 메시지 환경
Android 7.0 (API 24)부터 메시지에 회신하거나 알림에서 직접 텍스트 입력이 가능했음.
Android 9는 다음 기능을 통해 기능을 향상시킴.
단순화된 대화 참여자 지원 : Person 클래스는 대화 참여자 식별에 쓰임. addMessage()와 같은 다른 많은 API는 이제 CharSequence 대신 Person 클래스 사용함. Person 클래스는 Builder 패턴도 지원함.
이미지 지원 : 메시징 알림에 이미지 표시함. 메시지에서 setData()를 사용하여 이미지 표시 가능
// Create new Person.Person sender =newPerson()
.setName(name)
.setUri(uri)
.setIcon(null)
.build();
// Create image message.Message message =newMessage("Picture", time, sender)
.setData("image/", imageUri);
Notification.MessagingStyle style =newNotification.MessagingStyle(getUser())
.addMessage("Check this out!", 0, sender)
.addMessage(message);
초안같은 응답들 저장 : 사용자가 우연히 메시징 알림을 닫으면 앱에서 EXTRA_REMOTE_INPUT_DRAFT를 검색할 수 있음. 이 기능을 사용하여 사용자가 답장을 완료할 수 있도록 앱의 텍스트를 미리 채울 수 있음.
그룹대화 식별자 : setGroupConversation()을 사용하여 대화가 그룹인지 식별할 수 있음.
인텐트를 위한 의미론적 동작을 설정 : setSemanticAction() 메서드를 사용하면 mark as read, delete, reply 같은 의미론적인 의미를 가진 동작을 부여할 수 있음.
스마트 응답 : 메시징 앱에서 RemoteInput.setChoices() 를 사용하여 일련의 표준 응답을 제공할 수 있음.
채널 설정, 브로드캐스트 및 알림 일시중지
Android 8.0 에서 알림 채널이 도입되어 각 알림 유형에 대해 사용자가 맞춤 설정할 수 있는 채널을 만들 수 있음.
Android 9에서는 이러한 변경을 통해 알림 채널 설정을 단순화함.
채널 그룹 차단 : 사용자는 앱의 알림 설정에서 전체 채널 그룹을 차단할 수 있음. isBlocked() 메서드로 식별할 수 있으며, 이 경우 이 그룹에 있는 채널에는 어떤 알림도 보내지 않음. 앱에서는 getNotificationChannelGroup() 메서드를 사용해 현재 채널 그룹 설정을 쿼리할 수 있음.
새로운 브로드캐스트 인텐트 타입 : Android 시스템은 이제 알림 채널 및 채널 그룹의 차단 상태가 변경되면 브로드캐스트 인텐트를 보냄. 차단된 채널 또는 그룹을 소유한 앱은 이러한 인텐트를 받아 대응할 수 있음.
NotificationManager.Policy에는 3가지 Do-Not-Disturb 우선순위 카테고리가 있음.
PRIORITY_CATEGORY_ALARMS : 알람의 우선시 함.
PRIORITY_CATEGORY_MEDIA : 미디어 및 음성 탐색과 같은 미디어 소스의 사운드를 우선시 함.
PRIORITY_CATEGORY_SYSTEM : 시스템 사운드 우선시 함.
NotificationManager.Policy에는 시각적 반응을 막는 7가지 Do-Not-Disturb 상수가 있음.
알련진 이슈 : ANEURALNETWORKS_TENSOR_QUANT8_ASYMM 텐서를 Android 9 이상에서 사용할 수있는 ANEURALNETWORKS_PAD 작업에 전달하면 NNAPI의 출력이 TensorFlow Lite와 같은 상위 수준 머신러닝 프레임워크의 결과와 일치하지 않을 수 있음. 문제가 해결 될 때까지 ANEURALNETWORKS_TENSOR_FLOAT32만 전달해야 함.
ANEURALNETWORKS_TENSOR_FLOAT32를 IEEE 754 16 비트 부동 소수점 형식의 범위와 정밀도로 계산할지 여부를 지정할 수있는ANeuralNetworksModel_relaxComputationFloat32toFloat16()이 API에 새 기능으로 추가됨.
자동 완성 프레임워크
폼 작성시 사용자 경험을 향상시키기 위해 자동완성 서비스가 구현할 수 있는 여러 개선사항이 소개됨.
보안기능 향상
아래와 같은 보안 기능이 도입됨.
Android Protected Confirmation
Android 9 이상을 실행하는 지원 기기는 Android Protected Confirmation을 사용할 수 있는 기능을 제공함.
이 워크플로를 사용시 앱은 사용자에게 짧은 성명서를 승인할 것인지 묻는 메시지를 표시함.
이 성명서를 통해 앱에서 사용자가 결제와 같이 중요한 거래를 완료하기를 원하는지를 재확인할 수 있음.
만약 사용자가 성명서를 수락하면 Android Keysotre는 HMAC(Keyed-Hash Message Authentication Code)로 보호되는 암호화 서명을 받아서 저장함. Android Keystore가 메시지의 유효성을 확인한 후 앱은 신뢰할 수 있는 실행 환경(trusted execution environment, TEE)의 trustedConfirmationRequired에서 생성된 키를 사용하여 사용자가 수락한 메시지에 서명할 수 있음. 서명은 매우 높은 신뢰성으로 사용자가 성명서를 보았고 그것에 동의했음을 나타냄.
주의 : Android Protected Confirmation은 사용자에게 보안 정보 채널을 제공하지 않음. 앱은 Android 플랫폼이 제공하는 것 이상의 기밀유지 보장을 할 수 없음. 특히, 이 워크플로를 사용하여 사용자 기기에 일반적으로 표시하지 않는 중요 정보를 표시하지 말아야 함.
통합 생체인식 인증 다이얼로그
Android 9에서는 시스템이 앱 대신 생체 인식 다이얼로그를 제공함.
이 기능은 표준화된 모양, 느낌 그리고 다이얼로그 위치를 생성하여 사용자가 신뢰할 수 있는 생체 인식 검사기에 대해 인증하고 있다는 확신을 줌.
앱이 FingerprintManager를 사용하여 사용자에게 지문인식 다이얼로그를 표시하는 경우 BiometricPrompt를 사용하도록 대신함. BiometricPrompt는 시스템에 의해 인증 다이얼로그를 표시함. 또한 사용자가 선택한 생체 인식 타입에 맞게 동작을 변경함.
참고 : 앱에서 BiometricPrompt를 사용하기 전에 hasSystemFeature() 메소드를 사용하여 기기가 FEATURE_FINGERPRINT, FEATURE_IRIS 또는 FEATURE_FACE를 지원하는지 확인해야 함.
기기가 생체 인증을 지원하지 않는다면, createConfirmDeviceCredentialIntent() 메소드를 사용함으로써 사용자의 PIN, 패턴 또는 비번을 확인할 수 있음.
하드웨어 보안 모듈
Android 9 이상이 동작하는 지원 기기에서는 하드웨어 보안 모듈에 있는 (Keymaster HAL 구현체인) StrongBox Keymaster가 있을 수 있음. 모듈에는 다음이 포함됨.
자체 CPU
안전한 저장장치
순수 난수 생성기
패키지 변조 그리고 앱의 권한 없는 사이드 로딩을 예방할 수 있는 매커니즘
StrongBox Keymaster에 저장된 키를 확인할 때 시스템은 신뢰할 수 있는 실행 환경(TEE)에서 키의 무결성으로 확증함.
Keystore로 키 가져오기 보호
Android 9은 ASN.1로 인코딩된 키 형식을 사용하여 함호화된 키를 Keystore로 안전하게 가져오는 기능을 추가함.
Keymaster가 Keystore에 있는 키를 암호화 해제하므로, 키의 내용이 결코 기기의 호스트 메모리에 일반 텍스트로 나타나지 않음.
참고 : 이 기능은 Keymaster 4 이상과 함께 제공되는 기기에서만 지원함.
키 순환을 포함한 APK 서명 구성표
APK 서명 스킴 v3 지원이 추가됨.
이 스킴에서는 각 서명 인증서의 서명 블록에 순환 증명 레코드를 포함할 수 있는 옵션이 있음.
이 기능은 APK 파일의 과거 서명 인증서를 현재 서명된 것에 연결하여 앱에 새 서명 인증서로 서명이 가능함.
참고 : Android 8.1(API 27) 이하 기기에서는 서명 인증서 변경을 지원하지 않음.
앱의 최소 SDK 버전이 27 이하인 경우 이전 서명 인증서를 사용하여 새 서명으로 앱에 서명해야 함.
잠금 해제된 기기에서만 키 복호화를 허용하는 옵션
Android 9에서는 unlockedDeviceRequired 플래그가 도입됨.
이 옵션은 키를 사용하여 사용 중인 데이터나 저장된 데이터의 암호 복호화를 허용하기 전에 키 저장소에서 화면의 잠금을 해제해야 하는지 여부를 결정함.
이러한 유형의 키는 상태 데이터 또는 기업 데이터와 같이 중요한 데이터를 디스크에 저장하기 위해 암호화하는데 적합함.
이 플래그는 사용자가 폰을 분실하거나 도난당한 경우 장치가 잠긴 동안엔 데이터를 복호화할 수 없다는 높은 확신을 제공함.
참고 : unlockedDeviceRequired 플래그가 활성화되어 있다면 암호화와 서명 확인이 언제든지 발생할 수 있음.
이 플래그는 장치가 잠금 해제될 때 데이터의 복호화만 방지함.
장치가 잠긴 상태에서 키를 안전하게 해독하려면 setUnlockedDeviceRequired() 메서드에 true를 전달하여 플래그를 활성화시킴.
이 단계 완료 후 사용자의 화면이 잠길 때 데이터의 암호를 해독하거나 서명하려는 모든 시도가 실패함.
잠긴 기기는 액세스하기 전에 PIN, 암호, 지문 또는 다른 신뢰할 수 있는 것이 필요함.
레거시 암호화 지원
Keymaster 4가 실린 기기는 Triple Data Encryption Algorithm(Triple DES)이 지원됨.
앱이 Triple DES가 필요한 레거시 시스템과 상호 운용되는 경우 민간함 자격 증명을 암호화할 때 이 유형의 암호를 사용.
Android 백업
백업과 복원과 관련된 새 기능과 개발자 옵션 추가됨.
클라이언트 측 암호화 백업
클라이언트 측 비밀로 안드로이드 백업 암호화를 지원.
다음의 조건이 충족시 자동으로 사용됨.
사용자가 Android 9 이상을 사용하여 백업을 활성화함.
사용자가 잠금을 해제하기 위해 PIN, 패턴, 암호가 필요한 기기의 화면 잠금을 설정함.
이 개인 정보 보호 수단을 활성화하면 사용자의 기기에서 만든 백업에서 데이터를 복원을 위해 기기의 PIN, 패턴, 암호가 필요함.
백업에 필요한 기기 조건 정의
앱 데이터에 민감한 정보나 환경 설정이 포함시, 사용자의 백업이 포함된 앱의 데이터 아래 기기 컨디션을 정의할 수 있음. (예를 들어 클라이언트측 암호화가 활성화 되어있는거나 로컬 기기에서 기기로 전송이 일어나는 것같은)
접근성
탐색 의미 체계
Android 9에는 접근성 서비스, 특히 스크린 리더가 화면의 한 부분에서 다른 곳으로 이동하는 방법에 대해서 쉽게 정의하는 속성 추가. 이 속성은 시각 장애가 있는 사용자가 빠르게 앱 UI의 텍스트를 빠르게 이동하고 선택하는 것을 도와줌.
ex) 쇼핑 앱에서 스크린 리더가 모든 항목을 읽지 않아도 다음 카테고리로 바로 이동할 수 있도록 도와줌.
접근성 창 제목
Android 8.1 (API 27) 이하에서는 접근성 서비스가 화면의 특정 창을 업데이트한 시점을 항상 결정할 수 있지 않음.
(Activity가 Fragment를 바꿀 때와 같은 경우)
창은 논리적 그룹으로 이루어졌고 시각적으로 관계된 UI 요소로 구성됨.
Android 9에서는 접근성 창 제목 또는 개별적으로 식별 가능한 제목을 제공할 수 있음.
창에 액세스 가능한 창 제목이 있을 경우 접근성 서비스가 창 변화시 보다 자세한 정보를 받음.
이 기능을 통해 서비스는 UI에서 무엇이 변경되었는지에 대한 보다 세분화된 정보를 제공받음.
창 제목을 지정하려면 android:accessibilityPaneTitle 속성을 사용.
setAccessibilityPaneTitle() 을 사용하여 런타임에서 바뀌는 UI 창의 제목을 업데이트할 수 있음.
(예를 들어 Fragment 객체의 콘텐츠 영역에 제목을 제공할 수 있음)
제목 기반의 탐색
앱이 논리적 표제를 포함한 텍스트 콘텐츠를 표시하는 경우, 해당 View 인스턴스의 android:accessibilityHeading 속성을 true로 설정.
이 표제들을 추가하면 사용자가 다음 표제로 직접 이동할 수 있는 접근성 서비스가 허용됨.
모든 접근성 서비스는 이 기능을 사용하여 사용자의 UI 탐색 경험을 향상시킬 수 있음.
그룹 탐색 및 출력
스크린 리더는 보통 android:focusable 속성을 사용하여 ViewGroup 또는 View 객체의 모음을 단일 유닛으로 읽어야 하는 시점을 판별해옴. 사용자는 뷰가 서로 논리적으로 관련되어 있음을 이해할 수 잇었음.
Android 8.1 이하에서는 ViewGroup 내에 있는 각 View 객체를 포커스 가능하지 않은 것으로 표시하고, ViewGroup 자체는 포커스 가능한 것으로 표시해야 함. 이러한 배치에서는 View 의 일부 인스턴스가 `포커스 가능`으로 표시되었으며, 이로 인해 키보드 탐색이 더욱 번거롭게 됨.
Android 9부터는 View 객체를 `포커스 가능`으로 만들 경우 원치 않는 결과가 나올수 있는 상황에서 android:focusable 속성 대신 android:screenReaderFocusable 속성을 사용. 스크린 리더는 android:screenReaderFocusable 나 android:focusable을 true로 설정한 모든 요소에 포커스를 둠.
편의 작업
Android 9에서는 사용자를 대신해 편의 작업을 수행하기 위한 지원이 추가됨.
도움말과의 상호작용
접근성 프레임워크에 추가된 기능을 사용하여 앱UI의 도움말에 액세스할 수 있음.
도움말 텍스트를 읽으려면 getTooltipText()를 사용.
View 인스턴스에 지시하려면 ACTION_SHOW_TOOLTIP 및 ACTION_HIDE_TOOLTIP을 사용
추가된 전역 작업
Android 9에서는 AccessibilityService 클래스에서 ㄷ 가지 추가 기기 작업을 위한 지원이 제공됨.
서비스에서 사용자가 각각 GLOBAL_ACTION_LOCK_SCREEN 및 GLOBAL_ACTION_TAKE_SCREENSHOT 액션을 사용하여 기기를 잠그고 스크린 샷을 찍을 수 있음.
창 변경 세부정보
Android 9에서는 앱이 여러 창을 동시에 다시 그릴때 업데이트를 더욱 쉽게 추적할 수 있음.
TYPE_WINDOWS_CHANGED 이벤트가 발생하는 경우, getWindowChanges() API를 사용하여 창이 어떻게 변경되었는지 판별할 수 있음.
여러 창이 업데이트 되는 경우 각 창은 자체 이벤트 집합을 생성함.
getSource() 메서드는 각 이벤트와 관련된 창의 루트 뷰를 반환함.
앱에서 View 객체에 대해 접근성 창 제목을 정의한 경우 서비스는 앱 UI가 언제 업데이트 되는지 식별할 수 있음.
TYPE_WINDOW_STATE_CHANGED 이벤트가 발생하는 경우, getContentChangeTypes() 에 의해 반환되는 유형을 사용하여 창이 어떻게 변경되었는지 판별할수 있음.
ex) 프레임워크에서 창에 새로운 제목이 있거나 창에 새로운 제목이 있거나 창이 사라진 경우를 감지할 수 있음.
회전
원치 않는 회전을 없애기 위해 기기 위치가 바뀌더라도 방향이 고정되는 모드를 추가함.
필요시 사용자가 시스템 바의 버튼을 눌러 수동으로 회전을 트리거할 수 있음.
앱에 대한 호환성의 영향은 대부분 최소한임.
그러나 사용자 회전 기본설정이 항상 세로모드로 설정된 경우 앱에 맞춤형 회전 동작이 있거나 이상한 화면 방향 설정이 사용된다면 새로운 문제가 발생할 수도 있음.
권장하는 방법은 앱의 모든 주요 액티비티에서 회전 동작을 살펴보고 확인하는 것임.
텍스트
Android 9 은 다음과 같은 텍스트 관련 기능을 플랫폼으로 가져옴.
Precomputed Text : PrecomputedText 클래스는 보다 빨리 필요한 정보를 계산하고 캐시할 수 있게 함으로써 텍스트 렌더링 성능을 향상시킴. 이 클래스를 사용하면 앱이 메인 스레드를 벗어나 텍스트 레이아웃을 수행하도록 할 수 잇음.
Magnifier : Magnifier 클래스는 돋보기 API를 제공하는 플랫폼 위젯으로 모든 앱에서 일관된 돋보기 기능을 사용할 수 있게 해줌.
Smart Linkify : Android 9 에서는 TextClassifier 클래스가 머신러닝을 활용하여 선택된 텍스트에서 엔티티를 식별하고 액션을 제안하도록 개선됨. TextClassifier의 기능은 Linkify 클래스의 기능을 대체함. ex) 사용자가 전화 번호를 선택했다는 사실을 앱이 알아차릴 수 있음.
Text Layout : 여러가지 메서드와 속성으로 UI 디자인을 더 쉽게 구현할 수 있음. TextView 참조문서 참고.
DEX 파일의 ART AOT(Ahead-Of-Time) 변환
Android 9 이상이 실행되는 기기에서는 ART(Android RunTime) AOT(ahead-of-time) 컴파일러가 앱 패키지에 잇는 DEX(Dalvik Executable) 파일을 더 콤팩트한 표시로 변환하여 압축된 DEX 형식 파일로 더욱 최적화함.
앱이 더 빠르게 시작하고 디스크 공간과 RAM을 덜 소비하게 됨.
특히 디스트 I/O 속도가 느린 저사양 기기에 도움이 됨.
온디바이스 시스템 추적
Android 9 에서는 기기에서 시스템 트레이스를 기록 후 이 기록에 대한 보고서를 개발팀과 공유할 수 있음.
이 보고서는 HTML 을 비롯한 여러 형식을 지원함.
이런 트레이스를 수집함으로써 앱의 프로세스 및 스레드와 관련된 타이밍 데이터를 캡처하고 전체적으로 중요한 다른 유형의 기기 상태도 불 수 있음.
참고 : 트레이스를 기록하기 위해 코드를 계측할 필요는 없지만, 이를 실행해보면 앱 코드의 어떤 부분이 스레드 장애 또는 UI 버벅거림의 원인이 될지 파악하는데 도움이 될 수 있음.