Files
2nd/10_Wiki/Topics/Coding/Android_14_Migration_Notes.md
T
2026-05-09 21:08:02 +09:00

5.2 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
android-14-migration-notes Android 14+ 마이그레이션 — 주요 변화 Coding draft B conceptual 2026-05-09 2026-05-09
android
migration
vibe-coding
language applicable_to
Kotlin
Android
Android 14
target SDK 34
photo picker
foreground service type
predictive back

Android 14+ Migration

targetSdk 34/35 의 주요 변화 체크리스트. FGS type 의무화 / Photo picker 권장 / 6h 데이터 sync 한도 / Predictive back / Notification permission.

📖 핵심 개념

  • targetSdk 변경 = 새 동작 적용.
  • Permission 변경: media, photo picker.
  • FGS type 의무.
  • 새 권장: predictive back, large screen.

💻 코드 패턴

Photo Picker (권한 없이 사진 선택)

val launcher = registerForActivityResult(
    ActivityResultContracts.PickVisualMedia()
) { uri -> /* uri 한 장 */ }

launcher.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
// 또는 ImageAndVideo / SingleMimeType("image/jpeg")

다중:

val launcher = registerForActivityResult(
    ActivityResultContracts.PickMultipleVisualMedia(maxItems = 5)
) { uris -> /* List<Uri> */ }

→ READ_MEDIA_IMAGES 권한 불필요. 사용자 친화 + privacy.

Selected Photos Access (READ_MEDIA_VISUAL_USER_SELECTED)

사용자가 일부 사진만 access 허용 (모두 X).

val perms = arrayOf(
    Manifest.permission.READ_MEDIA_IMAGES,
    Manifest.permission.READ_MEDIA_VIDEO,
    Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED, // 14+
)

Foreground Service type (Android 14+ 의무)

<service
    android:name=".PlayerService"
    android:foregroundServiceType="mediaPlayback" />

Android_Foreground_Service_Patterns 참조.

dataSync 6시간 한도 (14+)

24시간 안 dataSync FGS 6시간 한도 — WorkManager 로 분할.

Predictive back gesture (14+)

<application android:enableOnBackInvokedCallback="true">
// Compose
BackHandler(enabled = canGoBack) { goBack() }

// 또는 OnBackPressedDispatcher
override fun onCreate(savedInstanceState: Bundle?) {
    onBackPressedDispatcher.addCallback(this) {
        // back 처리
    }
}

→ 사용자가 swipe back 시 미리보기 애니메이션.

Notification permission (13+)

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
if (Build.VERSION.SDK_INT >= 33) {
    requestPermission(Manifest.permission.POST_NOTIFICATIONS)
}

Background activity launch (14+)

// 14+ 더 엄격: background 에서 activity launch 어려워짐
// 권장: 사용자 작업이 보이는 곳 (notification action, FGS) 으로 trigger

Pending intent — exported 명시 (12+)

PendingIntent.getActivity(ctx, 0, intent, 
    PendingIntent.FLAG_IMMUTABLE) // 또는 FLAG_MUTABLE — RemoteInput 시

Exact alarm permission (12+)

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
val am = getSystemService<AlarmManager>()
if (am?.canScheduleExactAlarms() == true) {
    am.setExactAndAllowWhileIdle(...)
} else {
    // 권한 요청 / fallback
}

Implicit intent — package 명시 (15+ 권장)

// ❌ implicit
Intent(Intent.ACTION_VIEW, uri)

// ✅ package 명시
Intent(Intent.ACTION_VIEW, uri).setPackage("com.android.chrome")
// 또는 setComponent

Edge-to-edge 의무 (15+)

// Activity
enableEdgeToEdge()

// Compose
Scaffold { padding -> 
    // padding 사용해서 system bar 안 가리게
    Column(Modifier.padding(padding)) { ... }
}

Large screen / fold

val widthSizeClass = calculateWindowSizeClass(activity).widthSizeClass
when (widthSizeClass) {
    WindowWidthSizeClass.Compact -> NavigationBar(...)
    WindowWidthSizeClass.Medium -> NavigationRail(...)
    WindowWidthSizeClass.Expanded -> PermanentNavigationDrawer(...)
}

Resume / pause 정확히

DisposableEffect(Unit) {
    val obs = LifecycleEventObserver { _, ev ->
        when (ev) {
            Lifecycle.Event.ON_RESUME -> resume()
            Lifecycle.Event.ON_PAUSE -> pause()
            else -> {}
        }
    }
    lifecycle.addObserver(obs)
    onDispose { lifecycle.removeObserver(obs) }
}

🤔 의사결정 기준

변경 우선
Notification 권한 즉시 (13+)
FGS type 즉시 (14+)
Photo picker 전환 적극 권장
Predictive back 14+
Edge-to-edge 15+ 의무
Implicit intent 15+ 권장

안티패턴

  • targetSdk 안 올림: Play Store 거부.
  • Permission 옛 (READ_EXTERNAL_STORAGE): 13+ 동작 X. media-specific.
  • FGS type 누락: SecurityException.
  • Notification 권한 안 받고 notify: 무시.
  • Edge-to-edge X + 15+: 검은 bar.
  • Predictive back 안 옵트인: 새 UX 못 씀.
  • Background activity launch 시도: 차단.

🤖 LLM 활용 힌트

  • 매년 targetSdk + 1.
  • Photo picker / FGS type / notification permission 3종이 큰 변화.
  • WindowSizeClass 로 fold / tablet 자동.

🔗 관련 문서