Build iOS Otomatis dengan GitHub Actions menggunakan Match
Menyiapkan CI/CD untuk aplikasi Capacitor bisa jadi rumit dan memakan waktu. Berikut yang perlu Anda ketahui:
Direkomendasikan untuk Build Baru: Gunakan Capgo Build
Sekarang kami merekomendasikan penggunaan Capgo Build dengan Capgo CLI untuk build native Capacitor. Panduan Fastlane Match ini dipertahankan untuk tim yang memelihara pipeline GitHub Actions yang sudah ada, tetapi build iOS baru sebaiknya menggunakan Capgo CLI agar Anda tidak perlu memelihara Fastlane, repositori Match, Xcode runners, sertifikat, dan skrip upload sendiri.
Capgo Build untuk CI/CD oleh Capgo
Lewati pemeliharaan Fastlane Match, Xcode runner, sertifikat, provisioning profile, dan skrip upload. Build Capgo menjalankan signed native iOS build dari pipeline CI/CD Anda yang sudah ada:
- Kompatibel dengan pipeline Anda: Trigger Capgo Build dari GitHub Actions, GitLab CI, Jenkins, atau script lokal setelah web build Anda dan
npx cap sync. - Signing via CI secrets: Simpan App Store Connect key, sertifikat, provisioning profile, password, dan team ID di CI secrets Anda sendiri.
- Tanpa maintenance native runner: Capgo Build menyediakan lingkungan build Apple yang terawat, sehingga Anda tidak perlu mengelola runner macOS, image Xcode, Fastlane, atau repositori Match.
- Artifact dan submission: Download signed artifacts untuk QA atau submit release build melalui Capgo CLI.
Harga
- Paket Capgo mulai dari $12/bulan
- Termasuk OTA updates dan sekitar 15 build native per bulan
- Menit build ekstra ditagih per menit lewat credit
Panduan Setup Manual
Berikut langkah-langkah yang perlu Anda lakukan:
Continuous Delivery untuk iOS menggunakan Fastlane dan GitHub Actions dengan match
Prerequisites
Sebelum lanjut ke tutorial ini…
- Pastikan Fastlane sudah terpasang terinstal di mesin development Anda.
- Keanggotaan iOS Developer Program.
- Ingin baca-baca dulu 😆…
- Jika tim Anda terdiri dari banyak dev, kami sarankan pakai fastlane cert agar workflow lebih simpel.
Info penting soal harga

https://github.com/features/actions
Layanan ini 'gratis' hingga batas tertentu, tergantung pada mesin yang dipilih.
Kita akan menggunakan macOS mesin, Anda bisa melihat harga dan batasnya di screenshot (harga saat tutorial dibuat, bisa berubah di masa mendatang)
🔴 Setelah tahu persyaratan dan harganya, kalau Anda mau, kita lanjut…
📣 Di postingan ini, kita asumsikan aplikasi sudah dibuat di iTunes Connect, sertifikat ekosistem Apple sudah kita miliki, semuanya akan disalin oleh Fastlane!
Mari kita mulai 🤿
Langkah-langkah dalam postingan ini
- Menggunakan App Store Connect API dengan Fastlane Match
- Persyaratan
- Membuat App Store Connect API Key
- Menggunakan App Store Connect API Key
- Salin file Fastlane
- Konfigurasi Fastlane match
1. Menggunakan App Store Connect API dengan Fastlane Match
Mulai Februari 2021, autentikasi dua faktor atau verifikasi dua langkah wajib bagi semua pengguna untuk login ke App Store Connect. Lapisan keamanan tambahan untuk Apple ID ini memastikan hanya Anda yang dapat mengakses akun tersebut.
Dari Dukungan Apple
Memulai dengan match mengharuskan Anda mencabut sertifikat yang sudah ada. Tapi jangan khawatir, Anda akan langsung mendapatkan yang baru.
Persyaratan
Untuk dapat menggunakan App Store Connect API, Fastlane membutuhkan tiga hal.
- ID Issuer.
- ID Kunci.
- File Key atau isi Key.
Membuat App Store Connect API Key
Untuk membuat key, Anda harus memiliki izin Admin di App Store Connect. Jika tidak punya izin tersebut, Anda bisa mengarahkan orang yang relevan ke artikel ini dan mengikuti instruksi berikut.
1 — Login ke App Store Connect.
2 — Pilih Pengguna dan Akses.

