Bitbucket Pipelines tidak dapat membangun aplikasi iOS di runner yang dihostingnya, karena setiap langkah berjalan di dalam kontainer Linux dan Xcode hanya dapat berjalan di macOS. Anda memiliki dua opsi yang berfungsi: mendaftarkan Mac Anda sendiri sebagai runner Bitbucket yang dihosting, atau mempertahankan langkah di Linux dan menyerahkan kompilasi, tandatangan, dan unggah ke TestFlight ke layanan bangun awan. Panduan ini menunjukkan kedua hal tersebut, dengan file lengkap untuk aplikasi __CAPGO_KEEP_0__. bitbucket-pipelines.yml berkas untuk sebuah aplikasi Capacitor.
If your team already lives in Bitbucket for code review, Jira links, and deployments, you do not need a second CI tool just for iOS. The pipeline stays in Bitbucket. Only the part that needs a Mac moves.
Why iOS builds gagal pada Bitbucket Pipelines
Bitbucket Pipelines menjalankan setiap langkah di dalam sebuah gambar Docker yang Anda pilih (node:22, cimg/android, dan seterusnya) di infrastruktur Linux Atlassian. Itu sudah cukup untuk bun installunit tests, linting, dan bahkan pembangunan Android penuh. Namun, ia berhenti di iOS:
xcodebuild,codesigndan iOS SDK hanya ada di macOS.- Tidak ada gambar Linux yang dapat menghasilkan kode tanda tangan yang dapat diinstal pada perangkat iOS.
.ipa. - Sejak tanggal 28 April 2026, App Store Connect menolak unggahan yang tidak dibangun dengan Xcode 26 dan iOS 26 SDK, sehingga komputer Mac yang Anda gunakan harus selalu terupdate. Lihat Syarat Xcode 26 dari Apple untuk aplikasi Capacitor.
Bitbucket mendukung penggunaan runner sendiri pada Linux, Windows, dan macOS. Atlassian tidak menghitung menit pembangunan untuk langkah-langkah yang dijalankan pada runner Anda sendiri, tetapi Anda harus membayar biaya perangkat keras dan perawatan.
Tiga Pilihan Anda
| Opsi | Dimana iOS build dijalankan | Apa yang Anda pelihara | Sangat sesuai |
|---|---|---|---|
| Pengguna macOS yang dipasang sendiri | Mac mini milik Anda atau Mac yang disewa | macOS, Xcode, keychain, sertifikat, ruang disk, waktu aktif | Tim yang sudah memiliki Mac dan memiliki orang untuk menjalankannya |
| CI kedua hanya untuk mobile | Macs milik vendor lain | Dua pipeline, dua set rahasia dan trigger | Tim yang ingin CI mobile yang terdedikasi |
| Pembangunan awan yang dipanggil dari langkah Linux | Capgo Armada Mac Build | Dengan satu panggilan CLI dan beberapa variabel yang aman | Capacitor tim yang ingin Bitbucket tetap menjadi CI yang satu-satunya |
Bagian lain dari panduan ini menjelaskan detail tentang pilihan pertama dan ketiga. Untuk melihat gambaran yang lebih luas tentang platform, baca Menggunakan Platform CI/CD untuk Aplikasi iOS.
Pilihan 1: Membangun iOS dari Langkah Linux dengan Capgo Build
Capgo Bangun mengompilasi dan menandatangani aplikasi Capacitor pada Mac yang dikelola oleh Capgo. Langkah Bitbucket Anda melakukan apa yang sudah baik di Linux: menginstal dependensi, membangun layer web, dan menjalankan cap sync ios. Kemudian Capgo CLI mengunggah proyek native yang disiapkan (bukan sumber web code atau node_modules), menjalankan build Xcode, menandatangani dengan sertifikat Anda, dan dapat mengunggah hasilnya ke TestFlight. Log mengalir kembali ke langkah Bitbucket, dan perintah keluar dengan kode non-nol jika build gagal, sehingga build iOS yang gagal membuat pipeline gagal.
Karena runner Anda mengunggah proyek ke Capgo, Capgo tidak perlu akses ke repository Bitbucket Anda. Tidak ada koneksi repository untuk diotorisasi dan tidak ada aplikasi OAuth untuk disetujui.
Persyaratan
- Aplikasi Capacitor yang dapat dibangun secara lokal (Capacitor 8 memerlukan Node.js 22 atau lebih baru)
- Anggota Program Pengembang Apple dengan hak admin pada tim
- Sebuah akun Capgo dan sebuah API dengan izin unggah
- Aplikasi yang terdaftar di Capgo:
bunx @capgo/cli@latest app add
Pengaturan satu kali di mesin Anda
Jalankan onboarding sekali. Di iOS, itu membuat atau menggunakan kembali sertifikat distribusi dan profil pengaturan, dan meminta kunci API App Store Connect:
bunx @capgo/cli@latest login
bunx @capgo/cli@latest build init --platform ios
Jika Anda tidak memiliki Mac, Anda masih bisa membuat permintaan tanda tangan sertifikat di browser dengan penghasil sertifikat iOS, atau ikuti Pembangun aplikasi iOS dari Windows dengan Capgo Build.
Jalankan satu build dari laptop sebelum menyentuh CI. CI adalah tempat yang buruk untuk memperbaiki build pertama:
bun run build
bunx cap sync ios
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
Export kreditensial untuk Bitbucket
The CLI menyimpan kredit di mesin Anda. Untuk memindahkannya ke Bitbucket, ekspor mereka ke sebuah file dotenv:
bunx @capgo/cli@latest build credentials manage --appId com.example.app --platform ios
# choose "Export to .env" in the menu
Membuat ini menulis .env.capgo.com.example.app.ios dengan mode 0600. Ini berisi kunci-kunci berikut:
| Variabel | Isi Konten |
|---|---|
BUILD_CERTIFICATE_BASE64 |
Base64 dari sertifikat distribusi Anda .p12 Sertifikat Distribusi |
P12_PASSWORD |
Sandi sertifikat (kosong jika tidak ada) |
CAPGO_IOS_PROVISIONING_MAP_BASE64 |
Peta profil pengaturan yang dihasilkan oleh CLI |
APPLE_KEY_ID |
App Store Connect API ID Kunci |
APPLE_ISSUER_ID |
ID Penerbit App Store Connect |
APPLE_KEY_CONTENT |
sertifikat .p8 API kunci |
APP_STORE_CONNECT_TEAM_ID |
ID Tim Apple Anda |
Tambahkan setiap baris sebagai secured dalam Bitbucket di bawah Pengaturan Repositori > Pipelines > Variabel Repositori, plus CAPGO_TOKEN dengan Capgo API kunci. Variabel yang aman disembunyikan dalam log dan tidak dapat dibaca kembali dari antarmuka pengguna.
Jika Anda lebih suka API, loop ini menciptakan mereka secara bersamaan. Ini menggunakan token Bitbucket API dengan ruang lingkup variabel pipeline:
WORKSPACE=my-team
REPO=my-app
ENV_FILE=.env.capgo.com.example.app.ios
grep -v '^#' "$ENV_FILE" | grep '=' | while IFS= read -r line; do
key="${line%%=*}"
value="${line#*=}"
value="${value%\"}"; value="${value#\"}"
jq -n --arg k "$key" --arg v "$value" '{key:$k, value:$v, secured:true}' |
curl -s -u "$BB_EMAIL:$BB_API_TOKEN" \
-H 'Content-Type: application/json' \
-X POST --data @- \
"https://api.bitbucket.org/2.0/repositories/$WORKSPACE/$REPO/pipelines_config/variables" > /dev/null
echo "created $key"
done
rm "$ENV_FILE"
Hapus file tersebut dan tambahkan .env.capgo.* ke .gitignoreMengandung bahan tanda tangan teks biasa.
Untuk kreditensi produksi, pertimbangkan variabel pengiriman sebaliknya dari variabel repositori. Mereka dikaitkan dengan lingkungan pengiriman (misalnya Production) dan Anda dapat membatasi lingkungan tersebut hanya untuk administrator atau cabang tertentu pada rencana Premium.
The pipeline file
Bitbucket menginjeksi variabel repositori dan pengiriman sebagai variabel lingkungan, sehingga Capgo CLI dapat menangkapnya tanpa perlu peta. File ini menjalankan tes pada setiap push, membangun build iOS ad-hoc secara on demand, dan mengirim ke TestFlight pada tag versi:
# bitbucket-pipelines.yml
image: node:22
definitions:
caches:
bun: ~/.bun/install/cache
pipelines:
default:
- step:
name: Lint and test
caches:
- bun
script:
- curl -fsSL https://bun.sh/install | bash
- export PATH="$HOME/.bun/bin:$PATH"
- bun install --frozen-lockfile
- bun run lint
- bun run test
tags:
'v*':
- step:
name: Build iOS and upload to TestFlight
deployment: Production
caches:
- bun
script:
- curl -fsSL https://bun.sh/install | bash
- export PATH="$HOME/.bun/bin:$PATH"
- 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
--ios-distribution app_store
custom:
ios-adhoc:
- step:
name: Ad hoc iOS build for testers
caches:
- bun
script:
- curl -fsSL https://bun.sh/install | bash
- export PATH="$HOME/.bun/bin:$PATH"
- bun install --frozen-lockfile
- bun run build
- bunx cap sync ios
- echo "$ADHOC_PROFILE_BASE64" | base64 --decode > adhoc.mobileprovision
- >
bunx @capgo/cli@latest build request com.example.app
--platform ios
--build-mode release
--ios-distribution ad_hoc
--ios-provisioning-profile ./adhoc.mobileprovision
--output-upload
--output-retention 2d
--output-record /tmp/build.json
- bunx @capgo/cli@latest build last-output --path /tmp/build.json --field outputUrl
Beberapa detail yang penting:
- Gambar adalah Linux biasa
node:22. Tidak ada yang dalam file ini membutuhkan macOS. - Pada Linux,
cap sync iosmengopi aset web dan memperbarui konfigurasi native tetapi tidak dapat menjalankan CocoaPods. Itu tidak masalah. Mesin Mac yang menjalankan build menginstal pod atau menyelesaikan paket Swift sendiri. - Capgo membaca nomor build terbaru dari App Store Connect dan meningkatkannya, sehingga Anda tidak pernah mengalami “versi bundle harus lebih tinggi dari versi yang telah diunggah sebelumnya”.
--skip-build-number-bumpJika Anda mengelola sendiri. - Pembangunan ad hoc memerlukan profil pembangunan Ad Hoc, yang hanya terinstal pada perangkat yang terdaftar. Simpan sebagai }
ADHOC_PROFILE_BASE64Pindahkan __CAPGO_KEEP_0__ ke versi yang tepat (misalnya--ios-provisioning-profileflag mengatasi profil App Store dari lingkungan untuk pembangunan ini saja. Kumpulkan UDIDs tester dengan Pipelines > Jalankan pipeline > ios-adhoc. - Pin the CLI to an exact version (for example
@capgo/cli@7.104.0Setelah pipeline Anda stabil, maka tidak ada perubahan perilaku yang dapat dilakukan oleh rilis CLI di tengah sprint.
Jalankan pipeline kustom dari Pipelines > Jalankan pipeline > ios-adhocTerdapat perintah terakhir yang mencetak tautan download yang akan berlaku selama periode penyimpanan.
Persetujuan manual sebelum TestFlight
Jalankan pipeline kustom dari trigger: manual di langkah ini. Bagi rilis menjadi langkah pembangunan dan langkah unggah yang terkunci jika Anda ingin meminta persetujuan manusia untuk setiap unggah ke TestFlight:
tags:
'v*':
- step:
name: Test
script:
- curl -fsSL https://bun.sh/install | bash
- export PATH="$HOME/.bun/bin:$PATH"
- bun install --frozen-lockfile
- bun run test
- step:
name: Ship iOS to TestFlight
trigger: manual
deployment: Production
script:
- curl -fsSL https://bun.sh/install | bash
- export PATH="$HOME/.bun/bin:$PATH"
- 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
Untuk langsung menuju ke Ulasan Aplikasi setelah unggah ke TestFlight, tambahkan --submit-to-store-review dengan --store-release-name "$BITBUCKET_TAG". Daftar aplikasi Anda, screenshot, dan jawaban kewajiban masih harus lengkap di App Store Connect terlebih dahulu.
Tambahkan Android secara parallel
Bangun Android dapat berjalan langsung di runner Linux Bitbucket, tetapi Anda juga dapat mengirimkannya ke Capgo Build sehingga kedua platform menggunakan alur tanda tangan dan unggah yang sama. Gunakan parallel block:
tags:
'v*':
- parallel:
- step:
name: iOS release
script:
- curl -fsSL https://bun.sh/install | bash
- export PATH="$HOME/.bun/bin:$PATH"
- 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
- step:
name: Android release
script:
- curl -fsSL https://bun.sh/install | bash
- export PATH="$HOME/.bun/bin:$PATH"
- bun install --frozen-lockfile && bun run build
- bunx cap sync android
- bunx @capgo/cli@latest build request com.example.app --platform android --build-mode release --android-track internal
Langkah Android memerlukan ANDROID_KEYSTORE_FILE, KEYSTORE_KEY_ALIAS, KEYSTORE_KEY_PASSWORD, KEYSTORE_STORE_PASSWORD, and PLAY_CONFIG_JSON Angkut perubahan web tanpa membangun native --platform android.
Kirim perubahan web tanpa membangun native
Banyak perubahan kode ke dalam sebuah aplikasi Capacitor hanya menyentuh HTML, CSS, dan JavaScript. Mereka tidak memerlukan file binari yang baru. Capgo pembaruan hidup, langkah Bitbucket dapat memilih antara pembangunan toko dan bundle over-the-air:
branches:
main:
- step:
name: Release (live update or native)
script:
- curl -fsSL https://bun.sh/install | bash
- export PATH="$HOME/.bun/bin:$PATH"
- bun install --frozen-lockfile
- bun run build
- |
if bunx @capgo/cli@latest build needed com.example.app --channel production; then
echo "No native change, shipping a live update"
bunx @capgo/cli@latest bundle upload com.example.app --channel production
else
echo "Native change detected, building iOS"
bunx cap sync ios
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
fi
build needed keluar dengan code 0 ketika tidak ada pembangunan asli yang diperlukan dan 1 ketika diperlukan. Ini membandingkan versi plugin asli dengan apa yang hidup di saluran. Ini tidak melihat edit manual di bawah ios/, jadi juga paksa jalur asli ketika file-file tersebut berubah. Pola lengkap ada di Auto pilih live update atau pembangunan asli.
Option 2: Runner macOS yang dihosting sendiri
Jika Anda sudah memiliki Mac, Anda dapat mendaftarkan satu sebagai runner Bitbucket dan menjalankan Xcode sendiri.
Daftarkan runner
- Dalam Bitbucket, buka Pengaturan repository > Runner (atau Pengaturan workspace > Runner untuk membagikannya) dan klik Tambahkan Runner.
- Pilih MacOS sebagai sistem. Bitbucket menampilkan perintah start dengan UUID pelaksana dan kunci OAuth.
- Pada Mac, instal JDK yang didukung (runner adalah program Java), Xcode 26, dan fastlane. Lalu tempel perintah start.
- Tahan pelaksana berjalan sebagai agen peluncuran agar tetap hidup setelah restart.
Langkah ini mengarahkan pelaksana dengan label:
pipelines:
tags:
'v*':
- step:
name: iOS build on our Mac
runs-on:
- self.hosted
- macos
script:
- bun install --frozen-lockfile
- bun run build
- bunx cap sync ios
- echo "$BUILD_CERTIFICATE_BASE64" | base64 --decode > dist.p12
- echo "$PROFILE_BASE64" | base64 --decode > profile.mobileprovision
- bundle exec fastlane ios beta
pelaksana MacOS menjalankan langsung di host dengan lingkungan pengguna Anda, bukan di dalam kontainer. Pasang Bun dan Ruby di Mac itu sendiri.
Fastfile minimal
default_platform(:ios)
platform :ios do
lane :beta do
setup_ci(force: true)
api_key = app_store_connect_api_key(
key_id: ENV["APPLE_KEY_ID"],
issuer_id: ENV["APPLE_ISSUER_ID"],
key_content: ENV["APPLE_KEY_CONTENT"],
is_key_content_base64: true
)
import_certificate(
certificate_path: "dist.p12",
certificate_password: ENV["P12_PASSWORD"],
keychain_name: "fastlane_tmp_keychain",
keychain_password: ""
)
install_provisioning_profile(path: "profile.mobileprovision")
update_code_signing_settings(
path: "ios/App/App.xcodeproj",
use_automatic_signing: false,
team_id: ENV["APP_STORE_CONNECT_TEAM_ID"],
code_sign_identity: "Apple Distribution",
profile_name: ENV["PROFILE_NAME"]
)
increment_build_number(
xcodeproj: "ios/App/App.xcodeproj",
build_number: latest_testflight_build_number(api_key: api_key) + 1
)
build_app(
project: "ios/App/App.xcodeproj", # use workspace: "ios/App/App.xcworkspace" for CocoaPods projects
scheme: "App",
export_method: "app-store"
)
upload_to_testflight(api_key: api_key, skip_waiting_for_build_processing: true)
end
end
Project baru Capacitor 8 menggunakan Swift Package Manager, jadi Anda membangun App.xcodeproj. Projek yang lebih tua yang masih menggunakan CocoaPods membangun App.xcworkspace dan perlu pod install di runner. Kami memiliki GitHub Panduan Aksi iOS menggambarkan setiap aksi fastlane dalam lebih detail; jalur ini sama pada Bitbucket.
Apa yang Anda daftar
Arsip adalah bagian yang mudah. Mac yang self-hosted juga berarti:
- Pengembangan Xcode ketika Apple meningkatkan minimum SDK, diuji sebelum batas waktu.
- Keadaan Keychain. Suatu pekerjaan yang gagal dapat meninggalkan keychain sementara di belakang, dan pekerjaan berikutnya mengambil identitas yang salah.
- Tidak ada isolasi. Pekerjaan dijalankan di disk yang sama. DerivedData, arsip lama, dan simulator mengisi ruangnya.
- Satu build pada satu waktu per pengguna, kecuali Anda membeli lebih banyak Mac.
- Sertifikat dan profil yang berakhir setiap tahun dan harus diperbarui di mesin.
Jika tim Anda sudah mengelola Mac, itu adalah perdagangan yang wajar. Jika tidak ada yang ingin mengelola box tersebut, Option 1 menghilangkannya.
Troubleshooting
| Gejala | Pemicu dan solusi yang mungkin |
|---|---|
CAPGO_TOKEN is not set |
Variabelnya hilang, atau itu adalah variabel pengiriman dan langkah ini tidak memiliki deployment: Kunci. |
Langkah ini berfungsi pada main tidak pada tag |
Hanya variabel pengiriman yang berlaku untuk langkah-langkah yang mengklaim lingkungan pengiriman. |
Provisioning profile doesn't match bundle ID |
Profil dibuat untuk ID aplikasi lain. Jalankan ulang build init dan re-export. |
| Gagal autentikasi App Store Connect | ID penerbit atau ID kunci salah, atau kunci yang dicabut. Periksa kunci di App Store Connect > Pengguna dan Akses > Integrasi. |
| Upload ditolak untuk versi SDK | Proses build menggunakan Xcode yang lebih tua dari 26. Perbarui Mac yang dipasang sendiri. |
| Langkah sendiri macet di "Pending" | Runner offline atau label tidak sesuai self.hosted dan macos. |
errSecInternalComponent selama proses sign kode |
Kunci rantai terblokir dalam sesi non-interaktif. Gunakan setup_ci dan import sertifikat ke keychain sementara. |
| Build berhasil tetapi tidak ada di TestFlight. | Proses memakan beberapa menit, dan kinerja ekspor mungkin menunggu. Tambahkan ITSAppUsesNonExemptEncryption ke Info.plist jika aplikasi Anda hanya menggunakan enkripsi standar. |
jika aplikasi Anda hanya menggunakan enkripsi standar. Fixing build failures in Capacitor CI/CD pipelines dan Capgo Panduan Mengatasi Masalah Pembangunan.
__CAPGO_KEEP_0__ Panduan Perbaikan Build
Pick a self-hosted Mac when you already own the hardware, need full control of the Xcode environment, or build native Swift targets that are not Capacitor apps. Pick a cloud build from a Linux step when your app is a Capacitor app and you want Bitbucket to stay the single place your team configures CI. Either way, keep the build logic in bitbucket-pipelines.yml Masukkan material tanda tangan di variabel yang terenkripsi di samping code, dan jalankan pembangunan asli hanya ketika code asli benar-benar berubah.