Mengakses GPS lewat `@capacitor/geolocation` untuk watch position dan akurasi, menyimpan data persisten dengan `@capacitor/preferences`, serta memahami kapan pakai Preferences vs IndexedDB vs SQLite untuk berbagai kebutuhan storage.

Setelah di episode 6 kita menguasai Camera dan Filesystem, pada episode ini kita mendalami dua kemampuan native lain yang sangat umum di aplikasi mobile: lokasi GPS dan penyimpanan data persisten. Kombinasi keduanya memungkinkan kalian membangun fitur seperti tracker lokasi, rekomendasi berbasis lokasi, dan pengaturan user yang tetap tersimpan.
Mengapa topik ini penting? Karena hampir semua aplikasi mobile modern membutuhkan lokasi user (untuk peta, pengiriman, atau konten lokal) dan penyimpanan preferensi (theme, bahasa, token autentikasi).
npm install @capacitor/geolocation
npx cap syncimport { Geolocation } from '@capacitor/geolocation';
async function getCurrentPosition() {
const position = await Geolocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0,
});
console.log('Latitude:', position.coords.latitude);
console.log('Longitude:', position.coords.longitude);
console.log('Accuracy:', position.coords.accuracy, 'meter');
return position;
}| Opsi | Deskripsi |
|---|---|
enableHighAccuracy | Gunakan GPS hardware (lebih akurat, lebih boros baterai) |
timeout | Maksimal waktu tunggu dalam milidetik |
maximumAge | toleransi cache posisi lama (0 = selalu dapat baru) |
Untuk tracking lokasi real-time:
import { Geolocation } from '@capacitor/geolocation';
let watchId: string | null = null;
async function startTracking() {
watchId = await Geolocation.watchPosition(
{
enableHighAccuracy: true,
distanceFilter: 10, // update setiap 10 meter
},
(position, err) => {
if (position) {
console.log('New position:', position.coords.latitude, position.coords.longitude);
// Update UI atau kirim ke server
}
if (err) {
console.error('Location error:', err);
}
}
);
}
function stopTracking() {
if (watchId) {
Geolocation.clearWatch({ id: watchId });
watchId = null;
}
}import { Geolocation } from '@capacitor/geolocation';
async function checkLocationPermission() {
const status = await Geolocation.checkPermissions();
if (status.location === 'denied') {
const newStatus = await Geolocation.requestPermissions();
if (newStatus.location === 'denied') {
console.log('Permission lokasi ditolak');
}
}
}Note
Di iOS, NSLocationWhenInUseUsageDescription harus didefinisikan di Info.plist. Di Android, <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> harus ada di AndroidManifest.xml. Capacitor menambahkan ini otomatis, tetapi pastikan deskripsi permission wajar dan jelas.
npm install @capacitor/preferences
npx cap syncimport { Preferences } from '@capacitor/preferences';
// Simpan data
await Preferences.set({ key: 'user_theme', value: 'dark' });
await Preferences.set({ key: 'auth_token', value: 'eyJhbGciOiJIUzI1...' });
// Baca data
const theme = await Preferences.get({ key: 'user_theme' });
console.log('Theme:', theme.value); // "dark"
// Hapus data
await Preferences.remove({ key: 'auth_token' });
// Hapus semua data
await Preferences.clear();import { Preferences } from '@capacitor/preferences';
interface UserSettings {
theme: string;
language: string;
notifications: boolean;
}
const settings: UserSettings = {
theme: 'dark',
language: 'id',
notifications: true,
};
// Simpan
await Preferences.set({
key: 'user_settings',
value: JSON.stringify(settings),
});
// Baca dan parse
const stored = await Preferences.get({ key: 'user_settings' });
if (stored.value) {
const parsed: UserSettings = JSON.parse(stored.value);
console.log(parsed.theme); // "dark"
}| Kebanyakan | Preferences | IndexedDB | SQLite (Community) |
|---|---|---|---|
| Data | Key-value sederhana | Object complex, array besar | Structured data, relasional |
| Ukuran | ~6 MB (iOS), unlimited (Android) | ~50 MB+ | ~100 MB+ |
| Query | Get/set by key | Cursor, index, range query | SQL queries, JOIN |
| Use case | Settings, token, flag | Cache, offline data, catalog | Database relasional, CRUD kompleks |
| Performa | Sangat cepat | Cepat untuk batch | Optimal untuk query kompleks |
Gunakan Preferences untuk: theme, bahasa, token autentikasi, onboarding status, flag feature. Data yang tipikal berukuran di bawah 1 KB per key.
IndexedDB tersedia di WebView tanpa plugin tambahan. Cocok untuk cache data API, array objek besar, dan data yang perlu di-query by index.
Butuh plugin community (@capacitor-community/sqlite). Cocok untuk aplikasi yang membutuhkan SQL queries, relasi antar tabel, dan data relasional kompleks — misalnya aplikasi catatan atau task manager dengan filtering canggih.
Tip
Mulai dari Preferences untuk data sederhana. Jika kebutuhan tumbuh ke query kompleks atau data relasional, baru pertimbangkan SQLite. Jangan over-engineer dari awal.
import { Geolocation } from '@capacitor/geolocation';
import { Preferences } from '@capacitor/preferences';
async function initTracker() {
// Ambil setting terakhir
const saved = await Preferences.get({ key: 'last_position' });
if (saved.value) {
const last = JSON.parse(saved.value);
console.log('Last known position:', last.lat, last.lng);
}
// Mulai tracking
await Geolocation.watchPosition(
{ enableHighAccuracy: true, distanceFilter: 50 },
async (position) => {
if (position) {
// Simpan posisi terakhir
await Preferences.set({
key: 'last_position',
value: JSON.stringify({
lat: position.coords.latitude,
lng: position.coords.longitude,
timestamp: position.timestamp,
}),
});
}
}
);
}Pada episode 7 ini, kalian telah memahami:
@capacitor/geolocation untuk getCurrentPosition dan watchPosition.@capacitor/preferences untuk key-value storage persisten.Di episode 8 selanjutnya, kita akan membahas Push & Local Notifications — registrasi token FCM/APNs, push notification handling, notifikasi terjadwal, dan setup FCM + test push end-to-end. Sampai jumpa!