3 — Pilih tab Integrasi.

4 — Klik Generate API Key atau tombol Tambah (+).

5 — Masukkan nama untuk kunci tersebut. Nama ini hanya untuk referensi Anda dan bukan bagian dari kunci itu sendiri.

6 — Di bagian Access, pilih role untuk kunci tersebut. Role yang berlaku untuk kunci sama dengan role yang berlaku untuk user di tim Anda. Lihat role permissions. Kami menyarankan untuk memilih Manajer aplikasi.
7 — Klik Generate.
Akses kunci API tidak dapat dibatasi ke aplikasi tertentu.
Nama kunci baru, ID kunci, link download, dan info lainnya akan muncul di halaman.

Anda bisa mendapatkan ketiga informasi yang diperlukan di sini.
<1> ID Issue.
<2> Key ID.
<3> Klik “Download API Key” untuk download private key API Anda. Link download hanya muncul jika private key belum pernah di-download. Apple tidak menyimpan salinan private key tersebut. Jadi, Anda hanya bisa men-download-nya satu kali.
🔴 Simpan private key Anda di tempat yang aman. Jangan pernah membagikan kunci Anda, menyimpan kunci di repositori code, atau menyertakan kunci dalam code client-side.
Menggunakan App Store Connect API Key
File API Key (file p8 yang Anda unduh), key ID, dan issuer ID diperlukan untuk membuat JWT token untuk otorisasi. Ada beberapa cara informasi ini dapat dimasukkan ke Fastlane menggunakan action baru Fastlane, app_store_connect_api_key. Anda bisa mempelajari cara lain di dokumentasi Fastlane. Saya menunjukkan metode ini karena menurut saya ini cara termudah untuk bekerja dengan sebagian besar CI yang ada, di mana Anda dapat mengatur environment variables.
Sekarang kita bisa mengelola Fastlane dengan kunci App Store Connect API, hebat!
2. Salin file Fastlane
Fastlane adalah pustaka Ruby yang dibuat untuk mengotomatiskan tugas pengembangan mobile yang umum. Dengan Fastlane, Anda dapat mengonfigurasi “lanes” kustom yang membundel serangkaian “actions” yang menjalankan tugas yang biasanya Anda lakukan menggunakan Android Studio. Anda bisa melakukan banyak hal dengan Fastlane, tetapi untuk tujuan tutorial ini, kita hanya akan menggunakan beberapa action inti.
Buat folder Fastlane di root proyek Anda dan salin file berikut: Fastfile
default_platform(:ios)
DEVELOPER_APP_IDENTIFIER = ENV["DEVELOPER_APP_IDENTIFIER"]
DEVELOPER_APP_ID = ENV["DEVELOPER_APP_ID"]
PROVISIONING_PROFILE_SPECIFIER = ENV["PROVISIONING_PROFILE_SPECIFIER"]
TEMP_KEYCHAIN_USER = ENV["TEMP_KEYCHAIN_USER"]
TEMP_KEYCHAIN_PASSWORD = ENV["TEMP_KEYCHAIN_PASSWORD"]
APPLE_ISSUER_ID = ENV["APPLE_ISSUER_ID"]
APPLE_KEY_ID = ENV["APPLE_KEY_ID"]
APPLE_KEY_CONTENT = ENV["APPLE_KEY_CONTENT"]
GIT_USERNAME = ENV["GIT_USERNAME"]
GIT_TOKEN = ENV["GIT_TOKEN"]
def delete_temp_keychain(name)
delete_keychain(
name: name
) if File.exist? File.expand_path("~/Library/Keychains/#{name}-db")
end
def create_temp_keychain(name, password)
create_keychain(
name: name,
password: password,
unlock: false,
timeout: 0
)
end
def ensure_temp_keychain(name, password)
delete_temp_keychain(name)
create_temp_keychain(name, password)
end
platform :ios do
lane :build do
build_app(
configuration: "Release",
workspace: "./ios/App/App.xcworkspace",
scheme: "App",
export_method: "app-store",
export_options: {
provisioningProfiles: {
DEVELOPER_APP_ID => "#{PROVISIONING_PROFILE_SPECIFIER}"
}
}
)
end
lane :refresh_profiles do
match(
type: "development",
force: true)
match(
type: "adhoc",
force: true)
end
desc "Register new device"
lane :register_new_device do |options|
device_name = prompt(text: "Enter the device name: ")
device_udid = prompt(text: "Enter the device UDID: ")
device_hash = {}
device_hash[device_name] = device_udid
register_devices(
devices: device_hash
)
refresh_profiles
end
lane :closed_beta do
keychain_name = TEMP_KEYCHAIN_USER
keychain_password = TEMP_KEYCHAIN_PASSWORD
ensure_temp_keychain(keychain_name, keychain_password)
api_key = app_store_connect_api_key(
key_id: APPLE_KEY_ID,
issuer_id: APPLE_ISSUER_ID,
key_content: APPLE_KEY_CONTENT,
duration: 1200,
in_house: false
)
match(
type: 'appstore',
git_basic_authorization: Base64.strict_encode64("#{GIT_USERNAME}:#{GIT_TOKEN}"),
readonly: true,
keychain_name: keychain_name,
keychain_password: keychain_password,
api_key: api_key
)
gym(
configuration: "Release",
workspace: "./ios/App/App.xcworkspace",
scheme: "App",
export_method: "app-store",
export_options: {
provisioningProfiles: {
DEVELOPER_APP_ID => "#{PROVISIONING_PROFILE_SPECIFIER}"
}
}
)
pilot(
apple_id: "#{DEVELOPER_APP_ID}",
app_identifier: "#{DEVELOPER_APP_IDENTIFIER}",
skip_waiting_for_build_processing: true,
skip_submission: true,
distribute_external: false,
notify_external_testers: false,
ipa: "./App.ipa"
)
delete_temp_keychain(keychain_name)
end
lane :submit_review do
version = ''
Dir.chdir("..") do
file = File.read("package.json")
data = JSON.parse(file)
version = data["version"]
end
deliver(
app_version: version,
submit_for_review: true,
automatic_release: true,
force: true, # Skip HTMl report verification
skip_metadata: false,
skip_screenshots: false,
skip_binary_upload: true
)
end
end
Appfile
app_identifier(ENV["DEVELOPER_APP_IDENTIFIER"])
apple_id(ENV["FASTLANE_APPLE_ID"])
itc_team_id(ENV["APP_STORE_CONNECT_TEAM_ID"])
team_id(ENV["DEVELOPER_PORTAL_TEAM_ID"])
Konfigurasi Fastlane match
Fastlane match adalah pendekatan baru untuk penandatanganan code iOS. Fastlane match memudahkan tim untuk mengelola sertifikat dan profil provisioning yang diperlukan untuk aplikasi iOS Anda.
Buat repositori privat baru bernama certificates, misalnya di akun pribadi atau organisasi GitHub Anda.
Inisialisasi Fastlane match untuk aplikasi iOS Anda.
fastlane match init
Lalu pilih opsi #1 (Git Storage).
[01:00:00]: fastlane match supports multiple storage modes, please select the one you want to use:1. git2. google_cloud3. s3?
Tetapkan URL repository yang baru dibuat.
[01:00:00]: Please create a new, private git repository to store the certificates and profiles there[01:00:00]: URL of the Git Repo: <YOUR_CERTIFICATES_REPO_URL>
Sekarang di dalam folder Fastlane, ada file bernama Matchfile dan
_git_url_harus diset ke URL HTTPS repository sertifikat. Opsional, Anda juga bisa menggunakan SSH, tetapi memerlukan langkah berbeda untuk dijalankan.
# ios/Matchfilegit_url("https://github.com/gitusername/certificates")storage_mode("git")type("appstore")
Selanjutnya, kita akan menghasilkan sertifikat dan memasukkan kredensial Anda saat diminta dengan Fastlane Match.
Anda akan diminta untuk memasukkan passphrase. Ingat dengan benar karena akan digunakan nanti oleh GitHub Actions untuk mendekripsi repository sertifikat Anda.
fastlane match appstore
Jika semuanya berhasil, Anda seharusnya melihat sesuatu seperti ini:
[01:40:52]: All required keys, certificates and provisioning profiles are installed 🙌
Jika Anda mengalami masalah dengan GitHub dan izin yang diperlukan, mungkin ini posting akan membantu Anda menghasilkan token autentikasi untuk git.
Sertifikat dan profil provisioning yang dihasilkan diunggah ke resources repositori sertifikat

