본문 바로가기
깡샘 코틀린

10-1 API 레벨 호환성 고려하기

by 농농씨 2023. 6. 24.

06~10장까지 앱의 기본 기능을 구현하는 방법을 공부하고 있다.

10장에서는 사용자 알림과 API 레벨 호환성, 퍼미션을 살펴볼 것이다.

오늘도 열심히 해봅시다~

 

02장에서 build.gradle 파일을 설명하면서 SDK 버전을 설정하는 targetSdkminSdk에 관해 살펴봤다. 두 항목에 설정하는 값은 API 레벨을 의미하며 앱 개발에 큰 영향을 주는 중요한 정보이다. 

// API 레벨 설정
minSdk 21
targetSdk 31

만약 위와 같이 설정했다면 targetSdk에 설정한 31 버전의 API로 앱을 개발한다는 의미이다. 그런데 minSdk를 21로 지정했으므로 이 앱은 21버전(안드로이드 5.0 롤리팝) 기기부터 설치할 수 있다. 결국 이 앱은 31버전의 API로 개발하지만 21 버전 기기에서도 오류가 발생하지 않고 동작해야 한다

따라서 앱을 개발할 때 minSdk 설정값보다 상위 버전에서 제공하는 API를 사용한다면 호환성(compatibility)을 고려해야 한다. 예를 들어 안드로이드 API 문서(developer.android.com/reference)에서 Notification이라는 클래스를 찾으면 클래스 이름 위에 'Added in API Level 1'이라고 표시되어 있다. 이는 이 클래스가 API 레벨 1에 추가되었다는 것을 나타낸다. 따라서 이 클래스는 minSdk를 21로 설정한 앱에서 API 레벨 호환성 문제가 발생하지 않는다.

API 레벨 1에 추가된 클래스 예시

그런데 Notification.CallStyle 이라는 클래스는 API 레벨이 31이다. 즉, 31버전에서 추가된 클래스라는 의미이다. 이 클래스는 31버전 하위에서는 제공하지 않으므로 이 클래스를 사용해 앱을 개발하면 31 버전 하위 기기에서 오류가 생긴다.

즉, 사용할 API가 추가된 상위 버전에서는 문제가 없지만 하위 버전에서는 오류가 발생한다. 이처럼 API 레벨 호환성 문제가 발생하는 클래스나 함수를 사용하면 안드로이드 스튜디오에서 경고나 오류 메시지를 표시한다.

ex. Call requires API level S(current min is 21):android.app.Notification.CallStyle#forIncomingCall

Cast from CallStyle to Style requires API level 31 (current min is 21)

메시지를 보면 앱의 minSdk가 21로 지정되었으므로 Notification.CallStyle 클래스를 사용하면 문제가 발생한다는 의미이다. 이처럼 API 레벨 호환성에 문제가 있는 API를 사용할 때는 @기호로 시작하는 애너테이션(annotation)을 추가해 오류를 해결할 수 있다.

// API 호환성 애너테이션 1
@RequiresApi(Build.VERSION_CODES.S) // 호환성 문제 해결 위해 애너테이션 추가함
fun noti() {
	(...생략...)
    val builder: Notification.Builder = Notification.Builder(this, "1")
    	.setStyle(
        	Notification.CallStyle.forIncomingCall(caller, declineIntent, answerIntent)
        )
    (...생략...)
}

API 레벨 호환성에 문제가 있는 API를 사용한 함수나 클래스 선언부 위에 @RequiresApi 애너테이션을 추가하면 안드로이드 스튜디오에서 오류가 발생하지 않습니다. @RequiresApi 애너테이션 대신 @TargetApi 애너테이션을 이용해도 된다. 

// API 호환성 애너테이션 2
@TargetApi(Build.VERSION_CODES.S) // @RequiresApi()대신 @TargeApi()를 애너테이션으로 사용
fun noti() {
	(...생략...)
    val builder: Notification.Builder = Notification.Builder(this, "1")
    	.setStyle(
        	Notification.CallStyle.forIncomingCall(caller, declineIntent, answerIntent)
        )
    (...생략...)
}

(둘은 무슨차이일까?)

그런데 API 호환성 애너테이션은 안드로이드 스튜디오에서 오류를 무시하는 설정일 뿐이며 앱이 실행될 때 API 레벨 호환성 문제를 막으려면 직접 코드로 처리해줘야 한다. 예를 들어 Notification.CallStyle 클래스는 다음처럼 S 버전에서만 실행되게 할 수 있다.

// API 레벨 30 이상에서만 addCallback() 함수 실행
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){ // 주목!
	val builder: Notification.Builder = Notification.Builder(this, "1")
    	.setStyle(
        	Notification.CallStyle.forIncomingCall(caller, declineIntent, answerIntent)
        )
}

참고로 주목!은 책에 노란줄이 쳐져있는데 내가 설명하기 힘들 때 쓴다.

Build.VERSION.SDK_INT앱이 실행되는 기기의 API레벨이다. if 문에서 이 값을 이용해 특정 버전에서만 실행하도록 작성할 수 있다.

❓앱을 개발할 때 minSdk보다 하위 버전에 추가된 API만 이용하면 문제가 없는 거 아닌가요? 즉, 최신 API 레벨에 추가된 API를 사용하지 않으면 되잖아요?

❗️minSdk보다 하위 버전에 추가된 API만으로 앱을 개발하면 최신 기능이나 화면을 사용할 수 없어 시대에 뒤떨어질 수 있다.

또, 어떤 API는 사용하지 않으면 상위 버전 기기에서 오류가 발생하기도 해서 앱을 개발할 때 최신 기기를 무시할 수 없으므로 이때는 해당 API를 꼭 사용해야 한다. 그런데 또 최신 API를 사용하면 하위 버전에서 오류가 발생한다. 결국 새로운 API를 적용해 앱을 개발하되 API 레벨 호환성을 고려할 수밖에 없다.

'깡샘 코틀린' 카테고리의 다른 글

10-3 다양한 다이얼로그  (0) 2023.06.24
10-2 퍼미션 설정하기  (0) 2023.06.24
09-3 폰 크기의 호환성  (0) 2023.06.23
09-2 리소스 조건 설정  (0) 2023.06.23
09-1 리소스의 종류와 특징  (0) 2023.06.23