Langsung ke konten utama

CI/CD untuk Capacitor: Masalah Umum dan Solusinya

Jebakan CI/CD yang bikin build Capacitor gagal: signing iOS, macOS runners, Xcode 26, cap sync usang, version code, penolakan store, dan solusinya.

Masalah Code signing identities dan kegagalan step CI di pipeline Capacitor

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
Live updates untuk aplikasi Capacitor

Saat bug web-layer sudah live, kirim perbaikannya lewat Capgo alih-alih menunggu berhari-hari untuk persetujuan app store. Pengguna mendapat update di background, sementara perubahan native tetap mengikuti jalur review normal.

Terbaru dari Blog kami

Capgo memberikan insight terbaik yang Anda butuhkan untuk membuat aplikasi mobile yang benar-benar profesional.