Bagian Terakhir — Di Mana Meletakkan Pembaruan
Di Bagian 1 kita menyiapkan sertifikat Developer ID dan notarisasi, dan di Bagian 2 kita menyiapkan kunci penandatanganan Sparkle. Itu berarti kita sekarang memiliki cara untuk menandatangani aplikasi, melakukan notarisasi, dan memverifikasi keaslian pembaruan.
Namun lokasi yang ditunjuk oleh SUFeedURL (https://updates.example.com/appcast.xml), yang kita tulis ke Info.plist aplikasi di Bagian 2, masih belum berisi apa pun. Dalam bagian terakhir ini, kita akan menghosting feed pembaruan yang akan mengisi tempat tersebut dan menyelesaikan pengaturan build, melengkapi seluruh konfigurasi satu kali.
Seperti di Bagian 1 dan 2, semua nama dan domain (
FocusTimer,example.com,example-dev, dll.) adalah nilai contoh. Dalam praktiknya, gantikan dengan informasi Anda sendiri.
Mengapa Memiliki Repositori Pembaruan Terpisah
Agar pembaruan otomatis berfungsi, dua hal harus tersedia di internet.
appcast.xml— feed pembaruan yang memberi tahu aplikasi versi mana yang terbaru dan di mana mendapatkannya.dmg— file installer aplikasi yang sebenarnya
Ada batasan penting di sini. Kode Sparkle di dalam aplikasi mengambil file-file ini dengan HTTPS GET sederhana tanpa autentikasi. Artinya aplikasi di komputer pengguna harus dapat mengunduhnya secara langsung, tanpa prosedur apa pun seperti login.
Banyak pengembang menjaga repositori sumber utama aplikasi tetap privat. Tetapi file rilis di repositori privat memerlukan autentikasi, sehingga Sparkle tidak dapat mengambilnya. Itulah mengapa struktur yang umum digunakan adalah memisahkan repositori.
- Repositori utama (misalnya,
FocusTimer) — kode sumber. Boleh dijaga tetap privat. - Repositori pembaruan (misalnya,
FocusTimer-updates) — hanya menghostingappcast.xml. Harus publik.
Dalam artikel ini, kita akan menjalankan repositori pembaruan di GitHub Pages, hosting statis gratis milik GitHub.
Langkah 1 — Buat Repositori Pembaruan Publik
Buat repositori baru di GitHub.
- Klik New repository
- Nama:
FocusTimer-updates— nama ini digunakan dalam alamat feed sebentar lagi, jadi tetapkan dengan tepat, termasuk huruf besar/kecil. - Pemilik: akun atau organisasi Anda (contoh:
example-dev) - Visibilitas: Public — diperlukan, karena Sparkle harus mengambilnya tanpa autentikasi.
- Centang Add a README file (untuk commit pertama yang mudah)
- Klik Create repository
Langkah 2 — Aktifkan GitHub Pages
Sajikan repositori yang baru saja Anda buat sebagai situs statis.
- Buka Settings repositori → Pages di menu kiri
- Source: Deploy from a branch
- Branch: pilih
main/(root)→ Save - Setelah 1–2 menit, jika
https://example-dev.github.io/FocusTimer-updates/dapat diakses, berhasil.
Pada titik ini Anda sudah memiliki alamat publik tempat Anda dapat meletakkan file pembaruan. Tetapi masih ada satu langkah lagi.
Langkah 3 — Hubungkan Domain Kustom
Anda dapat menggunakan alamat GitHub Pages default (example-dev.github.io/...) apa adanya dan itu akan berfungsi. Tetapi jika Anda menyematkan alamat itu di SUFeedURL aplikasi, Anda akan menghadapi masalah jika suatu saat perlu memindahkan hosting dari GitHub Pages ke tempat lain — karena setiap aplikasi pengguna yang sudah didistribusikan masih menunjuk ke alamat lama.
Solusinya adalah menyisipkan lapisan domain yang Anda kendalikan. Jika Anda menetapkan SUFeedURL ke domain Anda sendiri, seperti https://updates.example.com/appcast.xml, maka saat Anda nanti memindahkan hosting, Anda hanya mengubah satu baris konfigurasi DNS dan pengguna yang sudah ada secara otomatis mengikuti ke lokasi baru. Anda hanya perlu melakukan pengaturan ini sekali, dan itu berlaku selamanya.
3-1. Tambahkan Rekaman DNS
Di layar konfigurasi penyedia DNS yang mengelola domain Anda (example.com), tambahkan rekaman berikut.
| Kolom | Nilai |
|---|---|
| Type | CNAME |
| Name | updates |
| Value | example-dev.github.io |
| TTL | 3600 (default) |
Ini membuat subdomain updates.example.com mengarah ke GitHub Pages.
3-2. Tambahkan File CNAME ke Repositori
Di root repositori pembaruan (FocusTimer-updates), buat file bernama CNAME yang isinya hanya satu baris — domainnya.
updates.example.com
Commit dan push file ini.
3-3. Daftarkan Domain dengan GitHub Pages
Di kolom Settings → Pages → Custom domain repositori, masukkan updates.example.com dan klik Save. GitHub secara otomatis menerbitkan sertifikat HTTPS, dan setelah diterbitkan, centang Enforce HTTPS.
3-4. Verifikasi
Propagasi DNS dan penerbitan sertifikat biasanya memakan waktu sekitar 10 menit. Setelah menunggu sebentar, verifikasi dengan perintah berikut.
curl -I https://updates.example.com/appcast.xml
Jika baris pertama respons menampilkan HTTP/2 200, semuanya baik-baik saja. (Jika Anda belum mengunggah appcast.xml, Anda mungkin mendapatkan 404, tetapi koneksi domain dan HTTPS itu sendiri dapat dikonfirmasi melalui jalur lain. Poin pentingnya adalah https://updates.example.com mengembalikan respons.)
Sebagai referensi, file installer
.dmgumumnya diunggah ke GitHub Releases daripada GitHub Pages. Menempatkan biner besar langsung di repositori akan membuatnya membengkak. Rilis disajikan melalui jalur yang berbeda dari Pages, jadi biarkan apa adanya, tidak terkait dengan pengaturan domain kustom di atas.
Langkah 4 — Simpan Repositori Pembaruan Secara Lokal
Untuk mengedit dan melakukan commit appcast.xml selama pekerjaan rilis, Anda perlu memiliki repositori pembaruan yang di-checkout secara lokal juga. Jika Anda meng-clone-nya ke lokasi yang sesuai di dalam folder proyek utama (misalnya, release/updates), skrip build dan rilis dapat menangani kedua repositori dari satu tempat, yang lebih nyaman.
git clone [email protected]:example-dev/FocusTimer-updates.git release/updates
Saat Anda menyimpan satu repositori di dalam repositori lain seperti ini, tambahkan release/updates/ ke .gitignore repositori utama agar keduanya tidak saling mengganggu.
Langkah 5 — ExportOptions.plist
Sekarang untuk pengaturan sisi build. Perintah xcodebuild -exportArchive Xcode membaca file konfigurasi bernama ExportOptions.plist saat mengekspor arsip menjadi .app untuk distribusi. Isinya untuk distribusi langsung (saluran Developer ID) adalah sebagai berikut.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>developer-id</string>
<key>signingStyle</key>
<string>automatic</string>
<key>teamID</key>
<string>ABCDE12345</string>
</dict>
</plist>
method—developer-id. Artinya “distribusi langsung, bukan Mac App Store.”signingStyle—automatic. Membiarkan Xcode secara otomatis memilih dan menggunakan sertifikat yang diterbitkan di Bagian 1.teamID— Team ID yang Anda catat di Bagian 1.
Buat file ini sekali di dalam proyek (misalnya, release/ExportOptions.plist) dan gunakan kembali untuk setiap rilis.
Langkah 6 — Periksa Pengaturan Sisi Aplikasi
Terakhir, mari tinjau pengaturan yang harus ada di proyek aplikasi itu sendiri. Jika Anda menambahkan Sparkle ke aplikasi baru untuk pertama kalinya, Anda dapat menggunakan daftar ini sebagai checklist.
Info.plist
Ini adalah kunci Sparkle yang ditambahkan di Bagian 2. Info.plist harus menyertakan kunci-kunci berikut.
<key>SUFeedURL</key>
<string>https://updates.example.com/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>5vT3kQbA9mZ0wR1yX8cD2eF4gH6jK7lN0pS2uV5xW8c=</string>
Periksa kembali bahwa SUFeedURL mengarah ke domain kustom yang dibuat di Langkah 3, dan bahwa SUPublicEDKey cocok dengan kunci publik yang dibuat di Bagian 2.
Entitlement
Jika aplikasi menggunakan App Sandbox, Sparkle memerlukan entitlement pengecualian agar dapat berkomunikasi dengan layanan internal untuk menginstal pembaruan. Entri berikut masuk ke file FocusTimer.entitlements.
<key>com.apple.security.app-sandbox</key><true/>
<key>com.apple.security.network.client</key><true/>
<key>com.apple.security.temporary-exception.mach-lookup.global-name</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)-spks</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)-spki</string>
</array>
Saat build, Xcode secara otomatis mengganti $(PRODUCT_BUNDLE_IDENTIFIER) dengan pengenal bundle yang sebenarnya (com.example.FocusTimer). Untuk detail setiap entri, lihat panduan sandboxing resmi Sparkle.
Sandboxing tidak wajib untuk aplikasi yang didistribusikan langsung (sandbox adalah persyaratan Mac App Store). Jika aplikasi Anda tidak menggunakan sandbox, pengecualian
mach-lookupdi atas tidak diperlukan. Namun, karena pembaruan otomatis menggunakan jaringan, entitlementnetwork.clientdan Hardened Runtime harus diaktifkan untuk notarisasi.
Pengaturan Build
Di pengaturan build Xcode, periksa hal-hal berikut.
CODE_SIGN_ENTITLEMENTS— jalur ke file entitlement di atasENABLE_HARDENED_RUNTIME = YES— kondisi yang diperlukan untuk notarisasiENABLE_OUTGOING_NETWORK_CONNECTIONS = YES— mengizinkan akses jaringan untuk memeriksa pembaruan
Rangkuman Seri — Konfigurasi Satu Kali Selesai
Konfigurasi satu kali tiga bagian untuk distribusi langsung kini selesai. Anda sekarang memiliki hal-hal berikut.
- ✅ (Bagian 1) Sertifikat Developer ID Application + kredensial untuk notarisasi
- ✅ (Bagian 2) Pasangan kunci penandatanganan EdDSA Sparkle + cadangan kunci privat
- ✅ (Bagian 3) Repositori pembaruan publik yang terhubung ke domain kustom +
ExportOptions.plist+ konfigurasi sisi aplikasi
Inilah semua yang hanya perlu dilakukan sekali. Anda tidak perlu mengulang pekerjaan ini setiap kali merilis versi baru.
Mulai sekarang, alur untuk mendistribusikan versi baru berulang dengan cara yang kurang lebih sama setiap kali — build arsip → ekspor dengan ExportOptions.plist → tandatangani dengan sertifikat Developer ID → notarisasi dengan notarytool → buat .dmg → tandatangani dengan kunci Sparkle → perbarui appcast.xml → unggah .dmg ke GitHub Release. Proses berulang ini sebagian besar dapat diotomatiskan dengan satu skrip, dan itu adalah topik untuk artikel terpisah.
Di antaranya, membuat
.dmgmelibatkan elemen desain seperti gambar latar belakang dan penempatan ikon, sehingga dibahas secara rinci dalam seri terpisah Mendesain DMG Distribusi untuk Aplikasi macOS Anda.
Distribusi langsung mungkin tampak menakutkan pada awalnya karena banyak yang harus disiapkan, tetapi poin pentingnya adalah bahwa “setelah Anda menyiapkannya, terus digunakan kembali.” Dengan mengorbankan sebagian kenyamanan App Store, Anda mendapatkan kendali atas setiap bagian dari proses distribusi.