Bitbucket Pipelines können keine iOS-Anwendung auf ihren Hosted-Runnern bauen, weil jeder Schritt in einem Linux-Container läuft und Xcode nur auf macOS läuft. Sie haben zwei funktionierende Optionen: Registrieren Sie Ihren eigenen Mac als selbstgehosteten Bitbucket-Runner oder lassen Sie den Schritt auf Linux und übergeben Sie die iOS-Kompilierung, -Signierung und -Upload an eine Cloud-Build-Dienstleistung. Diese Anleitung zeigt beide, mit vollständigen Dateien für eine __CAPGO_KEEP_0__-Anwendung. bitbucket-pipelines.yml Dateien für eine Capacitor-App.
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 auf Bitbucket Pipelines scheitern
Bitbucket Pipelines führt jeden Schritt innerhalb eines Docker-Images aus, das Sie wählen (node:22, cimg/android, und so weiter) auf Atlassians Linux-Infrastruktur. Das ist in Ordnung für bun installEinheiten-Tests, Linting und sogar vollständige Android-Builds. Es hält bei iOS
xcodebuild,codesign, und die iOS SDK existieren nur auf macOS.- Apples Lizenz erlaubt es nur macOS, auf Apple-Hardware zu laufen, daher gibt es kein Linux-Image, das einen signierten
.ipa. - Seit dem 28. April 2026 lehnt App Store Connect Uploads ab, die nicht mit Xcode 26 und dem iOS 26 SDK erstellt wurden, daher muss Ihr Mac aktuell bleiben. Siehe Apple’s Xcode 26-Anforderung für Capacitor-Apps .
Bitbucket unterstützt selbst gehostete Runner auf Linux, Windows und macOS. Atlassian berechnet keine Build-Minuten für Schritte, die auf Ihren eigenen Runnern ausgeführt werden, aber Sie zahlen für Hardware und Wartung.
Ihre drei Optionen
| Option | Wo die iOS-Builds ausgeführt werden | Was Sie unterhalten | Gute Anpassung |
|---|---|---|---|
| Selbst gehosteter macOS Runner | Ihr Mac mini oder ein gemietetes Mac | macOS, Xcode, Schlüsselkette, Zertifikate, Festplattenplatz, Verfügbarkeit | Teams, die bereits Macs besitzen und jemanden haben, der sie ausführt |
| Zweite CI nur für Mobilgeräte | Macs eines anderen Anbieters | Zwei Pipelines, zwei Satz von Geheimnissen und Trigger | Teams, die eine dedizierte mobile CI haben möchten |
| Cloud build aus einem Linux-Schritt aufgerufen | Capgo Build's Mac-Fleet | Einen CLI-Aufruf und einige gesicherte Variablen | Capacitor-Teams, die wollen, dass Bitbucket der einzige CI bleibt |
Der Rest dieser Anleitung behandelt die ersten und dritten Optionen im Detail. Für einen umfassenderen Überblick über die Plattformen lesen Sie Vergleich der CI/CD-Plattformen für iOS-Anwendungen.
Option 1: Capgo-Bau von iOS aus einem Linux-Schritt mit Capgo Build
Capgo Build erstellt und signiert Capacitor-Apps auf Capgo-verwalteten Macs. Ihr Bitbucket-Schritt tut, was es bereits gut auf Linux tut: Installieren Sie Abhängigkeiten, bauen Sie die Web-Schicht und führen Sie cap sync ios. Dann lädt Capgo CLI das vorbereitete native Projekt (nicht Ihre Web-Quelle code oder node_modules), führt den Xcode-Bau durch, signiert es mit Ihrem Zertifikat und kann das Ergebnis auf TestFlight hochladen. Die Protokolle fließen zurück in den Bitbucket-Schritt, und die Kommandos schließen mit einem Nicht-Null-Wert, wenn der Build fehlschlägt, also schlägt ein fehlgeschlagener iOS-Bau die Pipeline.
Da Ihr Runner das Projekt auf Capgo pushet, benötigt Capgo keinen Zugriff auf Ihre Bitbucket-Repository. Es gibt keine Repository-Verbindung, die autorisiert werden muss, und keine OAuth-Anwendung, die genehmigt werden muss.
Voraussetzungen
- Eine Capacitor-Anwendung, die lokal gebaut werden kann (Capacitor 8 benötigt Node.js 22 oder neuer)
- Ein Mitgliedschaft im Apple Developer Program mit Administratorrechten auf der Team
- Ein Capgo-Konto und ein API-Schlüssel mit Upload-Berechtigung
- Die App in Capgo registriert:
bunx @capgo/cli@latest app add
Einmalige Einrichtung auf Ihrem Gerät
Führen Sie die Einrichtung einmal durch. Auf iOS erstellt oder aktualisiert es Ihre Distributionszertifikat und Provisioning-Profil und fragt nach einem App Store Connect API-Schlüssel:
bunx @capgo/cli@latest login
bunx @capgo/cli@latest build init --platform ios
Wenn Sie keinen Mac zur Verfügung haben, können Sie den Zertifikatsantrag trotzdem im Browser erstellen. iOS-Zertifikatsgenerator, oder folgen Sie Erstellen Sie ein iOS-App von Windows mit Capgo Build.
Führen Sie einmal einen Build von Ihrem Laptop durch, bevor Sie sich an CI wenden. CI ist kein guter Ort, um ein erstes Build zu debuggen:
bun run build
bunx cap sync ios
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
Exportieren Sie die Anmeldeinformationen für Bitbucket
Der CLI speichert die Anmeldeinformationen auf Ihrem Gerät. Um sie in Bitbucket zu übertragen, exportieren Sie sie in eine dotenv-Datei:
bunx @capgo/cli@latest build credentials manage --appId com.example.app --platform ios
# choose "Export to .env" in the menu
Dies schreibt .env.capgo.com.example.app.ios mit Modus 0600. Es enthält diese Schlüssel:
| Variable | Inhalt |
|---|---|
BUILD_CERTIFICATE_BASE64 |
Base64 Ihres .p12 Verteilungszertifikats |
P12_PASSWORD |
Zertifikatspasswort (leer, wenn keines) |
CAPGO_IOS_PROVISIONING_MAP_BASE64 |
Provisioning-Profile-Zuweisung, generiert durch den CLI |
APPLE_KEY_ID |
App Store Connect API Schlüssel-ID |
APPLE_ISSUER_ID |
App-Store-Connect Aussteller-ID |
APPLE_KEY_CONTENT |
Base64 des .p8 API Schlüssel |
APP_STORE_CONNECT_TEAM_ID |
Ihre Apple-Team-ID |
Fügen Sie jede Zeile als gesichert in Bitbucket unter Einstellungen für das Repository > Pipelines > Repository-Variablen, plus CAPGO_TOKEN with your Capgo API key. Secured variables are masked in logs and cannot be read back from the UI.
Wenn Sie die API bevorzugen, erstellt diese Schleife sie in einem Durchgang. Sie verwendet einen Bitbucket-API-Token mit dem Pipeline-Variablen-Schreibbereich:
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"
Löschen Sie das Datei danach und fügen Sie .env.capgo.* to .gitignoreEs enthält plaintext Signiermaterial.
Für Produktionsanmeldeinformationen, überlegen Sie Statt Repository-Variablen, verwenden Sie anstatt von Repository-Variablen. Sie sind auf eine Bereitstellungsumgebung beschränkt (z.B. Production) und Sie können diese Umgebung auf Premium-Plänen auf Administratoren oder bestimmte Branches einschränken.
Die Pipelinfdatei
Bitbucket injiziert Repository- und Bereitstellungsvariablen als Umgebungsvariablen, so dass Capgo CLI sie ohne Mapping aufnehmen kann. Diese Datei führt Tests auf jedem Push durch, erstellt einen ad-hoc-iOS-Build auf Anfrage und sendet ihn an TestFlight bei Versionstags:
# 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
Eine paar Details, die wichtig sind:
- Die Bildschirmabbildung ist ein einfaches Linux
node:22. Nichts in dieser Datei benötigt macOS. - Auf Linux
cap sync ioskopiert Web-Assets und aktualisiert die native Konfiguration, kann jedoch CocoaPods nicht ausführen. Das ist in Ordnung. Der Mac, der die Bereitstellung ausführt, installiert Pods oder löst Swift-Pakete selbst. - Capgo liest die neueste Buildnummer von App Store Connect und erhöht sie, so dass Sie nie auf „Die Versionsnummer muss höher sein als die vorher hochgeladene Version“ treffen.
--skip-build-number-bumpWenn Sie es selbst verwalten. - Die Ad-hoc-Build benötigt ein Ad-hoc-Zertifikat, das nur auf den von ihm aufgeführten Geräten installiert wird. Speichern Sie es als sicheres
ADHOC_PROFILE_BASE64variable; die--ios-provisioning-profileDieses Flag überschreibt das App Store-Profil aus der Umgebung nur für diese Build. Sammeln Sie die UDIDs der Tester mit dem iOS UDID Finder. - Pinnen Sie die CLI an einer exakten Version (zum Beispiel
@capgo/cli@7.104.0) sobald Ihr Pipeline stabil ist, also kann ein CLI Release während des Sprints keine Verhaltensänderung verursachen.
Pipelines > Pipeline ausführen > ios-adhoc Pipelines > Pipeline ausführen > ios-adhocDie letzte Anweisung gibt einen Downloadlink aus, der nach Ablauf der Aufbewahrungsfrist abläuft.
Manuelle Genehmigung vor TestFlight
Die Unterstützung für trigger: manual on a step. Split the release into a build step and a gated upload step if you want a human to approve each TestFlight upload:
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
Um direkt nach dem Testflug-Upload zum App-Review-Verfahren zu gelangen, fügen Sie --submit-to-store-review mit --store-release-name "$BITBUCKET_TAG". Ihr App-Store-Eintrag, Screenshots und Compliance-Antworten müssen in App-Store-Connect vorher vollständig sein.
Adden Sie Android parallel
Android-Builds können direkt auf Bitbucket's Linux-Runnern ausgeführt werden, aber Sie können sie auch an Capgo Build senden, damit beide Plattformen denselben Signierung- und Upload-Flow verwenden. Verwenden Sie einen 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
Der Android-Schritt benötigt ANDROID_KEYSTORE_FILE, KEYSTORE_KEY_ALIAS, KEYSTORE_KEY_PASSWORD, KEYSTORE_STORE_PASSWORD, and PLAY_CONFIG_JSON Schicken Sie Web-Änderungen ohne native Build --platform android.
Schicken Sie Web-Änderungen ohne native Build
Die meisten Commits in einer Capacitor-App betreffen nur HTML, CSS und JavaScript. Diese benötigen keine neue Binärdatei. Mit Capgo Live-Updates, ein Bitbucket-Schritt kann zwischen einer Laden- und einer über-der-Air-Bundle entscheiden:
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 beendet sich mit code 0, wenn keine native Build erforderlich ist und 1, wenn sie erforderlich ist. Es vergleicht native Plugin-Versionen mit dem, was live auf dem Kanal ist. Es sieht manuelle Änderungen unter ios/, also zwingen Sie auch die native Pfade, wenn sich diese Dateien ändern. Das vollständige Muster ist in Auto wählen Sie live update oder native Build.
Option 2: Ein selbst gehosteter macOS-Runner
Wenn Sie bereits Macs besitzen, können Sie einen als Bitbucket-Runner registrieren und Xcode selbst ausführen.
Registrieren Sie den Runner
- Öffnen Sie in Bitbucket Einstellungen des Repositories > Runner (oder Einstellungen des Arbeitsplatzes > Runner um es zu teilen) und klicken Läufer hinzufügen.
- Wählen Sie MacOS als Betriebssystem. Bitbucket zeigt eine Startanweisung mit einem Läufer-UUID und OAuth-Zugriffsberechtigungen an.
- Installieren Sie auf dem Mac einen unterstützten JDK (der Läufer ist ein Java-Programm), Xcode 26 und fastlane. Dann fügen Sie die Startanweisung ein.
- Halten Sie den Läufer als Launch-Agent laufend, damit er bei Neustarten überlebt.
Ein Schritt richtet den Läufer mit Labels aus:
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
MacOS-Läufer werden direkt auf dem Host mit Ihrem Benutzerumfeld ausgeführt, nicht in einem Container. Installieren Sie Bun und Ruby auf dem Mac selbst.
Ein Minimal-File für Fastlane
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
Neue Capacitor 8-Projekte verwenden den Swift Package Manager, daher bauen Sie App.xcodeprojÄltere Projekte, die CocoaPods noch verwenden, bauen App.xcworkspace und benötigen pod install auf dem Runner. Unsere GitHub Actions iOS-Leitfaden erklärt jede fastlane-Aktion im Detail; die Lane ist auf Bitbucket dieselbe.
Wofür Sie sich anmelden
Der Archivierung ist das Einfache Teil. Ein selbst gehosteter Mac bedeutet auch:
- Xcode-Upgrades whenever Apple raises the minimum SDK, tested before the deadline.
- Zustand des Keychains. Ein abgestürzter Job kann einen temporären Keychain hinterlassen, und der nächste Job nimmt den falschen Identitätsnachweis.
- Keine Isolation. Die Jobs laufen auf demselben Festplatte. Der DerivedData, alte Archive und Simulatoren füllen es auf.
- Ein Build nach dem anderen pro Runner, es sei denn, Sie kaufen mehr Macs.
- Zertifikate und Profile die alle ein Jahr ablaufen und auf dem Gerät erneuert werden müssen.
Das ist ein vernünftiger Tausch, wenn Ihr Team bereits Macs verwaltet. Wenn niemand bereit ist, sich um diesen Rechner zu kümmern, entfernt Option 1 ihn.
Problembehandlung
| Symptom | Wahrscheinliche Ursache und Lösung |
|---|---|
CAPGO_TOKEN is not set |
Die Variable fehlt oder es ist eine Bereitstellungsvariablen und der Schritt hat keinen deployment: Schlüssel. |
Der Schritt funktioniert auf main aber nicht auf Tags |
Die Bereitstellungsoptionen gelten nur für Schritte, die eine Bereitstellungsumgebung deklarieren. |
Provisioning profile doesn't match bundle ID |
The profile was created for another app ID. Re-run build init und exportieren Sie erneut. |
| App Store Connect-Authentifizierung fehlgeschlagen | Der falsche Issuer-Id oder Key-Id oder eine abgelaufene Schlüssel. Überprüfen Sie die Schlüssel in App Store Connect > Benutzer und Zugriff > Integrations. |
| Die Upload-Abnahme für SDK Version. | Die zum Aufbau verwendete Xcode-Version ist älter als 26. Aktualisieren Sie die selbstgehostete Mac. |
| Der selbstgehostete Schritt hängt sich in „Pending“. | Der Runner ist offline oder die Labels passen nicht. self.hosted und macos. |
errSecInternalComponent Während des codesigns |
Der Schlüsselkasten ist in einer nicht interaktiven Sitzung gesperrt. Verwenden Sie setup_ci und importieren Sie das Zertifikat in den temporären Schlüsselkette. |
| Build läuft erfolgreich, aber nichts in TestFlight. | Die Verarbeitung dauert einige Minuten, und die Exportgenehmigung kann noch ausstehen. Fügen Sie hinzu: ITSAppUsesNonExemptEncryption zum Info.plist wenn Ihre App nur Standardverschlüsselung verwendet. |
wenn Ihre App nur Standardverschlüsselung verwendet. Behebung von Buildfehlern in Capacitor CI/CD-Pipelines und das Capgo Fehlerbehebungshandbuch.
Welche Option sollten Sie wählen?
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 Neben Ihrem code legen Sie das Signiermaterial in sicheren Variablen ab und führen native Builds nur dann durch, wenn sich die native code tatsächlich geändert haben.