Capacitor 앱을 Capacitor 8로 업그레이드하려면 Node.js 22+, Xcode 26+, Android Studio Otter를 설치하고 @capacitor/cli 최신 8.x로 업데이트한 후 bunx cap migrate를 실행하고, migrator가 보고하는 문제를 수정하세요. 주요 breaking changes는 iOS 15 최소 배포 대상, minSdk 24를 가진 Android SDK 36, Gradle 8.14.3과 함께 AGP 8.13, 그리고 adjustMarginsForEdgeToEdge 의 제거 및 새로운 System Bars 플러그인으로의 대체입니다.
이 가이드는 자동화 경로, 그 뒤의 모든 수동 단계, 그리고 업그레이드 후 가장 자주 발생하는 오류를 다룹니다. 앱이 아닌 플러그인을 유지 관리 중이라면 Capacitor 플러그인을 Capacitor 8로 업그레이드하는 방법 대신 사용하세요.
Capacitor 8가지 요구사항 한눈에 보기
프로젝트에 손을 대기 전에 툴체인을 확인하세요. 대부분의 업그레이드 실패는 code 때문이 아니라 CI의 오래된 JDK, Xcode, Node 때문입니다.
| 영역 | Capacitor 7 | Capacitor 8 |
|---|---|---|
| Node.js | 20+ | 22+ (CLI에서 선언) engines.node >= 22.0.0) |
| iOS 프로파일링 | 16+ | 26+ |
| iOS 배포 대상 | 14.0 | 15.0 |
| 디버깅하기 | Ladybug | Otter 2025.2.1+ |
| minSdkVersion | 23 | 24 |
| compileSdkVersion / targetSdkVersion | 35 | 36 |
| Android Gradle Plugin | 8.7.2 | 8.13.0 |
| Gradle wrapper | 8.11.1 | 8.14.3 |
| Kotlin (사용 시) | 1.9.25 | 2.2.20 |
| Android 빌드용 JDK | 21 | 21 (@capacitor/android Java 21로 컴파일됨) |
| 새 iOS 플랫폼 기본값 | CocoaPods | Swift Package Manager |
Xcode 26은 단순한 Capacitor 요구사항이 아닙니다. 2026년 4월 28일부터 App Store Connect는 이전 버전의 Xcode로 빌드된 업로드를 거부하므로 어차피 필요합니다. 자세한 내용은 Capacitor 앱을 위한 Apple의 Xcode 26 요구사항 에서 확인하세요.
시작하기 전에
- 모든 변경 사항을 커밋하거나 브랜치를 생성하세요. migrator가 네이티브 파일을 직접 수정합니다.
- 현재 앱이 Capacitor 7에서 정상적으로 빌드되는지 확인하세요. 빌드가 깨진 프로젝트를 업그레이드하는 것은 혼란만 가중시킵니다.
- Capacitor 6 이하 버전을 사용 중이라면 이전 메이저 버전부터 업그레이드하세요. 각 메이저 버전마다 CLI에 자체 마이그레이션 로직이 있습니다.
- 다음 명령어로 플러그인 목록을 확인하고
bunx cap ls각 플러그인에 Capacitor 8을 지원하는 릴리스가 있는지 확인하세요. 다음을 참고하세요.peerDependencies최신 버전의
bun pm view @capgo/capacitor-updater peerDependencies
다음과 같은 플러그인 @capacitor/core: ^7.0.0 peer dependency로 설치 시 경고가 발생하고 컴파일에 실패할 수 있습니다. Capgo 플러그인은 자체 버전 번호에서 Capacitor major 버전을 따르므로 @capgo/* 8.x 릴리스는 Capacitor 8을 대상으로 합니다.
- 로컬 및 CI 툴체인 업데이트: Node 22, Xcode 26, JDK 21, Android Studio Otter. GitHub Actions에서는 Xcode 26이 포함된 macOS 이미지를 고정하고
actions/setup-java포함java-version: '21'.
옵션 1: 다음으로 업그레이드 cap migrate
CLI에는 대부분의 작업을 처리하는 마이그레이션 명령이 포함되어 있습니다. 최신 CLI을 설치한 후 실행하세요:
bun add -D @capacitor/cli@latest
bunx cap migrate
The migrator asks whether it should install the new Capacitor packages and lets you pick npm, Yarn, pnpm or Bun. Pick Bun if your project has a bun.lock. 프롬프트를 건너뛰려면 bunx cap migrate --noprompt.
변경 사항:
- 버전 업데이트
@capacitor/core,@capacitor/ios,@capacitor/android및 공식@capacitor/*플러그인을 8.x로 업데이트합니다. - 설정합니다
IPHONEOS_DEPLOYMENT_TARGET = 15.0Xcode 프로젝트에서platform :ios, '15.0'Podfile에 있습니다. - 업데이트
variables.gradle, AGP classpath, Gradle wrapper 및kotlin_version. - 추가합니다
density대상android:configChanges에서AndroidManifest.xml.
전체 출력을 확인하세요. 파일이 커스터마이징되어 특정 단계가 적용되지 못하는 경우, CLI은 파일 이름과 함께 오류를 출력하고 계속 진행합니다. 해당 줄들은 수동으로 처리해야 할 작업 목록입니다.
완료되면:
bun run build
bunx cap sync
그 후 각 플랫폼을 IDE에서 열고 한 번 빌드하여 네이티브 오류를 전체적으로 확인하세요.
옵션 2: 수동 업그레이드
네이티브 프로젝트가 크게 커스터마이징되었거나 마이그레이터가 일부 단계를 건너뛴 경우, 아래 변경 사항을 수동으로 적용하세요. 이는 공식 Capacitor 8 업그레이드 가이드와 일치합니다.
npm 패키지 업데이트
bun add @capacitor/core@latest @capacitor/ios@latest @capacitor/android@latest
bun add -D @capacitor/cli@latest
이후 각 공식 플러그인을 업데이트하세요. 예:
bun add @capacitor/app@latest @capacitor/splash-screen@latest @capacitor/status-bar@latest
iOS: 배포 타깃을 15.0으로 상향
Xcode에서 프로젝트를 선택하고 빌드 설정을(를) 열고 iOS 배포 대상 하위 배포 그리고 15.0으로 설정하세요. 익스텐션을 포함한 모든 앱 타겟에 대해 반복하세요.
앱에서 여전히 CocoaPods를 사용 중이라면 업데이트하세요. ios/App/Podfile:
platform :ios, '15.0'
그런 다음 실행하세요 bunx cap sync ios, 그러면 다음이 실행됩니다 pod install 를 대신 처리해 줍니다.
앱이 SPM을 사용하면 CLI가 다시 생성됩니다 ios/App/CapApp-SPM/Package.swift 동기화할 때마다 올바른 플랫폼 버전과 정확한 capacitor-swift-pm 설치된 버전과 일치하는 @capacitor/ios. 해당 파일은 직접 수정하지 마세요.
iOS: 커스텀 뷰 컨트롤러 알림 제거
Capacitor 8은 이제 다음을 emit합니다 CAPBridgeViewController 알림 대상 viewDidAppear 및 viewWillTransition 자체적으로. post에 확장자나 서브클래스를 추가했다면 .capacitorViewDidAppear 또는 .capacitorViewWillTransition, 삭제하세요. 그렇지 않으면 리스너가 두 번 실행됩니다.
Android: Android Studio 및 AGP 업데이트
Android Studio Otter 이상을 설치하고 android 폴더를 열어 Tools > AGP Upgrade Assistant를 실행하세요. 8.13.0을 선택하고 해당 단계를 실행합니다. 또는 android/build.gradle 을(를) 직접 편집하세요:
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:8.13.0'
classpath 'com.google.gms:google-services:4.4.4'
}
}
그리고 android/gradle/wrapper/gradle-wrapper.properties:
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
Android: 업데이트 variables.gradle
ext {
minSdkVersion = 24
compileSdkVersion = 36
targetSdkVersion = 36
androidxActivityVersion = '1.11.0'
androidxAppCompatVersion = '1.7.1'
androidxCoordinatorLayoutVersion = '1.3.0'
androidxCoreVersion = '1.17.0'
androidxFragmentVersion = '1.8.9'
coreSplashScreenVersion = '1.2.0'
androidxWebkitVersion = '1.14.0'
junitVersion = '4.13.2'
androidxJunitVersion = '1.3.0'
androidxEspressoCoreVersion = '3.7.0'
cordovaAndroidVersion = '14.0.1'
}
플러그인이 읽는 추가 변수(예: firebaseMessagingVersion). Capacitor 8용 공식 플러그인 업데이트에는 firebaseMessagingVersion = '25.0.1', androidxBrowserVersion = '1.9.0', androidxMaterialVersion = '1.13.0' 및 androidxExifInterfaceVersion = '1.4.1'.
Android: 전환 = Gradle 파일의 할당 문법
Gradle은 공백 할당 문법을 비추천(deprecated) 처리했습니다. 현재는 경고만 표시하지만, 향후 Gradle 릴리스에서 오류가 발생하므로 지금 바로 수정하세요. android/app/build.gradle:
android {
- namespace "com.example.app"
- compileSdk rootProject.ext.compileSdkVersion
+ namespace = "com.example.app"
+ compileSdk = rootProject.ext.compileSdkVersion
defaultConfig {
aaptOptions {
- ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
+ ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}
}
과 같은 메서드 호출은 google() 또는 mavenCentral() 그대로 유지됩니다.
Android: Kotlin 및 configChanges
앱 모듈에 Kotlin을 사용하는 경우, 다음을 설정하세요. kotlin_version = '2.2.20'. Kotlin 2.x에서는 기존의 kotlinOptions {} 블록을 오류로 바꾸므로, 옮기세요. jvmTarget 앱으로 보내도록 kotlin { compilerOptions { ... } }.
그다음 추가하세요 density 메인 액티비티에 추가하면 디스플레이 밀도 변경 시(폴더블, 창 크기 조절, 디스플레이 크기 설정) WebView가 재생성되지 않습니다:
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"
Android: bridge 레이아웃 이름이 변경되어
bridge_layout_main.xml 더 이상 존재하지 않습니다. 앱이나 MainActivity 커스텀 fragment가 참조한다면 R.layout.bridge_layout_main, 사용하세요 R.layout.capacitor_bridge_layout_main.
Edge-to-edge와 새로운 System Bars plugin
시각적으로 가장 눈에 띄는 변화입니다. Capacitor 8에서는 android.adjustMarginsForEdgeToEdge 를 제거하고 핵심 System Bars plugin을 추가했습니다. 별도로 설치할 필요 없이 함께 제공됩니다. @capacitor/core.
Android 15는 SDK 35를 타겟팅하는 앱에 edge-to-edge를 강제하고, Android 16은 SDK 36을 타겟팅하는 앱에서 opt-out을 제거합니다. Capacitor 8은 36을 타겟팅하므로, 인셋을 처리하지 않으면 웹 콘텐츠가 상태 바와 내비게이션 바 뒤에 그려집니다.
플러그인 설정은 다음 경로에 있습니다: plugins.SystemBars:
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'Example',
webDir: 'dist',
plugins: {
SystemBars: {
// 'css' (default) injects --safe-area-inset-* variables on Android
// 'native' relies on env() and viewport-fit
// 'disable' leaves inset handling entirely to you
insetsHandling: 'css',
initialViewportFitValueHint: 'cover',
},
},
};
export default config;
사용하면 css 또는 native, 최신 Android WebView(Chromium 140+)는 viewport-fit=cover 을 보고하고 실제 env(safe-area-inset-*) 값을 반환합니다. 구형 WebView에서는 Capacitor이 WebView를 패딩하고 env 값을 0px으로 설정합니다. 따라서 meta 태그를 설정하고 변수를 사용하세요:
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
body {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
}
런타임에서 바 스타일이나 가시성을 변경할 수 있습니다:
import { SystemBars, SystemBarsStyle, SystemBarType } from '@capacitor/core';
await SystemBars.setStyle({ style: SystemBarsStyle.Dark });
await SystemBars.hide({ bar: SystemBarType.NavigationBar });
Ionic Framework 앱은 이미 safe-area 변수를 사용하므로, 대개 meta 태그만 추가하면 됩니다. 이전 플러그인 없이 edge-to-edge 구현하기 포스트에서는 8에서는 더 이상 존재하지 않는 Capacitor 7 옵션을 설명합니다.
그 밖에 확인할 동작 변경 사항
appendUserAgentiOS에서: Capacitor 7은 문자열 앞에 두 개의 공백을 추가하고, Capacitor 8은 하나를 추가합니다. 서버가 User Agent를 엄격하게 파싱한다면, 앞에 공백을 추가하세요.ios.appendUserAgent(루트 옵션이 아닙니다. 이 옵션은 Android에도 영향을 미칩니다.)- 화면 방향 및 바코드 스캐너: Android 16+의 대형 화면에서는 방향 잠금이 무시됩니다. 일시적인 예외 설정이 존재합니다.
android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITYmanifest 속성을 통해 설정할 수 있지만, Android 17에서는 이 기능이 제거됩니다. - 위치 정보:
timeout이제 Android와 iOS의 모든 요청에 적용됩니다. 새로운 타임아웃이 발생하면 값을 높여야 합니다.watchPositionAndroid에서 다음 기능이 추가되었습니다.interval옵션을 설정하세요. - 상태 표시줄: 플러그인은 더 이상 자체
CAPBridgeViewController알림 파일을 포함하지 않습니다. 이제 코어가 해당 이벤트를 발생시키기 때문입니다. - 새 iOS 플랫폼은 SPM을 기본값으로 사용하며:
bunx cap add ios이제 SPM 프로젝트를 생성합니다.--packagemanager CocoaPods이전 템플릿이 필요하면 사용하세요. 참고: Capacitor 8에서 CocoaPods를 사용하는 방법.
업그레이드 확인
배포 전 양쪽 플랫폼에서 다음 항목을 점검하세요:
bunx cap doctor
bunx cap sync
bunx cap run ios
bunx cap run android
cap doctor코어, CLI, iOS, Android의 일치하는 8.x 버전을 보여줍니다.- 앱 실행, 스플래시 화면 숨김, 딥 링크가 올바른 화면으로 열리는지 확인합니다.
- Android 15/16 기기와 노치가 있는 iPhone에서 상태 표시줄과 네비게이션 바 영역이 정상적으로 보이는지 확인합니다.
- 푸시 알림, 카메라, 파일 접근 및 네이티브 권한이 있는 모든 플러그인이 여전히 정상 작동하는지 확인합니다.
- 릴리스 빌드(Xcode의 Archive,
./gradlew bundleRelease)가 성공해야 하며, 디버그만으로는 부족합니다.
모든 머신에서 Xcode 26과 JDK 21을 유지 관리하고 싶지 않다면, Capgo 빌드 최신 toolchain으로 iOS와 Android 빌드를 클라우드에서 실행합니다.
Live Updates로 업그레이드를 안전하게 배포하세요
Capacitor 메이저 업그레이드는 네이티브 code을 변경하므로 App Store와 Google Play를 거쳐야 합니다. 업그레이드 후 빌드된 Web bundle은 이전 바이너리에 없는 플러그인 API를 호출할 수 있습니다.
사용 중이라면 Capgo Live Update 사용하기, 도입률이 따라잡을 때까지 Capacitor 7 사용자와 Capacitor 8 사용자를 분리하세요: 네이티브 버전을 올리고, 새 바이너리가 사용하는 채널에 새 bundle을 업로드한 뒤 실행하세요 호환성 검사 업로드 전에:
bunx @capgo/cli@latest bundle compatibility
번들의 네이티브 플러그인 버전과 채널에서 실행 중인 버전을 비교해, 사용자가 문제 있는 업데이트를 받기 전에 불일치를 알려줍니다.
흔히 발생하는 Capacitor 8 업그레이드 오류 해결 방법
The engine "node" is incompatible 또는 CLI 실행이 거부되는 경우 현재 Node 20 이하를 사용 중입니다. Node 22 LTS를 설치하고 CI 이미지도 업데이트하세요.
error: invalid source release: 21 Android에서. Gradle이 JDK 17로 실행 중입니다. Android Studio에서 내장 JDK 21을 사용하도록 설정하세요 (Settings > Build, Execution, Deployment > Build Tools > Gradle > Gradle JDK)로 설정하고 JAVA_HOME CLI 및 CI 빌드용 JDK 21로 지정하세요.
Minimum supported Gradle version is 8.13. AGP는 업데이트했지만 wrapper는 그대로입니다. wrapper를 8.14.3으로 설정하세요.
Dependency ... requires libraries and applications that depend on it to compile against version 36. compileSdkVersion 어딘가에 여전히 35가 남아 있습니다. 확인하세요: variables.gradle 그리고 해당 버전을 하드코딩한 모든 플러그인.
Using 'kotlinOptions' ... is an error 또는 유사한 Kotlin DSL 에러가 발생합니다. 플러그인 또는 앱 모듈이 아직 사용 중인 kotlinOptions입니다. 플러그인을 업데이트하거나, 릴리스가 나올 때까지 패치하세요(참고: Capacitor 플러그인 패치 방법).
Xcode: No such module 'Capacitor' 업그레이드 후. CocoaPods의 경우, 다음을 열고 App.xcworkspace, 아니라 App.xcodeproj그리고 다시 실행하세요. bunx cap sync ios. SPM의 경우, 다음을 사용하세요. File > Packages > Reset Package Caches.
"X" plugin is not implemented on ios/android. 플러그인이 동기화되지 않았거나, Capacitor 8 / SPM 호환 릴리스가 없습니다. 다음을 실행하고 bunx cap sync 경고를 확인하세요.
더 긴 목록은 다음을 참고하세요: Capacitor iOS 트러블슈팅 가이드 및 Android 트러블슈팅 가이드. 코어와 플러그인 버전 불일치는 다음에서 다룹니다: Capacitor 버전 불일치 오류 해결.
지루한 작업은 AI 에이전트에게 맡기세요
Claude Code, Cursor 또는 유사한 에이전트를 사용 중이라면, 공개된 Capgo 기술 스택 에는 다음이 포함됩니다: capacitor-app-upgrade-v7-to-v8 및 capacitor-app-upgrades 메이저 버전 간 점프용 스킬. 다음 명령어로 설치하세요 bunx skills add Cap-go/capgo-skills 에이전트에게 앱 업그레이드를 요청하세요. 에이전트가 migrator를 실행한 뒤, Gradle 문법, Kotlin 옵션, CI 이미지처럼 CLI가 흔히 놓치는 단계를 점검합니다.
다음 단계
Capacitor 9는 이미 프리릴리스입니다. 8에서 안정화되면 다음을 읽어보세요. Capacitor 9 준비하기 다음 업그레이드가 더 가벼워집니다.