--- id: android-14-migration-notes title: Android 14+ 마이그레이션 — 주요 변화 category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [android, migration, vibe-coding] tech_stack: { language: "Kotlin", applicable_to: ["Android"] } applied_in: [] aliases: [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 (권한 없이 사진 선택) ```kotlin val launcher = registerForActivityResult( ActivityResultContracts.PickVisualMedia() ) { uri -> /* uri 한 장 */ } launcher.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly)) // 또는 ImageAndVideo / SingleMimeType("image/jpeg") ``` 다중: ```kotlin val launcher = registerForActivityResult( ActivityResultContracts.PickMultipleVisualMedia(maxItems = 5) ) { uris -> /* List */ } ``` → READ_MEDIA_IMAGES 권한 불필요. 사용자 친화 + privacy. ### Selected Photos Access (READ_MEDIA_VISUAL_USER_SELECTED) 사용자가 일부 사진만 access 허용 (모두 X). ```kotlin 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+ 의무) ```xml ``` [[Android_Foreground_Service_Patterns]] 참조. ### dataSync 6시간 한도 (14+) 24시간 안 dataSync FGS 6시간 한도 — WorkManager 로 분할. ### Predictive back gesture (14+) ```xml ``` ```kotlin // Compose BackHandler(enabled = canGoBack) { goBack() } // 또는 OnBackPressedDispatcher override fun onCreate(savedInstanceState: Bundle?) { onBackPressedDispatcher.addCallback(this) { // back 처리 } } ``` → 사용자가 swipe back 시 미리보기 애니메이션. ### Notification permission (13+) ```xml ``` ```kotlin if (Build.VERSION.SDK_INT >= 33) { requestPermission(Manifest.permission.POST_NOTIFICATIONS) } ``` ### Background activity launch (14+) ```kotlin // 14+ 더 엄격: background 에서 activity launch 어려워짐 // 권장: 사용자 작업이 보이는 곳 (notification action, FGS) 으로 trigger ``` ### Pending intent — exported 명시 (12+) ```kotlin PendingIntent.getActivity(ctx, 0, intent, PendingIntent.FLAG_IMMUTABLE) // 또는 FLAG_MUTABLE — RemoteInput 시 ``` ### Exact alarm permission (12+) ```xml ``` ```kotlin val am = getSystemService() if (am?.canScheduleExactAlarms() == true) { am.setExactAndAllowWhileIdle(...) } else { // 권한 요청 / fallback } ``` ### Implicit intent — package 명시 (15+ 권장) ```kotlin // ❌ implicit Intent(Intent.ACTION_VIEW, uri) // ✅ package 명시 Intent(Intent.ACTION_VIEW, uri).setPackage("com.android.chrome") // 또는 setComponent ``` ### Edge-to-edge 의무 (15+) ```kotlin // Activity enableEdgeToEdge() // Compose Scaffold { padding -> // padding 사용해서 system bar 안 가리게 Column(Modifier.padding(padding)) { ... } } ``` ### Large screen / fold ```kotlin val widthSizeClass = calculateWindowSizeClass(activity).widthSizeClass when (widthSizeClass) { WindowWidthSizeClass.Compact -> NavigationBar(...) WindowWidthSizeClass.Medium -> NavigationRail(...) WindowWidthSizeClass.Expanded -> PermanentNavigationDrawer(...) } ``` ### Resume / pause 정확히 ```kotlin 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 자동. ## 🔗 관련 문서 - [[Android_Foreground_Service_Patterns]] - [[Android_Notification_Patterns]] - [[Android_Lifecycle_Aware_Components]]