Lompat ke konten utama

Mengapa Geofence Tidak Terpicu di iOS

Geofence tidak terpicu di iOS pada aplikasi Capacitor Anda? Pelajari cara kerja region monitoring, izin, aturan radius dan limit, serta cara debug setiap kasusnya.

Mengapa Geofence Tidak Terpicu di iOS

Saat geofence tidak terpicu di iOS, penyebabnya hampir selalu salah satu dari daftar singkat ini: aplikasi kurang izin Always, perangkat sudah berada di dalam region saat ditambahkan, radius terlalu kecil untuk dideteksi iOS, aplikasi mencapai limit 20 region, atau pengujian kurang lama. Geofencing iOS bekerja dengan baik, namun ia melaporkan crossing sesuai jadwalnya sendiri. Panduan ini menjelaskan bagaimana region monitoring memutuskan kapan akan aktif, dan cara debug aplikasi Capacitor menggunakan @capgo/background-geolocation, yang mencakup native geofencing di iOS dan Android.

Cara kerja monitoring region di iOS

Di iOS, geofence adalah CLCircularRegion objek yang didaftarkan ke Core Location. Setelah terdaftar, sistem operasi yang akan memonitornya, bukan aplikasi Anda. Aplikasi Anda bisa dalam kondisi suspended atau tidak berjalan, namun iOS tetap melacak region tersebut menggunakan kombinasi cell tower, Wi-Fi, dan GPS agar penggunaan baterai tetap rendah.

Saat iOS mendeteksi perangkat melewati batas, ia akan mengirimkan event enter atau exit ke aplikasi, serta menjalankan aplikasi di background jika diperlukan dan diizinkan. Ada beberapa aturan yang mengatur keputusan tersebut:

  • iOS tidak melaporkan perpindahan tepat saat perangkat menyentuh batas. Panduan Apple menyatakan bahwa perangkat harus melewati batas, bergerak sejauh jarak minimum, dan menetap di sana selama setidaknya sekitar 20 detik sebelum event dikirimkan. Ini dilakukan untuk menghindari error akibat GPS jitter.
  • Akurasi lokasi untuk monitoring region bergantung pada sinyal radio di sekitar. Di kota dengan Wi-Fi padat, prosesnya bisa cepat. Di jalan pedesaan, bisa memakan waktu beberapa menit.
  • Event hanya berlaku untuk transisi. Berada di dalam sebuah region saat monitoring dimulai tidak akan dianggap sebagai event entry.

Setup geofencing di aplikasi Capacitor

Install plugin dan konfigurasi iOS keys:

bun add @capgo/background-geolocation
bunx cap sync
<key>NSLocationWhenInUseUsageDescription</key>
<string>We use your location to detect when you arrive at a store.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need Always access to notify you when you arrive, even when the app is closed.</string>

Kemudian daftarkan region:

import { BackgroundGeolocation } from '@capgo/background-geolocation';

await BackgroundGeolocation.setupGeofencing({
  url: 'https://api.example.com/v1/geofence-events',
  headers: { Authorization: 'Bearer <token>' },
  notifyOnEntry: true,
  notifyOnExit: true,
  payload: { userId: 'u-42' },
});

await BackgroundGeolocation.addGeofence({
  identifier: 'store-paris-11',
  latitude: 48.8606,
  longitude: 2.3795,
  radius: 150,
  payload: { storeId: 'paris-11' },
});

await BackgroundGeolocation.addListener('geofenceTransition', (event) => {
  console.log(`${event.transition} ${event.identifier}`, event.payload);
});

await BackgroundGeolocation.addListener('geofenceError', (event) => {
  console.error('Geofence error', event.identifier, event.code, event.message);
});

setupGeofencing meminta permission yang dibutuhkan geofencing secara default (requestPermissions defaultnya adalah true). Di iOS, itu berarti Always.

Sekarang, kemungkinan penyebab kegagalannya.

1. Anda tidak memiliki otorisasi Always

Region monitoring di iOS butuh otorisasi Always. Jika hanya menggunakan While Using App, region Anda tidak akan mengirimkan event saat aplikasi di background atau tidak berjalan, padahal itulah fungsi utama geofence.

Cek sebelum mendaftarkan region, dan jelaskan permintaan tersebut di UI Anda terlebih dahulu:

const status = await BackgroundGeolocation.checkPermissions();

if (status.backgroundLocation !== 'always' && status.backgroundLocation !== 'granted') {
  // Show your own screen explaining the feature, then:
  const next = await BackgroundGeolocation.requestPermissions({
    permissions: ['backgroundLocation'],
  });
  if (next.backgroundLocation === 'when_in_use' || next.backgroundLocation === 'denied') {
    await BackgroundGeolocation.openSettings();
  }
}