Terakhir, buka project di Xcode, dan perbarui provisioning profile untuk konfigurasi release aplikasi Anda.

Beberapa hal yang perlu diperhatikan 💡
MATCH
Agar CI/CD dapat mengimpor sertifikat dan provisioning profile, CI/CD perlu akses ke repositori sertifikat. Anda bisa melakukannya dengan membuat personal access token (yang harus digunakan sebelumnya) yang memiliki scope untuk mengakses atau membaca repositori privat.
Di GitHub, buka Pengaturan → Pengaturan Developer → Token akses pribadi → klik Generate New Token → centang repo scope → lalu klik Generate token.

Simpan salinan personal access token yang telah dibuat. Anda akan menggunakannya nanti untuk environment variable GIT_TOKEN.
Lalu ganti file match yang dibuat di folder Fastlane dengan Matchfile
CERTIFICATE_STORE_URL = ENV["CERTIFICATE_STORE_URL"]
GIT_USERNAME = ENV["GIT_USERNAME"]
GIT_TOKEN = ENV["GIT_TOKEN"]
FASTLANE_APPLE_ID = ENV["FASTLANE_APPLE_ID"]
git_url(CERTIFICATE_STORE_URL)
storage_mode("git")
type("appstore")
git_basic_authorization(Base64.strict_encode64("#{GIT_USERNAME}:#{GIT_TOKEN}"))
username(FASTLANE_APPLE_ID)
Ini akan digunakan oleh GitHub Actions untuk mengimpor sertifikat dan provisioning profiles. Dan var akan diset di GitHub Secrets, bukan di-hard-code di file.
Memproses Build
Di GitHub Actions, biaya dihitung berdasarkan menit yang Anda gunakan untuk menjalankan workflow CI/CD. Berdasarkan pengalaman, butuh sekitar 10–15 menit sebelum build dapat diproses di App Store Connect.
Untuk proyek privat, estimasi biaya per build bisa mencapai $0.08/menit x 15 menit = $1.2, atau lebih, tergantung konfigurasi atau dependensi proyek Anda.
Jika Anda memiliki kekhawatiran yang sama soal harga seperti saya untuk proyek pribadi, Anda bisa tetap menggunakan skip_waiting_for_build_processing ke true.
Apa kekurangannya? Anda harus memperbarui kepatuhan aplikasi secara manual di App Store Connect setelah build selesai diproses, agar bisa mendistribusikan build tersebut ke pengguna.
Ini hanya parameter opsional yang perlu diperbarui jika Anda ingin menghemat build minutes untuk proyek privat. Untuk proyek gratis, ini seharusnya tidak jadi masalah sama sekali. Lihat harga.
3. Siapkan GitHub Actions
Konfigurasikan secret GitHub
Pernah bertanya-tanya dari mana nilai ENV berasal? Nah, ini bukan rahasia lagi – nilainya diambil dari secret proyek Anda. 🤦

