Engineering note · Android

안드로이드 SDK 15 (Target 35) 업데이트 대응 및 Edge-to-Edge UI, IME 인셋 처리

2025년 07월 02일이현수
태그androidkotlinwebview

안드로이드 15 (Target SDK 35) 업데이트 시 필수적으로 알아야 할 변경 사항과 Edge-to-Edge UI 강제화로 인해 발생하는 하이브리드 웹뷰 키보드 가림 버그 및 인셋 처리 해결책을 공유한다.

구글 플레이 스토어 배포 규격에 따라 targetSdkVersion을 35(안드로이드 15)로 설정하면 운영체제 수준에서 시스템 동작 및 UI 정책이 크게 변경된다. 특히 기존 레이아웃 구성을 흔드는 화면 전체 렌더링 강제화 정책은 하이브리드 웹뷰 앱 등에서 다양한 오동작을 일으킬 수 있다.

타겟 SDK 35 이상 앱의 주요 변경 사항

빌드 타겟 버전을 35 이상으로 올리면 다음 규칙들이 적용되므로, 영향 범위가 넓은 요소들을 점검해야 한다.

  • OpenJDK 17 마이그레이션: 안드로이드 15의 코어 런타임이 OpenJDK 17을 기반으로 하므로 관련 코어 자바/코틀린 API 를 확인해야 함
  • 정확한 알람 권한 제한 (USE_EXACT_ALARM): 백그라운드 스케줄링 등에 쓰이는 정확한 알람을 구성하려면 명시적인 승인을 얻도록 정책이 엄격화
  • 포그라운드 서비스 유형 명시 선언 필수: AndroidManifest.xml 내에 포그라운드 서비스의 유형(dataSync, mediaProcessing 등)을 선언하지 않으면 런타임 차단이 발생한다.
  • TextView elegantTextHeight 기본값 변환: 한글이나 아랍어 등 획이 크고 복잡한 문자열의 가독성을 높이기 위해 세로 폰트 크기가 자동 확장되는데, 이로 인해 텍스트 영역 레이아웃이 미세하게 뒤틀릴 수 있음
  • Edge-to-Edge UI 기본 강제 적용: 가장 눈에 띄는 변화로, 앱 화면 전체를 상하단 시스템 바(상태바 및 소프트웨어 내비게이션 바) 영역까지 전부 덮어버리는 레이아웃 전체 렌더링 모드가 기본으로 사용됨

안드로이드 스튜디오의 Tools -> Android SDK Upgrade Assistant 기능을 활용하면 프로젝트 마이그레이션 단계에서 권장되는 체크리스트 가이드를 참고하여 도움을 받을 수 있다.

Edge-to-Edge UI와 인셋의 이해

Edge-to-Edge 모드가 켜지면 상태바나 기기 내비게이션 바가 반투명 또는 완전히 투명해지면서 앱 콘텐츠가 덮힌다. 이를 제어하는 핵심 개념이 인셋 (Inset) 이다. Inset은 화면의 특정 영역이 시스템 UI(상태 바, 내비게이션 바)와 교차하는 부분을 나타낸다. 콘텐츠가 가려지는 것을 막기 위해 최상위 루트 뷰 컨테이너에 인셋의 물리 픽셀 크기만큼 패딩을 계산하여 적용해주어야 한다.

kotlin
// Activity onCreate 시점 적용 예시
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val rootView = findViewById<View>(R.id.rootView)  
    
    ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, insets ->  
        // 상태 표시줄, 내비게이션 바의 크기 픽셀 정보 수집
        val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())  
    
        // 수집한 크기만큼 패딩을 동적으로 적용하여 시스템 바 영역과 콘텐츠 분리
        view.updatePadding(  
            left = systemBars.left,  
            top = systemBars.top,  
            right = systemBars.right,  
            bottom = systemBars.bottom  
        )  
    
        // 처리 완료 표시 반환
        WindowInsetsCompat.CONSUMED  
    }
}

웹뷰 소프트 키보드 가림 현상 해결

타겟 SDK 35 전환 후 하이브리드 웹뷰 Input 포커싱 시, 키보드가 입력 창을 완전히 덮어버려 사용자가 입력값을 알 수 없는 상황이 발생했다.

오동작의 근본 원인 분석

기본적으로 웹뷰는 키보드가 열릴 때 adjustPan 방식으로 작동해 레이아웃 조정 없이 뷰가 화면 밖으로만 쏠리곤 한다. android:windowSoftInputMode="adjustResize" 속성을 추가하여 키보드가 띄워질 때 액티비티 전체 뷰 크기를 압축하여 상단으로 밀려 올라오게 만들어 주는 것이 기본 정석이다.

그러나 Edge-to-Edge 대응을 위해 인셋 리스너의 패딩 업데이트(view.updatePadding) 로직을 추가하며 문제가 발생했다. 시스템 인셋 패딩 조절 요청이 adjustResize 동작보다 더 높은 우선순위로 동작해서, 키보드가 상승해도 bottom 패딩이 시스템 내비게이션 바 고정 높이에 묶여버린 것. 뷰의 높이를 줄여주지 못해 레이아웃 리사이징이 막힌 것이다.

동적 인셋 병합 해결책

이 문제를 해결하기 위해 시스템 바 인셋 리스너 내부에서 기기 소프트 키보드에 해당하는 IME 인셋 크기(WindowInsetsCompat.Type.ime())까지 연계하여 bottom 패딩을 동적으로 연산하도록 Kotlin 코드를 개선했다.

xml
<activity
    android:windowSoftInputMode="adjustResize">

액티비티에 android:windowSoftInputMode="adjustResize" 추가.

kotlin
ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, insets ->
    val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
    // 키보드 인셋 감지
    val imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime())

    view.updatePadding(
        left = systemBars.left,
        top = systemBars.top,
        right = systemBars.right,
        // 키보드가 켜졌을 때는 키보드 높이를, 꺼졌을 때는 기본 네비게이션 바 높이를 유연하게 선택 적용
        bottom = maxOf(systemBars.bottom, imeInsets.bottom)
    )
    WindowInsetsCompat.CONSUMED
}

maxOf 연산식을 활용하여 키보드가 보이지 않을 때는 systemBars.bottom 크기만큼 시스템 내비게이션 패딩을 유지하고, 입력 활성화로 키보드가 위로 튀어나오면 키보드의 실시간 높이인 imeInsets.bottom을 선택하여 패딩 크기를 늘려주도록 유도했다.

좋아요와 댓글

댓글 남기기

댓글 0개

댓글을 불러오는 중입니다.