Capacitor (dari tim Ionic) membungkus web app yang sudah di-build (HTML, CSS, JavaScript) jadi aplikasi Android dan iOS: tampilannya jalan di WebView, yaitu "browser tanpa bingkai" di dalam aplikasi native, dan fitur HP dipanggil lewat plugin. Ionic Framework adalah kumpulan komponen UI web yang meniru tampilan iOS dan Android, biasanya dipakai di atas Capacitor. Bayangin brosur harga Bu Rini. PWA itu brosur yang ditempel pelanggan sendiri di kulkasnya, diambil dari browser. Capacitor itu brosur yang sama, dimasukkan ke bingkai berlampu lalu dipajang di etalase mal (toko aplikasi); lampunya fitur native lewat plugin. React Native itu papan nama yang dicetak khusus dengan bahan asli toko: komponen native sungguhan. Pelajaran ini menimbang ketiganya, termasuk pilihan React Native untuk Laundry Bu Rini di pelajaran kedua.
🧪 Tebakan cepat: Di versi Capacitor Laundry Bu Rini,
PushNotifications.register()dipanggil di iPhone Mbak Wulan dan di HP Android Pak Darto. Server Laravel menerima dua token. Bisakah keduanya dikirimi notifikasi lewat satu layanan, sepertiExponentPushTokendi pelajaran push? Jawabannya ada di bagian "Plugin: kamera, push, preferences".
Tiga cara membawa web ke HP
| PWA | Capacitor | React Native (Expo) | |
|---|---|---|---|
| Yang menggambar tampilan | browser | WebView di aplikasi native (Android System WebView, WKWebView di iOS) | view native (UIView di iOS, View di Android) |
| Kode web yang dipakai ulang | semuanya | semuanya: isi folder dist |
logika dan hook; tampilan ditulis ulang dengan View dan Text |
| Masuk toko | gak (Android bisa lewat TWA) | App Store dan Play | App Store dan Play |
| Fitur HP | API browser | plugin Capacitor | Expo modules |
| Perbaikan tanpa review toko | deploy web | lewat layanan live update pihak ketiga | EAS Update |
Jadi beda mendasarnya: Capacitor membungkus web app di dalam WebView native, sedangkan React Native me-render komponen native sesungguhnya.
Membungkus web app dengan Capacitor 8
Versi per 11 Oktober 2026: @capacitor/core, @capacitor/cli, @capacitor/android, dan @capacitor/ios 8.5.3. Untuk web app yang sudah ada (di sini versi web kecil Laundry Bu Rini yang di-build Vite ke dist):
npm install @capacitor/core
npm install -D @capacitor/cli
npx cap init "Laundry Bu Rini" id.laundryburini.web --web-dir dist
npm install @capacitor/android @capacitor/ios
npm run build # Vite menulis dist/
npx cap add android # membuat folder android/ (project Android Studio)
npx cap add ios # membuat folder ios/ (project Xcode)
Hasilnya di scratchpad pelajaran ini:
$ npx cap sync android
✔ Copying web assets from dist to android/app/src/main/assets/public in 111.45ms
✔ copy android in 258.18ms
[info] Found 4 Capacitor plugins for android:
@capacitor/[email protected]
@capacitor/[email protected]
@capacitor/[email protected]
@capacitor/[email protected]
[info] Sync finished in 1.414s
cap initmenuliscapacitor.config.jsonberisiappId,appName, danwebDir: "dist"(jadi.tskalau TypeScript terpasang).npx cap syncmenyalindistke dalam project native dan memperbarui plugin. Jalankan setiap habisnpm run build. Web app-nya ikut di dalam file aplikasi, jadi deploy web gak mengubah aplikasi yang sudah terpasang.- Project Android-nya
minSdkVersion 24dantargetSdkVersion 36; project iOS minimal iOS 15.0 dan memakai Swift Package Manager (Package.swift), tanpa CocoaPods. - Folder
android/danios/adalah kode sumber yang di-commit dan diedit di Android Studio atau Xcode. Ini kebalikan dari Expo CNG, yang membuat ulang folder itu dariapp.json. npx cap open androidmembuka Android Studio,npx cap run iosmenjalankan build debug di simulator atau HP.
Plugin: kamera, push, preferences
Kode web yang sama jalan di browser, Android, dan iOS:
// src/js/app.js
import { Capacitor } from '@capacitor/core';
import { Camera } from '@capacitor/camera';
import { Preferences } from '@capacitor/preferences';
import { PushNotifications } from '@capacitor/push-notifications';
const platform = Capacitor.getPlatform(); // 'web', 'android', atau 'ios'
const foto = await Camera.takePhoto({ quality: 70 }); // dialog izin muncul di pemakaian pertama
document.querySelector('#nota').src = foto.webPath ?? '';
await Preferences.set({ key: 'order-terakhir', value: '13' });
// POST /api/me/push-tokens seperti di pelajaran push (token login Bearer disingkat)
const kirimKeServer = (token) =>
fetch('https://laundryburini.id/api/me/push-tokens', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, platform }),
});
await PushNotifications.requestPermissions();
await PushNotifications.addListener('registration', (t) => kirimKeServer(t.value));
await PushNotifications.register();
Camera.takePhoto()ada sejak plugin kamera 8.1.0.Camera.getPhoto()dari materi lama sekarang deprecated.Preferencesmenyimpan keUserDefaultsdi iOS danSharedPreferencesdi Android. README-nya menulis bahwa OS mobile bisa membersihkanlocalStoragesewaktu-waktu, makanya plugin ini ada.- Token dari
registrationberbeda per platform: di iOS token APNs, di Android token FCM (butuhgoogle-services.jsondari Firebase). Jadi server Laravel harus bicara ke dua layanan: APNs dan FCM. Itu jawaban tebakannya. Di Expo, keduanya dibungkus jadi satuExponentPushToken[...]untuk satu API.
| Kebutuhan | Plugin Capacitor | Di aplikasi Expo kita |
|---|---|---|
| Foto nota | @capacitor/camera 8.2.5 |
expo-camera (pelajaran sensor) |
| Simpan nilai kecil | @capacitor/preferences 8.0.1 |
MMKV atau AsyncStorage |
| Push | @capacitor/push-notifications 8.1.3: APNs dan FCM |
expo-notifications: satu token Expo |
Ionic Framework: UI yang meniru platform
Capacitor gak memberi komponen apa pun: tampilannya HTML dan CSS milikmu (Tailwind juga bisa). Ionic Framework (@ionic/react 9.0.7) memberi komponen yang gayanya ikut platform:
import { IonApp, IonBadge, IonItem, IonLabel, IonList, setupIonicReact } from '@ionic/react';
import '@ionic/react/css/core.css';
setupIonicReact(); // gaya 'ios' di iPhone, 'md' (Material Design) di Android
export function DaftarOrder({ orders }: { orders: Order[] }) {
return (
<IonApp>
<IonList>
{orders.map((o) => (
<IonItem key={o.id} button detail>
<IonLabel>#{o.id} {o.nama}</IonLabel>
<IonBadge slot="end">{o.status}</IonBadge>
</IonItem>
))}
</IonList>
</IonApp>
);
}
- Ionic 9 (rilis 19 Agustus 2026) butuh iOS 16 ke atas, React 18 atau 19, dan Capacitor 7 ke atas.
- Gesture usap untuk kembali di iOS ditulis ulang dalam kode web:
swipeGesturedi router outlet Ionic aktif bawaan di modeios. Rasanya mendekati, tapi bukan gesture bawaan sistem.
PWA: tanpa toko sama sekali
- Tombol pasang. Event
beforeinstallpromptcuma ada di Chrome (sejak versi 61) dan Samsung Internet. Safari dan Firefox gak punya. Di iPhone, pelanggan sendiri yang memilih Bagikan, lalu Tambahkan ke Layar Utama; sejak iOS 26, situs apa pun yang ditambahkan ke layar utama terbuka sebagai web app. - Push di iPhone. Web Push jalan di iOS 16.4 ke atas, dan cuma untuk web app yang sudah ditambahkan ke layar utama. Di dalam WebView (Android maupun iOS), Web Push gak tersedia: makanya Capacitor memakai plugin push native.
- Contoh nyata: BelajarWeb.dev sendiri. Situs ini aplikasi Vite dan React dengan
vite-plugin-pwa, dan ada di Google Play sebagai "Hyper Sheets - Learn Web Dev" lewat TWA (Trusted Web Activity): Chrome menampilkan PWA-nya layar penuh, dan/.well-known/assetlinks.jsonmembuktikan aplikasi dan situsnya milik orang yang sama. TWA cuma ada di Android.
Bisakah web app seperti BelajarWeb.dev jadi aplikasi Capacitor?
Secara teknis bisa: webDir: "dist" hasil Vite langsung dibungkus. Yang perlu ditimbang:
- App Store. Panduan 4.2: "Your app should include features, content, and UI that elevate it beyond a repackaged website." Website yang cuma dibungkus berisiko ditolak. Tambahkan yang khas aplikasi: push, kamera, kerja offline.
- Alamat asal berubah. Halaman di Capacitor berjalan di
https://localhost(Android) dancapacitor://localhost(iOS), jadi API Laravel harus mengizinkan dua origin itu di CORS. - Update. Kode web ada di dalam aplikasi, jadi deploy ke server gak sampai ke HP. Ionic Appflow (live update resmi) gak menerima pelanggan baru sejak 11 Februari 2025 dan berhenti 31 Desember 2027; alternatifnya layanan pihak ketiga seperti Capgo atau Capawesome Cloud.
- Versi WebView. Android System WebView di-update lewat Play Store, sedangkan WKWebView ikut versi iOS. Capacitor menganggap WebView Android di bawah versi 60 gak didukung (
minWebViewVersion).
Performa dan rasa
Untuk daftar tiga order dan form jemput, ketiganya terasa cepat. Bedanya muncul di daftar panjang, gesture, dan animasi: di WebView semuanya digambar engine browser, dan JavaScript, perhitungan layout, serta event sentuh berbagi satu main thread halaman; di React Native, daftar dan gesture adalah view native, dan animasi Reanimated jalan di UI thread (pelajaran animasi). Jangan percaya angka benchmark orang lain: ukur di HP Android paling murah yang dipakai pelanggan, dengan Chrome DevTools (chrome://inspect) untuk WebView, atau alat di pelajaran performa untuk React Native.
Tabel keputusan Laundry Bu Rini, ditinjau ulang
| Kebutuhan Bu Rini | PWA | Capacitor | Capacitor + Ionic | React Native (Expo) |
|---|---|---|---|---|
| Ada di App Store dan Play | tidak | ya, asal lebih dari website | ya, asal lebih dari website | ya |
| Push "Siap diambil" di iPhone | cuma dari layar utama | ya, server ke APNs dan FCM | ya, server ke APNs dan FCM | ya, satu token Expo |
| Daftar terasa seperti aplikasi bawaan | tidak | tidak | meniru | ya |
| Perbaikan tanpa review toko | ya | lewat pihak ketiga | lewat pihak ketiga | ya, EAS Update |
Untuk aplikasi pelanggan Bu Rini, React Native lewat Expo tetap pilihan yang jujur: semua baris "ya", dan server push-nya sudah dibangun untuk satu token Expo. Jawabannya beda kalau kondisinya beda. Seandainya Bu Rini sudah punya web pemesanan yang jadi dan timnya cuma bisa web, Capacitor adalah jalan tercepat ke toko. Untuk aplikasi kasir di tiga tablet karyawannya, PWA sudah cukup.
⚠️ Jebakan yang sering ketemu
server.urlikut ke build rilis. Dokumentasi konfigurasi Capacitor menulis "This is not intended for use in production." Aplikasi pelanggan akan mencoba memuat dev server di laptopmu dan gagal. Pakai cuma untuk live reload.- Lupa
npx cap syncsetelahnpm run build. Aplikasinya masih membawadistyang lama. - Membungkus website tanpa fitur aplikasi. Berisiko ditolak panduan 4.2 App Store.
- Mengira satu token push cukup. Capacitor memberi token APNs di iOS dan FCM di Android.
TL;DR: Capacitor 8 (8.5.3) membungkus web app yang sudah di-build (webDir: "dist") dalam WebView native dan memberi fitur HP lewat plugin; React Native me-render komponen native sesungguhnya. Capacitor paling tepat saat tim sudah punya web app yang ingin cepat dijadikan aplikasi mobile. Alurnya cap init, cap add android/ios, lalu npm run build dan npx cap sync setiap kali; android/ dan ios/ di-commit. Plugin: Camera.takePhoto() (getPhoto deprecated), Preferences (UserDefaults, SharedPreferences), dan push dengan token APNs di iOS dan FCM di Android. Ionic Framework 9 memberi komponen bergaya iOS dan Material dan meniru gesture-nya di kode web. PWA gak lewat toko: tombol pasang cuma di Chrome, iPhone lewat Tambahkan ke Layar Utama, Web Push iOS 16.4 ke atas dari layar utama; BelajarWeb.dev sendiri ada di Play lewat TWA. Timbang panduan 4.2, CORS untuk https://localhost dan capacitor://localhost, dan update yang butuh build atau live update pihak ketiga (Appflow berhenti akhir 2027). Untuk aplikasi pelanggan Laundry Bu Rini, React Native lewat Expo tetap pilihan yang tepat.