1. APP_STORE_CONNECT_TEAM_ID - ID tim App Store Connect Anda jika Anda tergabung dalam beberapa tim.
2. DEVELOPER_APP_ID - di App Store Connect, buka aplikasinya → Informasi Aplikasi → Gulir ke bagian General Information di aplikasi Anda dan cari Apple ID.
3. DEVELOPER_APP_IDENTIFIER - bundle identifier aplikasi Anda.
4. DEVELOPER_PORTAL_TEAM_ID - ID tim Developer Portal Anda jika Anda tergabung di beberapa tim.
5. FASTLANE_APPLE_ID - Apple ID atau email developer yang Anda gunakan untuk mengelola aplikasi.
6. GIT_USERNAME & GIT_TOKEN - Nama pengguna git dan personal access token Anda.
7. MATCH_PASSWORD - passphrase yang Anda tetapkan saat menginisialisasi match, akan digunakan untuk mendekripsi sertifikat dan provisioning profiles.
8. PROVISIONING_PROFILE_SPECIFIER - match AppStore <YOUR_APP_BUNDLE_IDENTIFIER>, mis. match AppStore com.domain.blabla.demo.
9. TEMP_KEYCHAIN_USER & TEMP_KEYCHAIN_PASSWORD - tetapkan pengguna dan kata sandi keychain sementara untuk workflow Anda.
10. APPLE_KEY_ID — App Store Connect API Key 🔺Key ID.
11. APPLE_ISSUER_ID — App Store Connect API Key 🔺Issuer ID.
12. APPLE_KEY_CONTENT — App Store Connect API Key 🔺 File Key atau isi Key .p8, cek saja
13. CERTIFICATE_STORE_URL — URL repo kunci Match Anda (contoh: https://github.com/***/fastlane_match.git)
4. Konfigurasikan file workflow GitHub
Buat direktori workflow GitHub.
cd .github/workflows
Di dalam workflow folder, buat file bernama build-upload-ios.ymldan tambahkan berikut.
name: Build source code on ios
on:
push:
tags:
- '*'
jobs:
build_ios:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v6
- name: set Node.js
uses: actions/setup-node@v6
with:
node-version: '24'
cache: npm
- name: Install dependencies
id: install_code
run: npm ci
- name: Build
id: build_code
run: npm run build
- uses: actions/cache@v5
with:
path: ios/App/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-
- name: Sync
id: sync_code
run: npx cap sync
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7.2
- uses: maierj/fastlane-action@v2.3.0
env:
DEVELOPER_APP_IDENTIFIER: ${{ secrets.DEVELOPER_APP_IDENTIFIER }}
DEVELOPER_APP_ID: ${{ secrets.DEVELOPER_APP_ID }}
PROVISIONING_PROFILE_SPECIFIER: match AppStore ${{ secrets.DEVELOPER_APP_IDENTIFIER }}
TEMP_KEYCHAIN_USER: ${{ secrets.TEMP_KEYCHAIN_USER }}
TEMP_KEYCHAIN_PASSWORD: ${{ secrets.TEMP_KEYCHAIN_PASSWORD }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
CERTIFICATE_STORE_URL: https://github.com/${{ secrets.CERTIFICATE_STORE_REPO }}.git
GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
GIT_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
FASTLANE_APPLE_ID: ${{ secrets.FASTLANE_APPLE_ID }}
MATCH_USERNAME: ${{ secrets.FASTLANE_APPLE_ID }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
DEVELOPER_PORTAL_TEAM_ID: ${{ secrets.DEVELOPER_PORTAL_TEAM_ID }}
with:
lane: closed_beta
- name: Upload release bundle
uses: actions/upload-artifact@v2
with:
name: ios-release
path: ./App.ipa
retention-days: 60
Workflow ini harus dipicu setelah setiap GitHub tag, jika Anda perlu mengotomatiskan tag, silakan lihat Build dan release otomatis dengan GitHub actions pertama.
Kemudian workflow ini akan mengambil deps NodeJS Anda, menginstalnya, dan mem-build aplikasi JavaScript Anda.
Setiap kali Anda mengirim commit baru, sebuah release akan di-build di TestFlight.
App Anda tidak wajib menggunakan Ionic, hanya base Capacitor yang wajib. Bisa menggunakan modul Cordova lama, tapi Capacitor JS plugin lebih disarankan.
5. Jalankan workflow
Buat commit
Lakukan commit, Anda akan melihat workflow yang aktif di repositori.
Trigger workflow
Push commit baru ke branch main atau development untuk trigger workflow.

Setelah beberapa menit, build seharusnya sudah tersedia di dashboard App Store Connect Anda.

Bisa deploy dari mesin lokal?
Ya, bisa, dan sangat mudah.
Bayangkan Anda punya repo privat, kuota menit free plan sudah habis, dan Anda tidak ingin bayar untuk release baru, atau mungkin Anda lebih suka submit aplikasi secara manual.
Ayo kita lakukan
Oke, pertama kita perlu membuat di my_project_path/fastlane buat file bernama .env, tepat di path yang sama dengan Fastfile, untuk bisa membuat yang sama secret properties yang sama yang ada di _GitHub kami, seperti berikut:
file .env untuk deploy dari mesin lokal
Sekarang, Anda bisa buka terminal dan jalankan Fastlane dari mesin Anda:
fastlane closed_beta
❌ Hal penting soal .env file, karena kita sebaiknya tidak mengekspos data ini, kita harus menambahkannya ke dalam .gitignore, atau semacamnya: ❌
fastlane/*.env
Cara kerjanya sama seperti saat dijalankan via GitHub Actions di remote machine, tapi ini di mesin lokal kita. 🍻

Eksekusi terminal: $ Fastlane closed_beta
Jika Anda sudah sampai di sini, selamat! Sekarang Anda punya proses otomatis penuh untuk aplikasi iOS Anda dengan Fastlane dan GitHub Actions.
Setiap kali Anda mengirim commit baru, build rilis akan dibuat di Google Play Console, beta channel. Saya akan terus memperbaiki blog ini berdasarkan feedback Anda. Jika ada pertanyaan atau saran, kabari saya via email. martin@capgo.app
Build di perangkat Anda
Jika Anda masih perlu build di perangkat Anda, Anda perlu menambahkannya secara manual ke provisioning.
Hubungkan perangkat Anda ke Mac dan buka menu perangkat
Lalu salin identifier Anda
Kemudian jalankan perintah ini:
fastlane register_new_device
Anda akan diminta untuk mengatur nama perangkat dan identifier:

jika ada masalah
Jika perangkat dev Anda bermasalah, misalnya tidak bisa dipakai untuk testing, biasanya ini solusinya.
Ada perintah ajaib yang bisa menyelamatkan Anda:
fastlane match nuke development
fastlane match development
Lalu: Bersihkan proyek dengan menahan Shift(⇧)+Command(⌘)+K atau memilih Product > Clean (labelnya mungkin “Clean Build Folder”)
Lalu coba jalankan lagi aplikasi di perangkat Anda.
Terima kasih
Blog ini berdasarkan artikel-artikel berikut:
- Continuous delivery untuk iOS menggunakan Fastlane dan GitHub actions
- Dokumentasi Fastlane
- Pesan GitHub ini dari @mrogunlana
Lanjutkan dari Automatic Capacitor IOS build dengan GitHub actions menggunakan match
Jika Anda menggunakan Build iOS Capacitor otomatis dengan GitHub actions menggunakan match untuk merencanakan otomatisasi CI/CD, hubungkan dengan CI/CD Capgo untuk workflow produk di Capgo CI/CD, Capgo Native Build untuk workflow produk di Capgo Native Builds, Integrasi Capgo untuk alur kerja produk di Integrasi Capgo, Integrasi CI/CD untuk detail implementasi di Integrasi CI/CD, dan Integrasi GitHub Actions untuk detail implementasi di Integrasi GitHub Actions.