Cara Mendistribusikan Aplikasi Desktop Buatan Pengembang Solo Tanpa Peringatan Keamanan
TuBrief 편집팀
2026년 7월 15일
0
Computing/Software원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
커뮤니티의 다른 글
댓글 (0)
Log in to leave a comment
아직 작성된 글이 없습니다
원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
Log in to leave a comment
아직 작성된 글이 없습니다
Jika Anda telah menyelesaikan aplikasi desktop yang berjalan dengan baik di perangkat lokal, pengembangan baru selesai setengah jalan. Rintangan sebenarnya dimulai saat pengguna menekan tautan unduhan dan layar mereka menampilkan peringatan berwarna merah seperti "File rusak" atau "PC Anda dilindungi".
Melewati hambatan keamanan OS, mengontrol kecepatan build, dan membuat sistem pembaruan otomatis yang memperbarui aplikasi ke versi terbaru setiap kali pengguna membukanya adalah hal yang cukup melelahkan. Bahkan jika Anda memilih Tauri v2 karena dianggap lebih ringan daripada Electron, masalah praktis dalam proses distribusi tetap ada. Berikut adalah panduan bagi pengembang solo atau tim kecil agar dapat mendistribusikan produk dengan rapi tanpa membuang waktu dan biaya yang tidak perlu.
Aplikasi desktop tanpa penandatanganan kode (Code Signing) akan dianggap sebagai malware di tingkat sistem operasi. Agar tidak memicu peringatan keamanan di PC pengguna, Anda memerlukan biaya dan dokumen pendukung.
Untuk mendistribusikan aplikasi di macOS, Anda wajib mendaftar ke Apple Developer Program seharga 99 dolar per tahun. Setelah mendapatkan akun, Anda perlu membuat src-tauri/Entitlements.plist yang mendefinisikan hak pengecualian keamanan memori agar webview Tauri dapat berjalan dengan baik. Jika pengaturan ini terlewat, aplikasi akan langsung tertutup (crash) saat dijalankan.
`xml
<?xml version="1.0" encoding="UTF-8">
com.apple.security.cs.allow-jit
com.apple.security.cs.allow-unsigned-executable-memory
`
Tentukan file ini di opsi bundle pada src-tauri/tauri.conf.json.
`json
{
"bundle": {
"macOS": {
"signingIdentity": "Developer ID Application: Your Name (TEAMID)",
"entitlements": "./Entitlements.plist",
"minimumSystemVersion": "11.0",
"dmg": {
"appPosition": { "x": 180, "y": 170 },
"applicationFolderPosition": { "x": 480, "y": 170 }
}
}
}
}
`
Untuk melewati filter SmartScreen di Windows, di masa lalu seseorang harus mendapatkan sertifikat EV (Extended Validation) dalam bentuk token USB fisik seharga 400-700 dolar per tahun. Selain mahal, hal ini sangat merepotkan bagi pengembang individu.
Alternatifnya adalah Azure Trusted Signing (ATS), layanan penandatanganan berbasis cloud dari Microsoft. Dengan biaya langganan sekitar 9,99 dolar per bulan, Anda tidak perlu menyimpan kunci fisik karena penandatanganan diproses di dalam cloud HSM yang dikelola oleh Microsoft.
AZURE_TENANT_ID, CLIENT_ID, CLIENT_SECRET) dan informasi ATS ke dalam Secrets GitHub Actions.sign-tool selama proses build untuk menerapkan tanda tangan digital pada file MSI atau EXE yang telah dikompilasi oleh Tauri.Aplikasi yang ditandatangani dengan cara ini akan menghindari peringatan Windows SmartScreen sejak awal pengunduhan, sehingga Anda dapat mempertahankan pengguna yang mungkin keluar di tahap instalasi.
Tauri memang ringan, tetapi proses build mengharuskan Anda menjalankan kompiler Rust dan toolchain asli untuk setiap OS. Meskipun berjalan lancar di komputer Anda, sering kali terjadi kesalahan linker di komputer rekan tim lain, atau hasil distribusi rusak karena polusi dependensi di lingkungan lokal. Build untuk distribusi harus dilakukan di pipeline CI/CD yang terisolasi agar aman.
Masalahnya adalah runner hosting default GitHub memiliki spesifikasi yang kurang memadai untuk membuild Rust. Jika strukturnya selalu mengunduh dependensi baru dan melakukan build dari awal, satu build rilis bisa memakan waktu lebih dari 10 menit.
Alih-alih hanya menggunakan actions/cache yang mengompres file untuk dikirim ke cloud, Anda bisa mendapatkan kecepatan yang jauh berbeda dengan menggabungkan plugin cache khusus yang menargetkan penyimpanan NVMe berkinerja tinggi (swatinem/rust-cache) atau runner hosting khusus (Namespace, Depot, dll.).
Berdasarkan log build proyek open source pemutar musik spotify-player, berikut adalah perbandingan kinerja antara runner GitHub standar dengan runner khusus yang menggunakan cache volume lokal:
| Platform dan Konfigurasi Cache | Waktu Runner GitHub Standar | Waktu dengan Optimalisasi Cache | Pengurangan Waktu Build |
|---|---|---|---|
| Ubuntu Linux | 9 menit 31 detik | 34 detik | 94,0% lebih cepat |
| macOS Darwin | 9 menit 31 detik | 27 detik | 95,2% lebih cepat |
| Windows MSVC | 9 menit 31 detik | 44 detik | 92,2% lebih cepat |
| Biaya Workflow | $0,44 per eksekusi | $0,074 per eksekusi | 83,1% penghematan |
Menghubungkan infrastruktur cache volume yang persisten saja dapat mengurangi waktu tunggu build tim pengembang hingga setidaknya 40%.
Pengaturan otomatisasi distribusi ditentukan di .github/workflows/publish.yml sebagai berikut.
`yaml
jobs:
build-binaries:
strategy:
matrix:
platform: [macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
# ... setelah tahap build selesai, panggil tauri-action
`
Dengan menempatkan tauri-apps/tauri-action di akhir workflow, penginstal yang sudah ditandatangani untuk kedua OS akan otomatis terdaftar di GitHub Release Draft setiap kali Anda melakukan push tag baru.
Saat mengemas penginstal untuk Windows, Anda harus menentukan metode instalasi mesin webview WebView2. Jika koneksi internet terjamin dan Anda harus meminimalkan ukuran file unduhan, metode downloadBootstrapper yang tidak menambah ukuran bundle adalah pilihan yang tepat. Sebaliknya, jika menargetkan lingkungan offline, lebih aman untuk menyertakan offlineInstaller meskipun ukuran file instalasi bertambah sekitar 127MB.
Cara menangani data saat mengoperasikan aplikasi berbasis Tauri juga penting. Menyimpan data di IndexedDB atau LocalStorage milik browser adalah tindakan yang berisiko.
Sebenarnya, ada perubahan internal saat transisi dari Tauri v1 ke v2 di mana skema domain webview Windows berubah dari [https://tauri.localhost](https://tauri.localhost) menjadi [http://tauri.localhost](http://tauri.localhost). Hal ini menyebabkan jalur cache browser beralih secara paksa, yang mengakibatkan hilangnya semua data lama.
Untuk mencegah bencana data yang terhapus setelah distribusi, informasi penting harus disimpan langsung ke file SQLite di area sistem file asli, bukan di penyimpanan webview. Dengan menggunakan API appDataDir dari Tauri v2, aplikasi secara otomatis menemukan jalur sandbox yang aman sesuai standar sistem operasi.
C:\Users\<UserName>\AppData\Roaming\<BundleIdentifier>/Users/<UserName>/Library/Application Support/<BundleIdentifier>Berikut adalah contoh kode Rust (src-tauri/src/lib.rs) yang mengikat database SQLite ke area aman dan menjalankan migrasi skema dengan mengintervensi siklus hidup aplikasi:
`rust
use std::fs;
use tauri::Manager;
use tauri_plugin_sql::{Migration, MigrationKind};
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let database_migrations = vec![
Migration {
version: 1,
description: "initialize_user_profiles_table",
sql: "CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
);",
kind: MigrationKind::Up,
}
];
tauri::Builder::default()
.setup(|app| {
let local_app_dir = app.path().app_data_dir()
.expect("Critical: Could not resolve target operating system app data path.");
if !local_app_dir.exists() {
fs::create_dir_all(&local_app_dir)
.expect("Critical: Failed to establish persistent storage directory structure.");
}
Ok(())
})
.plugin(
tauri_plugin_sql::Builder::default()
.add_migrations("sqlite:users.db", database_migrations)
.build()
)
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
`
Dengan konfigurasi ini, database pengguna akan tetap terjaga dengan aman meskipun cache internal Electron atau Chromium terhapus karena pembaruan otomatis atau penginstalan ulang.
Cara yang meminta pengguna untuk mengunjungi situs web setiap kali ada versi baru akan meningkatkan rasio churn (pengguna berhenti menggunakan aplikasi). Anda harus membuat struktur yang menyajikan file pembaruan secara diam-diam dengan menggabungkan cloud object storage dan CDN.
Kombinasi Cloudflare R2 dan AWS CloudFront efisien sebagai server distribusi. Cloudflare R2 tidak memiliki biaya Egress (biaya transfer data keluar), sehingga biaya trafik jaringan yang timbul saat merilis file pembaruan skala besar dapat ditekan hingga nol.
File metadata (latest.json) yang diperiksa klien saat mencari versi baru tidak boleh di-cache oleh CDN atau browser. Anda harus mencantumkan kebijakan di bawah ini pada respons header.
`http
Cache-Control: no-cache, no-store, must-revalidate
`
Sebaliknya, file biner penginstal yang sebenarnya adalah file immutable (tidak berubah) yang mengandung hash unik, sehingga dapat diatur agar disimpan selama mungkin di CDN untuk mengurangi beban trafik pada server asal.
`http
Cache-Control: public, max-age=31536000, immutable
`
Di Tauri v2, lokasi opsi terkait pembaruan telah berpindah ke bawah blok plugins.updater. Berikut adalah spesifikasi pengaturan tauri.conf.json.
`json
{
"bundle": {
"createUpdaterArtifacts": true
},
"plugins": {
"updater": {
"active": true,
"endpoints": [
"https://cdn.myapp.com/releases/latest.json"
],
"dialog": false,
"pubkey": "dW5zaWduZWQgYm91bmRmaXg...",
"windows": {
"installMode": "passive"
}
}
}
}
`
Agar pengguna di lingkungan Windows tidak perlu menekan jendela konfirmasi yang mengganggu, atur installMode ke passive atau quiet. Mode passive tidak menampilkan jendela wizard instalasi, melainkan hanya menampilkan progress bar yang sederhana sebelum menyelesaikan penggantian secara diam-diam.
Setelah pengaturan selesai, hubungkan @tauri-apps/plugin-updater dan @tauri-apps/plugin-process di sisi frontend untuk memeriksa tambalan (patch) baru saat aplikasi berjalan dan memicu reboot.
`typescript
import { check } from "@tauri-apps/plugin-updater";
import { ask } from "@tauri-apps/plugin-dialog";
import { relaunch } from "@tauri-apps/plugin-process";
export async function runBackgroundUpdater(): Promise {
try {
const updatePayload = await check();
if (updatePayload && updatePayload.available) {
const userResponse = await ask(
`Versi baru [v${updatePayload.version}] tersedia. Apakah Anda ingin memperbarui dan menjalankan ulang aplikasi sekarang?`,
{
title: "Pemberitahuan Pembaruan Perangkat Lunak Otomatis",
kind: "info",
okLabel: "Instal pembaruan dan jalankan ulang",
cancelLabel: "Terapkan nanti"
}
);
if (userResponse) {
await updatePayload.downloadAndInstall();
await relaunch();
}
}
} catch (error) {
console.error("Terjadi pengecualian saat memeriksa pembaruan otomatis:", error);
}
}
`
Dengan menyisipkan fungsi ini pada tahap mount awal komponen React atau View teratas, pengguna akan selalu menggunakan perangkat lunak versi terbaru tanpa harus memeriksa situs web secara manual.
appDataDir yang dikontrol secara asli dan jalankan migrasi skema jangka panjang agar data tidak berantakan saat aplikasi diperbarui.