Membangun dan Mendistribusikan Aplikasi Mac·iOS tanpa Membuka Xcode
(scottwillsey.com)- Setelah menyelesaikan pengaturan awal akun Apple dan sertifikat, otomatisasi build, penandatanganan, dan distribusi aplikasi Mac serta iOS dapat dilakukan hanya dengan alat CLI di dalam Xcode.app
- Dari pembuatan proyek dengan XcodeGen melalui regenerasi
.xcodeprojdiproject.yml, hingga notarization Mac dan instalasi ke iPhone dapat ditangani denganxcodebuild,notarytool,stapler, dandevicectl - Distribusi Mac dijalankan berurutan lewat satu
scripts/release.sh: archive, penandatanganan Developer ID, notarization, stapling tiket, verifikasi Gatekeeper, dan instalasi ke/Applications, lalu langsung berhenti jika terjadi kegagalan - Untuk kompilasi dan pengujian cepat,
CODE_SIGNING_ALLOWED=NObisa digunakan, tetapi build dengan tanda tangan sementara ini tidak akan lolos Gatekeeper dan izin iCloud KVS serta App Group juga tidak terikat ke team ID yang sebenarnya - Kunci privat untuk penandatanganan dan kata sandi notarization disimpan di login keychain, dan bila perintah serta aturan distribusi dicatat di
CLAUDE.mdatauAGENTS.md, agen seperti Claude Code dapat menjalankan ulang seluruh workflow tersebut
Cakupan yang Bisa Ditangani tanpa Xcode GUI
- Xcode tetap harus terpasang, tetapi tidak perlu dijalankan;
xcodebuild,notarytool,stapler, dandevicectlsemuanya adalah alat shell di dalam Xcode.app yang bisa dijalankan secara mandiri - Pengaturan awal seperti login Apple ID, pembuatan sertifikat Developer ID, dan penyimpanan kata sandi notarization memerlukan GUI atau terminal interaktif
- Setelah pengaturan awal selesai, pembuatan proyek, build, archive, ekspor aplikasi bertanda tangan, notarization, verifikasi, instalasi, hingga distribusi ke iPhone fisik bisa dilakukan tanpa mouse
- Saat buntu dalam penulisan konfigurasi atau skrip, Anda bisa memberikan kebutuhan pekerjaan dan nilai spesifik proyek ke Claude Code atau alat coding LLM lain untuk membangun workflow tersebut
Memilih Toolchain Xcode Lengkap
- Pertama, pastikan hasil
xcode-select -padalah/Applications/Xcode.app/Contents/Developer - Jika yang dipilih adalah Command Line Tools mandiri, tentukan toolchain Xcode lengkap dengan perintah berikut
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
/Library/Developer/CommandLineToolsyang dipasang lewatxcode-select --installmemang berisiclangdangit, tetapi tidak menyertakan SDK iOS,notarytool,devicectl, dan alat pengembangan aplikasi lengkap lainnya- Jika Xcode sudah terpasang, paket Command Line Tools terpisah tidak diperlukan
- Persetujuan lisensi dan pemasangan komponen tambahan juga bisa dilakukan dari CLI
sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch
Mereproduksi Proyek dengan XcodeGen
- XcodeGen mengelola konfigurasi proyek Xcode dalam YAML dan meregenerasi
.xcodeprojsetiap kali build dilakukan - Bisa diunduh dari GitHub atau dipasang lewat Homebrew
brew install xcodegen
.xcodeprojadalah folder yang terlihat seperti file di macOS, dan karena Xcode terus mengubah file serta referensi di dalamnya, konflik atau perubahan yang tidak perlu bisa muncul di repositori Git- Dengan hanya meng-commit
project.ymlke Git dan mengabaikan.xcodeprojyang dihasilkan, konfigurasi proyek bisa tetap reproducible
xcodegen generate
Pengaturan Akun Pengembang Apple dan Sertifikat
- Anda harus menambahkan Apple ID di
Settings → Accountspada Xcode - Distribusi aplikasi dan notarization memerlukan akun Apple Developer berbayar
- Buat sertifikat distribusi di
Settings → Accounts → Apple ID → Manage Certificates… → + → Developer ID Application - Apple Development dan Developer ID Application memiliki kegunaan yang berbeda
- Apple Development digunakan untuk menjalankan aplikasi di perangkat sendiri atau mengirimkannya ke iPhone untuk debugging lokal
- Developer ID Application diperlukan untuk mendistribusikan
.appyang dinotarize agar lolos Gatekeeper di Mac milik orang lain
- Saat sertifikat Developer ID Application dibuat, sertifikat beserta kunci privat pasangannya akan dipasang di login keychain
- Penandatanganan aktual menggunakan kunci privat, dan kunci ini tidak bisa diunduh ulang, jadi jangan dihapus dan backup keychain harus dibuat
Menyimpan Kredensial Notarization di Keychain
- Notarization aplikasi Mac adalah proses mengunggah aplikasi bertanda tangan ke Apple untuk diperiksa dari malware
notarytoolmelakukan autentikasi dengan profil yang disimpan di keychain, dan saat pertama kali membuat profil Anda perlu memasukkan kata sandi khusus aplikasi secara interaktif
xcrun notarytool store-credentials App-Name \
--apple-id "you@example.com" \
--team-id YOUR-TEAM-ID
- Jangan meminjam profil notarization milik aplikasi lain; buat sesuai nama aplikasi untuk menghindari kegagalan diam-diam di lingkungan lain
- Kata sandi khusus aplikasi berbeda dari kata sandi Apple ID, dan dibuat di
Sign-In & Security → App-Specific Passwordspada situs Apple ID - Jika kata sandi Apple ID diubah, kata sandi khusus aplikasi bisa kedaluwarsa tanpa peringatan terpisah
- Jika muncul
401 invalid credentialssaat notarization, periksa dulu apakah kata sandi khusus aplikasi sudah kedaluwarsa sebelum mencurigai seluruh konfigurasi
- Jika muncul
- Penyimpanan profil bisa diverifikasi dengan perintah berikut
xcrun notarytool history --keychain-profile App-Name
- Jika kata sandi khusus aplikasi disimpan di vault 1Password yang bisa diakses Claude Code, pembuatan profil notarization untuk aplikasi baru juga bisa diserahkan ke agen
- Anda memang bisa mengotomatisasi input kata sandi dengan
--password, tetapi karena kata sandi dapat tertinggal di riwayat shell, lebih baik masukkan sekali secara manual lalu simpan di keychain atau 1Password
Pemisahan Konfigurasi Penandatanganan Lokal dan Rahasia
- Team ID dan bundle prefix yang diperlukan untuk penandatanganan aktual disimpan di
Local.xcconfig
cp Local.xcconfig.example Local.xcconfig
BUNDLE_PREFIX = your.real.prefix
DEVELOPMENT_TEAM = YOUR-TEAM-ID
- Tambahkan
Local.xcconfigke.gitignoreagar konfigurasi lokal per proyek tidak masuk ke repositori - Karena kunci privat penandatanganan tetap berada di login keychain dan kata sandi khusus aplikasi untuk notarization tetap berada di profil keychain
notarytool, rahasia tidak tercatat di Git
Mengotomatisasi Distribusi Mac dengan release.sh
scripts/release.shdi repositori menjalankan seluruh pipeline distribusi aplikasi Mac dengan satu perintah
./scripts/release.sh
-
Skrip bekerja dalam urutan berikut
- Memeriksa lebih dulu apakah
xcodegendan profil notarization tersedia - Meregenerasi proyek dengan
xcodegen generate - Membuat archive Release dengan
xcodebuild archive - Mengekspor aplikasi bertanda tangan Developer ID dengan
ExportOptions.plistdanxcodebuild -exportArchive - Mengemas aplikasi ke ZIP lalu mengirimkannya ke Apple dengan
notarytool submit --wait - Menempelkan tiket notarization dengan
stapler staple - Memverifikasi apakah Gatekeeper mengizinkannya lewat
spctl - Menghentikan proses lama lalu menyalin aplikasi ke
/Applications - Mendaftarkan aplikasi yang terpasang dengan
lsregister - Memverifikasi ulang tiket dan status Gatekeeper pada bundle yang sudah terpasang
- Memeriksa lebih dulu apakah
-
Meskipun model sudah mengetahui prosedur distribusi umum, informasi spesifik proyek seperti nama scheme, team ID, nama profil notarization, dan lokasi instalasi tetap harus diberikan oleh pengguna
-
Jika skrip pertama gagal, perlu ada iterasi perbaikan berdasarkan hasil eksekusi, tetapi setelah workflow stabil, Anda cukup menjalankan perintah distribusi tanpa modifikasi tambahan
-
Mencegah Kegagalan dan Distribusi yang Tidak Sempurna
set -euo pipefailmembuat skrip langsung berhenti jika satu saja perintah gagal, sehingga kondisi tidak lengkap tidak dianggap suksescd "$(dirname "$0")/.."memastikan skrip berpindah ke root repositori tak peduli dari direktori mana ia dipanggil- Blok preflight check memeriksa
xcodegendan profil notarization sebelum archive yang memakan waktu dijalankan - Bukan hanya aplikasi hasil ekspor, tetapi juga aplikasi yang sudah disalin ke
/Applicationsdiperiksa ulang untuk menangkap kerusakan bundle saat proses salin - Jika membutuhkan profil notarization lain, Anda bisa menimpanya dengan variabel lingkungan
TZED_NOTARY_PROFILE=<name> ./scripts/release.sh
Menyampaikan Aturan Distribusi ke Agen
- Jika
release.shbisa melakukan distribusi dengan satu perintah,CLAUDE.mdatauAGENTS.mdmembuat agen memakai perintah itu di setiap sesi tanpa perlu instruksi tambahan - Di dalam dokumen, catat perintah untuk meregenerasi proyek, menjalankan unit test, build macOS cepat, dan distribusi aktual
xcodegen generate
swift test
xcodebuild -project YOUR-APP-NAME.xcodeproj \
-scheme YOUR-APP-NAME-macOS \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO build
./scripts/release.sh
- Perbedaan dua jalur build itu juga perlu dijelaskan dalam dokumen
- Build
CODE_SIGNING_ALLOWED=NOcocok untuk CI dan pengecekan lokal cepat - Untuk distribusi aplikasi menu bar yang nyata, lolos atribut karantina, dan sinkronisasi iCloud, dibutuhkan
release.shyang melakukan penandatanganan Developer ID dan notarization
- Build
- Jika Anda mengarahkan agar metode dari satu aplikasi dirujuk oleh repositori lain, Claude Code dapat menyalin konfigurasi yang sama ke aplikasi berikutnya
Build Cepat Tanpa Tanda Tangan dan Pengujian
- Unit test berbasis Swift Package Manager dijalankan tanpa build Xcode
swift test
- Pengecekan kompilasi cepat untuk aplikasi macOS dilakukan dengan penandatanganan dimatikan
xcodebuild -project TZed.xcodeproj \
-scheme TZed-macOS \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO build
- Build simulator untuk aplikasi iOS dan ekstensi widget juga dapat dijalankan dengan cara yang sama
xcodebuild -project TZed.xcodeproj \
-scheme TZed-iOS \
-destination 'generic/platform=iOS Simulator' \
CODE_SIGNING_ALLOWED=NO build
- Build dengan tanda tangan sementara yang dibuat dengan
CODE_SIGNING_ALLOWED=NOdapat dipakai untuk kompilasi dan menjalankan simulator - Namun build ini akan ditolak Gatekeeper, dan karena tidak memiliki team prefix, izin seperti iCloud KVS dan App Group tidak akan terikat, sehingga tidak bisa digunakan untuk distribusi
Distribusi Headless ke iPhone Fisik
- Distribusi ke perangkat iOS tidak memiliki tahap notarization seperti aplikasi Mac, dan menggunakan
xcodebuildsertadevicectl - Aplikasi untuk perangkat fisik dibangun dan ditandatangani dengan sertifikat Apple Development serta development provisioning profile
xcodebuild -project TZed.xcodeproj \
-scheme TZed-iOS \
-destination 'generic/platform=iOS' \
-allowProvisioningUpdates \
-derivedDataPath build/ios \
archive -archivePath build/TZed-iOS.xcarchive
.appyang dihasilkan dipasang dengan menentukan UDID perangkat yang terhubung
xcrun devicectl device install app \
--device <DEVICE-UDID> build/ios/…/TZed.app
devicectl list devicesmenampilkan perangkat yang terhubung, sudah dipasangkan, dan UDID-nya- Menentukan
-allowProvisioningUpdatesakan mengambil development provisioning profile yang diperlukan
Cara Code Signing Bekerja tanpa GUI
-
Saat sertifikat Developer ID Application dibuat, Apple menerbitkan sertifikat, lalu Mac membuat kunci privat pasangannya dan menyimpan keduanya di login keychain
-
codesignyang dipanggil olehxcodebuildmenandatangani biner dengan kunci privat, lalu menyertakan sertifikat yang terhubung ke sertifikat root Apple agar penandatangan bisa diverifikasi -
Jika menggunakan
signingStyle: automatic,xcodebuildakan memilih sertifikat yang sesuai dengan team ID dan mengambil provisioning profile yang diperlukan dari Apple -
Karena itu, provisioning profile tidak perlu di-commit ke repositori
-
Entitlement, Notarization, dan Stapling
- File
.entitlementspada tiap target berisi izin seperti sandbox, network client, iCloud KVS, dan App Group - Entitlement terikat saat ditandatangani dengan team ID yang sebenarnya, sehingga build bertanda tangan sementara tidak akan membuat iCloud dan App Group berfungsi normal
- Penandatanganan dan notarization adalah tahap yang berbeda
- Penandatanganan membuktikan siapa yang membuat aplikasi
- Notarization adalah proses Apple memeriksa aplikasi bertanda tangan dari malware lalu menerbitkan tiket
- Stapling menempelkan tiket itu ke aplikasi agar Gatekeeper tetap mempercayainya saat offline
- Untuk aplikasi menu bar
LSUIElementyang menggunakan UI tersembunyi, notarization diperlukan agar lolos dari deteksi XProtect
- File
-
Perintah Verifikasi Manual
codesign -dv --verbose=4 /Applications/TZed.app spctl -a -vvv -t exec /Applications/TZed.app stapler validate /Applications/TZed.appcodesignmemeriksa penandatangan dan sertifikatspctlmemeriksa apakah Gatekeeper akan mengizinkan aplikasi dijalankanstapler validatememverifikasi bahwa tiket notarization sudah ditempelkan
Alat Standar yang Dijalankan Agen
- Tidak diperlukan server MCP build terpisah atau plugin khusus; Claude Code menjalankan CLI standar dalam shell non-interaktif
- Alat yang digunakan adalah
xcodebuild,xcrun notarytool,xcrun stapler,spctl,codesign,devicectl,xcodegen, danswift CLAUDE.mdmenyampaikan ke agen aturan seperti konvensi penamaan profil notarization, perbedaan antara build cepat dan distribusi aktual, serta keharusan memakairelease.shsaat distribusi- Hanya
notarytool store-credentialsawal yang tetap menjadi tahap interaktif; setelah itu seluruh proses bisa diotomatisasi
Mengganti Pekerjaan Xcode GUI dengan CLI
- Pembuatan
.xcodeprojyang biasanya dikelola Xcode digantikan olehproject.ymldanxcodegen generate ⌘Batau tombol Run setara denganxcodebuild … buildProduct → Archiveditangani denganxcodebuild … archive- Distribusi aplikasi lewat Organizer dapat digantikan oleh
xcodebuild -exportArchive - Upload lewat Organizer dilakukan dengan
xcrun notarytool submit --wait - Penempelan tiket otomatis menggunakan
xcrun stapler staple - Proses instalasi drag-and-drop ke
/Applicationsditangani dengancp -Rdanlsregister - Aksi Run ke iPhone fisik digantikan oleh
xcodebuild archivedandevicectl device install - Setelah instalasi Xcode dan XcodeGen, pengaturan kredensial awal, serta penulisan
release.shdanCLAUDE.mdselesai, distribusi build baru berikutnya bisa dijalankan hanya dengan satu kalimat atau satu perintah
1 komentar
Komentar di Hacker News
Ada banyak hal yang tidak bisa diselesaikan di sandbox, jadi saya menjalankan agen AI langsung di Mac. Namun setelah melihat insiden xAI mengunggah direktori home yang bahkan berisi kunci SSH, saya jadi benar-benar mempertimbangkan ulang pilihan ini
Saya tidak terlalu khawatir mesin itu sendiri rusak. Sebagian besar sudah dicadangkan atau di-commit ke Git, jadi bisa dipulihkan dalam beberapa jam. Namun saya sama sekali tidak ingin direktori
.sshdikirim ke agen AI, dan itu jangan coba dicegah lewat prompt, melainkan harus diblokir di level sistem. Saya sedang mempertimbangkan membuat pengguna terpisah dan menerapkan izin700pada direktori home. Keamanannya terasa seperti mundur ke era 1990-an, tetapi sisi lainnya adalah kita bisa menyelesaikan pekerjaan dengan kecepatan yang belum pernah ada sebelumnya. Saya sendiri juga memakai cara berisiko ini, jadi bukan bermaksud menyalahkan orang lainUntuk solusi siap pakai, bisa memakai Tart https://tart.run/ atau VirtualBuddy https://github.com/insidegui/VirtualBuddy yang open source, atau membuat sendiri dengan vibe coding alat yang membungkus OS API https://developer.apple.com/documentation/virtualization. Belakangan juga ada Apple container https://github.com/apple/container
agent. Setahun lalu saya gagal karena OAuth dan keychain, tetapi baru-baru ini berhasil mengimplementasikannya berkat panduan Claude bahwaCLAUDE_CODE_OAUTH_TOKENbisa digunakanDiperlukan tool pendamping untuk mengatur izin lewat ACL, tetapi saat ini berfungsi di macOS. Tingkat risikonya kira-kira berada di antara sandbox Claude bawaan dan isolasi container/mesin penuh. Seiring membaiknya sandbox Claude sendiri, saya sempat meragukan imbal hasil proyek pertahanan berlapis ini, tetapi melihat kemungkinan bocornya direktori home, ada cukup alasan untuk terus melanjutkannya. Belum saya rilis sebagai open source, tetapi saya bersedia berdiskusi dengan orang yang tertarik
Untuk bersenang-senang, saya sedang membangun dan menguji aplikasi iOS hanya dengan Linux, dan ternyata sangat sederhana; https://github.com/xtool-org/xtool bekerja dengan sangat baik
Tanpa perlu mengunggah ke TestFlight atau App Store, dari Linux pun aplikasi bisa dipasang langsung ke iPhone melalui USB. Kalau belum yakin, minta agen coding membuat aplikasi iOS Hello World dan mengunggahnya; itu cara mudah untuk mulai
Proyek open source saya, Axiom, membantu tool eksekusi coding melakukan pekerjaan pengembangan untuk sistem operasi Apple secara efektif
Selain berbagai teknologi dan agen, proyek ini juga mencakup tool untuk LLM seperti
xclog,xcprof,xcsym, danxcui. Tool-tool ini mengekspos fungsi yang diperlukan secara efisien dari sisi token dan juga berguna untuk teknologi atau agen di luar Axiom. Axiom: https://charleswiltgen.github.io/Axiom/, tool CLI: https://charleswiltgen.github.io/Axiom/tools/Membaca kalimat “Saya membuat Claude Code menulis skrip yang melakukan pengarsipan, penandatanganan Developer ID, notarization, stapling, hingga instalasi ke
/Applicationstanpa membuka Xcode, dan berhenti dengan jelas jika gagal di tahap mana pun” terasa agak aneh. Sebab tulisan yang sedang kita baca ini sendiri seolah-olah Claude sedang berbicara kepada kitaHampir di setiap tahap tulisan, terasa janggal juga karena berulang kali ada arahan seperti tanyakan lagi ke LLM, misalnya “tunjukkan tulisan ini ke Claude Code atau tool coding LLM pilihan Anda dan biarkan ia menyelesaikannya”, “kalau tidak tahu, tanya LLM untuk membantu pengaturannya”, “tujuan memakai LLM adalah menghindari pekerjaan manual yang tidak diinginkan”, dan “minta ia membuat workflow”
Dari sudut pandang saya yang sudah lebih dari setahun mengembangkan aplikasi Mac dan iOS dengan agent, menurut saya tulisan ini bukan saran yang baik. Terutama, Xcode MCP yang unggul harus berjalan saat Xcode sedang dibuka
Dengan alat MCP, Anda bisa mengakses berbagai fungsi jauh lebih cepat dan ringkas daripada
xcodebuild, dan juga bisa membuat serta merender#Previewyang tidak mungkin dilakukan jika Xcode ditutup. MCP dan agent bawaan di Xcode 27 juga mengendalikan simulator dengan sangat baik melalui DeviceHub. DeviceHub menggantikan Simulator.app, dan tampaknya agent bisa memahami serta menanganinya tanpa harus mengakali API aksesibilitas dengan alat sepertiaxeXcode MCP memang tidak sempurna. Masalah jendela izin yang muncul setiap kali menjalankan agent saya akali dengan persetujuan otomatis menggunakan Keyboard Maestro. Meski begitu, Xcode 27 sangat meningkatkan kegunaan vibe coding di Xcode. Sekarang saya menjalankan Codex dari UI agent bawaan Xcode sendiri, tanpa menangani MCP secara terpisah, dan lingkungan eksekusi ini lebih mampu mengarahkan model agar memanfaatkan alat yang tersedia. Pada akhirnya, kita mendapatkan hal terpenting: umpan balik yang lebih cepat dan validasi yang lebih kuat
Xcode-mcp-proxyyang mem-proxy Xcode MCP sambil mengeklik dialog dan memulihkan koneksi. Saya penasaran, untuk pengujian aplikasi macOS apakah Anda memakai Peekaboo, atau otomatisasi tangkapan layar biasaJika ingin sebisa mungkin tidak menyentuh IDE iOS dan Android, React Native dan Expo juga pilihan yang baik
Xcode dan Android Studio hanya dipakai saat memasang simulator perangkat, sementara sisanya hingga distribusi ke store ditangani oleh toolchain Expo. Bahkan di Windows yang tidak bisa memasang Xcode, dengan aplikasi terkelola Expo Anda bisa menjalankan aplikasi iOS langsung di iPhone. Untuk titik awal berbasis RN dan Expo, Ignite yang terawat dengan baik sangat bagus: https://github.com/infinitered/ignite
Secara ketat, ini tetap menggunakan Xcode. Xcode adalah GUI yang sangat banyak bug-nya, yang membungkus berbagai utilitas UNIX dan aplikasi level sistem yang umumnya stabil
Merilis aplikasi lewat CLI adalah praktik lama, dan setidaknya sudah mungkin sejak 2012, saat saya merilis aplikasi Xcode pertama saya
Untuk setidaknya sebagian debugging, semua orang pada akhirnya harus menggunakan Xcode
Build sudah bisa ditangani sebagian besar oleh agent dari command line, dan jika diberi instruksi eksplisit sesuai situasi, build bisa dilakukan lebih cepat. Jika Anda memakai grup sinkronisasi sistem berkas Xcode, XcodeGen mungkin hanya pekerjaan tambahan yang tidak perlu
Di iOS, yang paling saya rekomendasikan adalah menambahkan fitur App Store Connect ke agent: https://github.com/rorkai/App-Store-Connect-CLI. Dengan begitu, bukan hanya Anda tidak perlu selalu menyalakan Xcode, Anda juga tidak perlu berada di dekat MacBook. Cukup ubah dengan Codex dari iPhone, lalu instruksikan
ascuntuk melakukan build dan mengunggah ke TestFlight, unduh versi baru, jalankan, dan ulangiSaya terus terganggu oleh kenyataan bahwa developer dengan anggaran terbatas yang tidak mampu membeli Mac pada dasarnya tersisih dari pengembangan iOS. Setiap kali harga produk Apple naik, semakin banyak orang yang tidak bisa ikut serta dalam pengembangan
Jika melakukan vibe coding untuk aplikasi, dalam jangka panjang Expo adalah pilihan yang lebih baik. Karena berbasis React, data pelatihan LLM berisi jauh lebih banyak kode React daripada Swift, dan kualitas kode yang dihasilkan juga lebih tinggi
Semua pekerjaan bisa dilakukan dari command line, dan karena berupa web view, debugging juga mudah. Setelah dikompilasi menjadi aplikasi iOS native, rasanya mirip dengan aplikasi native lainnya. Dengan kombinasi Expo dan Fastlane, pengajuan dan distribusi iOS bisa diotomatisasi sepenuhnya, sehingga versi baru dapat diunggah ke App Store dengan satu perintah