Kebanyakan kegagalan CI/CD Capacitor berasal dari daftar singkat yang sama: signing iOS code, macOS tooling yang hilang atau usang, web build yang tidak pernah masuk ke native project, build number yang dipakai ulang, dan persyaratan store yang baru gagal saat upload. Semuanya punya penyebab yang sudah diketahui dan perbaikan yang bisa diterapkan sekali. Panduan ini mengelompokkan pitfall berdasarkan tahap pipeline, beserta error yang akan Anda lihat, penyebabnya, dan apa yang perlu diubah.
Jika Anda menyiapkan pipeline dari nol, baca Setup CI/CD untuk aplikasi Capacitor pertama, lalu gunakan daftar ini untuk memperkuatnya.
Tahap 1: Membangun web layer
Jebakan: aplikasi native membawa build web lama
Gejala: CI berhasil, aplikasi terinstal, tapi UI yang muncul adalah UI kemarin.
Penyebab: cap sync menyalin apa pun yang ada di webDir pada saat itu. Jika pipeline berjalan cap sync sebelum web build, atau web build menulis ke folder yang berbeda dari webDir di capacitor.config.ts, proyek native akan berisi file usang.
Solusi: selalu jalankan langkah-langkah ini dalam urutan ini, dan gagal jika folder output kosong.
bun install --frozen-lockfile
bun run build
test -f dist/index.html || { echo "web build missing"; exit 1; }
bunx cap sync
Pastikan webDir sesuai dengan output bundler Anda (dist untuk Vite, www untuk Angular dengan Ionic, build untuk beberapa setup React).
Jebakan: URL dev server tertinggal di config
Gejala: release build menampilkan layar kosong atau mencoba memuat http://192.168.x.x:5173.
Penyebab: server.url di capacitor.config.ts diatur untuk live reload dan di-commit.
Solusi: jangan pernah commit server.url. Baca dari environment variable yang tidak pernah diatur oleh CI:
import type { CapacitorConfig } from '@capacitor/cli'
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'Example',
webDir: 'dist',
...(process.env.LIVE_RELOAD_URL && {
server: { url: process.env.LIVE_RELOAD_URL, cleartext: true },
}),
}
export default config
Jebakan: environment variables di-bake pada waktu yang salah
Gejala: aplikasi produksi terhubung ke staging API.
Penyebab: Vite, webpack, dan Angular menyisipkan environment variable saat build time. Nilai yang ada saat bun run build ran adalah yang ada di dalam binary, dan di setiap live update yang di-build dari job yang sama.
Solusi: atur variabel spesifik environment sebelum web build, per job, dan build bundle terpisah untuk staging dan production. Jangan mencoba menukarnya setelahnya cap sync.
Masalah: lockfile drift
Gejala: versi plugin di CI berbeda dari yang ada di mesin Anda, dan kompilasi native gagal karena missing symbols.
Solusi: commit lockfile dan install dengan bun install --frozen-lockfile (atau npm ci). Sematkan @capacitor/core, @capacitor/ios, @capacitor/android, dan @capacitor/cli ke versi yang sama. Versi yang tidak cocok sering memicu error native; lihat Mengatasi error version mismatch Capacitor.
Tahap 2: Native toolchain
Masalah: versi Node, JDK, atau Xcode salah
Gejala: Unsupported class file major version, The engine "node" is incompatible, atau error Xcode terkait fitur SDK.
Penyebab: perubahan image hosted runner, dan Capacitor 8 punya syarat minimum yang ketat.
| Alat | persyaratan Capacitor 8 |
|---|---|
| Node.js | 22 or newer |
| JDK | 21 |
| Xcode | 26 or newer |
| Target deployment iOS | 15.0 |
Android minSdkVersion / targetSdkVersion |
24 / 36 |
Solusi: pin setiap versi secara eksplisit di pipeline daripada mengandalkan latest:
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '26'
Pitfall: build dengan Xcode yang tidak lagi diterima Apple
Gejala: upload gagal dengan pesan bahwa app di-build dengan SDK yang tidak didukung.
Penyebab: sejak 28 April 2026, App Store Connect mewajibkan Xcode 26 dan iOS 26 SDK. Mac self-hosted dan runner image lama masih default ke Xcode 16.
Solusi: pilih macos-26 image atau install Xcode 26 pada runner Anda. Detailnya di Persyaratan Xcode 26 dari Apple untuk app Capacitor.
Jebakan: kebingungan antara CocoaPods dan SPM
Gejala: xcodebuild: error: 'App.xcworkspace' does not exist, atau pods tidak ditemukan.
Penyebab: proyek Capacitor 8 terbaru menggunakan Swift Package Manager dan build ios/App/App.xcodeproj. Proyek lama menggunakan CocoaPods dan build ios/App/App.xcworkspace setelah pod install. Pipeline yang disalin dari tutorial lama mengasumsikan workspace tersebut.
Solusi: cek mana yang digunakan proyek Anda dan build file yang sesuai. Jika sedang migrasi, lihat Cara migrasi aplikasi Capacitor Anda ke SPM.
Jebakan: build plugin Android gagal setelah upgrade Gradle
Gejala: Namespace not specified, package attribute is deprecated, atau error dari plugin build.gradle setelah update Android Studio.
Solusi: pin Android Gradle Plugin di android/build.gradle, upgrade di branch, dan update plugin terlebih dahulu. Error spesifik dibahas di Perbaiki error build plugin Capacitor dengan AGP 9.
Tahap 3: signing Code
Jebakan: iOS signing hanya jalan di Mac Anda
Gejala: No signing certificate "iOS Distribution" found, No profiles for 'com.example.app' were found, atau errSecInternalComponent.
Penyebab: keychain Mac Anda menyimpan sertifikat dan Xcode mengunduh profil secara otomatis. CI runner tidak memiliki keduanya, dan keychain-nya terkunci dalam sesi non-interaktif.
Solusi: impor sertifikat ke keychain sementara yang tidak terkunci dan instal profil di lokasi yang dicari oleh Xcode 16 ke atas:
security create-keychain -p "$KEYCHAIN_PASSWORD" ci.keychain
security set-keychain-settings -lut 21600 ci.keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" ci.keychain
security import dist.p12 -k ci.keychain -P "$P12_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" ci.keychain
security list-keychains -d user -s ci.keychain login.keychain
PROFILES="$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"
mkdir -p "$PROFILES"
cp app.mobileprovision "$PROFILES/"
Gunakan nama identity Apple Distribution, bukan legacy iOS Distribution. fastlane’s setup_ci plus match mengotomatiskan hal ini. Capgo Build mengambil sertifikat dan profil sebagai environment variables dan mengelola keychain di mesinnya sendiri, sehingga job Linux tidak perlu menyentuh security.
Jebakan: sertifikat kedaluwarsa atau dicabut
Gejala: pipeline yang berjalan lancar selama setahun tiba-tiba gagal dalam semalam.
Penyebab: Sertifikat distribusi Apple dan provisioning profile kedaluwarsa setelah satu tahun. Rekan tim yang membuat sertifikat baru di Xcode juga bisa membuat profile yang dipakai CI Anda jadi tidak valid.
Solusi: masukkan tanggal kedaluwarsa ke kalender tim, pakai satu sertifikat distribusi bersama untuk CI, dan cek sebelum build. bunx @capgo/cli@latest build prescan --platform ios memeriksa kedaluwarsa sertifikat, password, dan pairing profile sebelum ada yang di-upload.
Jebakan: Login Apple ID dan prompt two-factor
Gejala: fastlane macet menunggu code 6 digit.
Solusi: pakai key App Store Connect API (.p8, key ID, issuer ID) alih-alih Apple ID dan password. Ini tidak butuh two-factor authentication dan bisa dibatasi ke App Manager. Kalau autentikasi tetap gagal padahal key-nya benar, cek jam runner: token ditandatangani dengan waktu lokal, dan Apple menolak token dengan timestamp yang tidak sinkron.
Jebakan: secret base64 yang gagal di-decode
Gejala: MAC verification failed, invalid keystore format, atau base64: invalid input.
Penyebab: line break yang ditambahkan saat menyalin nilai base64, atau .p12 dibuat dengan default OpenSSL 3 yang tidak bisa dibaca oleh macOS.
Solusi: encode dalam satu baris, dan gunakan -legacy saat membuat .p12 dengan OpenSSL 3:
base64 -i dist.p12 | tr -d '\n' > dist.p12.b64
openssl pkcs12 -export -legacy -inkey key.pem -in cert.pem -out dist.p12
Jebakan: Android keystore yang hilang
Gejala: Anda tidak bisa sign update karena tidak ada yang punya keystore-nya.
Solusi: with Play App Signing, the keystore is the upload key, and Play Console support can register a new one. Store the keystore in your CI secrets and in an offline backup. Never let it live only on one laptop. The Generator keystore Android membuat yang baru jika Anda memulai dari awal.
Tahap 4: Desain pipeline
Jebakan: native build pada setiap pull request
Gejala: pengecekan PR yang lambat dan tagihan menit macOS yang membengkak.
Penyebab: iOS build di hosted macOS runner adalah menit paling mahal di kebanyakan paket CI, padahal mayoritas commit hanya menyentuh JavaScript.
Solusi: jalankan lint, test, dan web build pada setiap PR. Jalankan native build hanya pada release tag atau merge ke main. Untuk pratinjau PR, kirimkan web bundle ke channel Capgo alih-alih melakukan build binary, seperti yang dijelaskan dalam Membandingkan platform CI/CD untuk aplikasi Capacitor.
Pitfall: build iOS dan Android secara berurutan
Solusi: gunakan matrix agar kedua platform build secara paralel, dan atur fail-fast: false agar masalah signing iOS tidak membatalkan build Android yang valid.
strategy:
fail-fast: false
matrix:
platform: [ios, android]
Pitfall: tidak ada caching, atau cache yang salah
Gejala: setiap build mengunduh dependensi Gradle dan CocoaPods dari awal, atau build staging malah membawa config produksi dari cache lama.
Solusi: cache ~/.gradle/caches, ~/.gradle/wrapper, dan ios/App/Pods berdasarkan lockfiles. Pisahkan cache per environment. Dengan Capgo Build, cache build per-app bisa dipisah dengan --cache-key prod dan --cache-key staging, atau dilewati dengan --no-cache untuk build yang bersih.
Jebakan: path monorepo
Gejala: could not find capacitor.config atau plugin yang hilang dari proyek native.
Solusi: jalankan perintah Capacitor dari paket aplikasi, dan arahkan tools ke hoisted node_modules. Capgo CLI menerima --path dan --node-modules untuk hal ini.
Tahap 5: Submit ke store
Masalah: nomor build digunakan kembali
Gejala: Pesan “The bundle version must be higher than the previously uploaded version” di iOS, atau “Version code has already been used” di Google Play.
Solusi: buat nomornya di CI. Dengan fastlane, baca build TestFlight terbaru lalu tambahkan satu. Dengan Capgo Build, ini defaultnya: ia mengambil nomor build terbaru dari App Store Connect atau yang tertinggi versionCode dari Google Play lalu menaikkannya.
Masalah: build tertahan di TestFlight
Gejala: upload berhasil tetapi tester tidak pernah melihat build tersebut.
Penyebab: jawaban export compliance belum diisi.
Solusi: deklarasikan sekali di ios/App/App/Info.plist jika Anda hanya menggunakan enkripsi standar:
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
Jebakan: penolakan privacy manifest
Gejala: email dari Apple tentang deklarasi required reason API yang belum ada (ITMS-91053).
Solusi: tambahkan PrivacyInfo.xcprivacy ke target app dan perbarui plugin yang menyertakan miliknya sendiri. Lihat panduan privacy manifest untuk aplikasi iOS.
Jebakan: tipe artefak salah
Solusi: Google Play membutuhkan AAB (bundleRelease), bukan APK. bundleRelease tetap berhasil tanpa release signing config dan menghasilkan AAB tanpa tanda tangan yang ditolak Play Store, jadi konfigurasi signingConfigs.release di android/app/build.gradle terlebih dahulu. iOS butuh ekspor App Store, bukan IPA development atau ad hoc. Cek metode ekspor di build step Anda.
Tahap 6: Live updates
Pitfall: merilis live update yang butuh Native Build baru
Gejala: setelah update over-the-air, aplikasi crash saat memanggil method plugin yang tidak ada di binary yang terinstal.
Penyebab: web bundle bergantung pada versi plugin yang lebih baru daripada yang dikompilasi ke dalam aplikasi di perangkat pengguna.
Solusi: biarkan pipeline yang memutuskan. build needed exit 0 jika dependensi native sesuai dengan yang ada di channel, dan 1 jika diperlukan binary baru:
if bunx @capgo/cli@latest build needed com.example.app --channel production; then
bunx @capgo/cli@latest bundle upload com.example.app --channel production
else
bunx cap sync
bunx @capgo/cli@latest build request com.example.app --platform ios
bunx @capgo/cli@latest build request com.example.app --platform android
fi
Paksa juga native path saat file di bawah ios/, android/, atau capacitor.config.* berubah. Pola lengkapnya ada di Pilih otomatis live update atau Native Build, dan aturan kompatibilitasnya ada di kompatibilitas native.
Solusi yang paling banyak menghilangkan pitfall
If you only change one thing, move iOS compilation and signing out of your CI runners. Keychain setup, Xcode upgrades, macOS costs, and profile installation all disappear from your pipeline when a Linux job hands the prepared project to Build Capgo:
bun install --frozen-lockfile && bun run build
bunx cap sync ios
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
Pitfall pada tahap 1, 5, dan 6 tetap berlaku, karena hal tersebut berkaitan dengan proyek Anda, bukan runner. Untuk info lebih lanjut tentang debugging job yang gagal, lihat Mengatasi kegagalan build di pipeline CI/CD Capacitor.
Referensi cepat
| Error | Jebakan | Bagian |
|---|---|---|
| UI lama di build baru | cap sync sebelum build web |
Tahap 1 |
No profiles for ... were found |
Profile tidak terinstal atau tidak cocok | Tahap 3 |
errSecInternalComponent |
Keychain terkunci | Tahap 3 |
MAC verification failed |
Password salah atau OpenSSL 3 .p12 |
Tahap 3 |
Unsupported class file major version |
JDK salah | Tahap 2 |
| SDK terlalu usang saat upload | Xcode lebih lama dari versi 26 | Tahap 2 |
| Versi bundle harus lebih tinggi | Nomor build dipakai ulang | Tahap 5 |
| Versi code sudah dipakai | Dipakai ulang versionCode |
Tahap 5 |
| Crash setelah live update | Perubahan Native dikirim via OTA | Tahap 6 |