Perlu dicatat bahwa iOS mungkin tidak langsung menampilkan prompt upgrade ke Always. Pengguna yang memilih “Allow While Using App” mungkin baru melihat prompt kedua di kemudian hari. Pengguna yang memilih “Allow Once” mendapatkan izin sementara yang akan direset. Jika geofencing adalah fitur utama, cek statusnya setiap kali aplikasi dimulai dan tampilkan banner yang jelas jika statusnya bukan Always.

2. Perangkat sudah berada di dalam region

Jika Anda menambahkan geofence saat ponsel sudah berada di dalamnya, iOS tidak akan mengirimkan event enter. Tidak ada batas yang dilewati. Tim pengembang sering mengalami ini saat testing di meja kerja dengan region di sekitar kantor.

Perbaiki di aplikasi Anda: saat mendaftarkan region, bandingkan posisi saat ini dengan region tersebut dan tangani kondisi “sudah di dalam” secara manual.

import { Geolocation } from '@capacitor/geolocation';

function distanceMeters(lat1: number, lon1: number, lat2: number, lon2: number) {
  const R = 6371000;
  const toRad = (d: number) => (d * Math.PI) / 180;
  const dLat = toRad(lat2 - lat1);
  const dLon = toRad(lon2 - lon1);
  const a =
    Math.sin(dLat / 2) ** 2 +
    Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
  return 2 * R * Math.asin(Math.sqrt(a));
}

const region = { identifier: 'store-paris-11', latitude: 48.8606, longitude: 2.3795, radius: 150 };
await BackgroundGeolocation.addGeofence(region);

const pos = await Geolocation.getCurrentPosition({ enableHighAccuracy: true });
if (distanceMeters(pos.coords.latitude, pos.coords.longitude, region.latitude, region.longitude) < region.radius) {
  handleAlreadyInside(region.identifier);
}

declare function handleAlreadyInside(id: string): void;

Untuk mengetes event enter, berjalanlah atau berkendaralah keluar melewati radius, tunggu, lalu kembali lagi.

3. Radius terlalu kecil

iOS menerima radius kecil, tetapi reliabilitasnya menurun drastis di bawah 100 meter, karena region monitoring bergantung pada Wi-Fi dan posisi seluler. Region 30 meter di sekitar pintu toko mungkin terlambat terdeteksi, terdeteksi setelah pelanggan pergi, atau tidak terdeteksi sama sekali.

Nilai praktis:

Kasus penggunaan Radius yang disarankan
Kedatangan di toko atau restoran 100 hingga 200 m
Kantor, kampus, gudang 150 hingga 300 m
Lingkungan atau zona kota 500 m ke atas

Jika butuh presisi hingga level pintu, gabungkan geofence yang lebih besar dengan foreground location atau beacon setelah pengguna berada di dalam. Capgo juga punya plugin iBeacon untuk proximity indoor.

4. Anda mencapai batas 20 region

Aplikasi iOS maksimal hanya bisa memantau 20 region sekaligus. Jika Anda menambah lebih banyak, registrasi tambahan akan gagal dan muncul error monitoring.

Gunakan getMonitoredGeofences() untuk melihat apa yang benar-benar terdaftar, dan menjaga set region terdekat secara bergantian:

const { regions } = await BackgroundGeolocation.getMonitoredGeofences();
console.log(`Monitoring ${regions.length} regions`, regions);

Pola yang umum digunakan:

  1. Simpan daftar lengkap lokasi Anda di server.
  2. Saat aplikasi dimulai, atau saat user berpindah jauh (misalnya saat keluar dari region “refresh” besar di sekitar user), ambil 19 lokasi terdekat.
  3. Panggil removeAllGeofences(), lalu tambahkan 19 lokasi terdekat plus satu region besar yang berpusat pada user. Keluar dari region besar tersebut adalah sinyal untuk melakukan refresh.

Android mengizinkan hingga 100 geofence per aplikasi, jadi code yang berjalan di Android bisa gagal di iOS hanya karena alasan ini.

5. Pengujian terlalu singkat atau terlalu statis

iOS melaporkan transisi hanya setelah perangkat benar-benar melewati dan menetap di sisi lain. Jika Anda melewati region 150 meter dengan kecepatan 50 km/jam, Anda hanya berada di dalamnya sekitar 20 detik. Itu mungkin tidak cukup.

Saat melakukan pengujian:

  • Tetaplah di luar selama semenit, lalu masuk ke dalam dan diam di sana selama minimal beberapa menit.
  • Tes dengan Wi-Fi menyala. Mematikan Wi-Fi membuat monitoring region menjadi jauh kurang akurat, meskipun Anda tidak terhubung ke jaringan apa pun.
  • Jangan mengandalkan Simulator untuk urusan timing. Gunakan GPX route di Xcode untuk mengecek handler Anda, lalu tes langsung di perangkat.

6. Event terpicu, tapi JavaScript Anda tidak berjalan

Saat iOS menjalankan ulang aplikasi Anda di background untuk sebuah region event, plugin native menerimanya, tetapi Capacitor WebView mungkin belum dimuat atau cepat-cepat ditangguhkan kembali. geofenceTransition listener hanya akan terpicu saat WebView sedang aktif.

Itulah alasannya setupGeofencing menerima sebuah url. Plugin melakukan POST pada transisi dari native code, termasuk hasil merge payload Anda, sehingga backend Anda tetap menerimanya meskipun JavaScript tidak pernah berjalan. Header disimpan bersama setup agar tetap berfungsi setelah relaunch, dan Anda bisa merotasi header tersebut dengan updateHeaders().

Delivery bersifat best effort, tanpa antrean retry. Pastikan endpoint Anda cepat dan idempotent, serta catat setiap request selama pengujian.

7. Location Services atau Background App Refresh mati

Cek hal berikut pada perangkat uji:

  • Settings, Privacy & Security, pastikan Location Services aktif.
  • Setel aplikasi Anda ke Always.
  • Precise Location aktif untuk aplikasi Anda. Tanpanya, area kecil tidak akan akurat.
  • Matikan Low Power Mode saat pengujian awal. Mode ini mengurangi aktivitas background.

8. Reboot dan update aplikasi

iOS menyimpan region yang dipantau meski aplikasi ditutup. Setelah restart perangkat, pemantauan berlanjut saat sistem aktif, namun aplikasi Anda harus tetap sinkronisasi ulang region saat launch: getMonitoredGeofences() bandingkan dengan ekspektasi Anda dan tambahkan kembali yang hilang. Lakukan hal yang sama setelah update aplikasi, atau saat server mengubah daftar lokasi.

Di Android, geofence dihapus setelah reboot dan beberapa kondisi lain (lokasi mati, data aplikasi dihapus), jadi registrasi ulang saat launch memang wajib. Melakukannya di kedua platform membuat logika tetap simpel.

9. Paksa berhenti (Force quit)

Jika user melakukan force quit aplikasi via app switcher, iOS menganggap user tidak ingin aplikasi berjalan. Perilaku relaunch region setelah force quit berubah di berbagai versi iOS. Jangan buat fitur yang hanya jalan jika aplikasi di-relaunch setelah force quit, dan tes pada versi iOS yang digunakan user Anda.

Checklist debugging

Periksa Cara
Izin Selalu Aktif checkPermissions() mengembalikan always atau granted untuk backgroundLocation
Region terdaftar getMonitoredGeofences() menampilkan identifier
Di bawah 20 region Hitung dari getMonitoredGeofences()
Radius ≥ 100 m Tinjau addGeofence panggilan
Tidak sedang berada di dalam Bandingkan posisi saat ini dengan registrasi
Error dicatat di logs Dengarkan geofenceError
Backend menerima event Atur url di setupGeofencing dan log request
Tes pergerakan nyata Keluar dari region sepenuhnya, tunggu, kembali dan menetap

Perbedaan Android yang perlu diperhatikan

Jika code yang sama berfungsi di Android tapi tidak di iOS, batasan 20 wilayah dan syarat Always biasanya menjadi penyebabnya. Jika berfungsi di iOS tapi tidak di Android, pastikan Anda sudah menambahkan ACCESS_BACKGROUND_LOCATION ke manifest Anda dan mengatur backgroundLocation: true di dalam setupGeofencing. Plugin tidak menambahkan izin tersebut secara otomatis, karena Google Play memerlukan deklarasi untuk lokasi latar belakang (background location).

Meluncurkan perubahan

String izin dan konfigurasi native memerlukan build baru. Daftar wilayah, nilai radius, dan teks UI dapat diubah di sisi server atau dikirim melalui live updates Capgo. Untuk pelacakan berkelanjutan alih-alih event enter dan exit, lihat mengapa iOS menghentikan update lokasi latar belakang, dan plugin tersebut dokumentasi plugin untuk API selengkapnya.

Live update untuk aplikasi Capacitor

Saat bug di web layer sudah live, kirim perbaikannya lewat Capgo alih-alih menunggu berhari-hari untuk persetujuan app store. Pengguna menerima update di background, sementara perubahan native tetap di jalur review normal.

Terbaru dari Blog kami

Capgo memberikan insight terbaik yang Anda butuhkan untuk membuat aplikasi mobile yang benar-benar profesional.