Membuat dan memantau pembatasan wilayah

Pembatasan wilayah menggabungkan kemampuan penentuan lokasi pengguna saat ini dan kemampuan penentuan kedekatan lokasi pengguna dengan lokasi tertentu. Untuk menandai lokasi tertentu, Anda harus menentukan lintang dan bujurnya. Untuk menyesuaikan kedekatan lokasi, Anda harus menambahkan radius. Lintang, bujur, dan radius menentukan pembatasan wilayah, yang menciptakan area lingkaran, atau pembatas, di sekitar lokasi tertentu.

Anda dapat memiliki beberapa pembatasan wilayah aktif, dengan batas 100 per pengguna perangkat per aplikasi. Untuk setiap pembatasan wilayah, Anda dapat meminta Layanan Lokasi untuk mengirimi Anda peristiwa masuk dan keluar, atau menentukan durasi di area pembatasan wilayah untuk menunggu, atau diam, sebelum memicu suatu peristiwa. Anda dapat membatasi durasi pembatasan wilayah dengan menentukan durasi akhir dalam milidetik. Setelah pembatasan wilayah berakhir, Layanan Lokasi otomatis akan menghapusnya.

Tutorial ini menunjukkan cara menambahkan dan menghapus pembatasan wilayah, kemudian mendeteksi transisi pembatasan wilayah menggunakan BroadcastReceiver.

Catatan: Di perangkat Wear, Geofencing API tidak menggunakan daya secara efisien. Kami tidak merekomendasikan API ini di Wear. Baca Menghemat daya dan baterai untuk mengetahui informasi selengkapnya.

Menyiapkan pemantauan pembatasan wilayah

Langkah pertama dalam meminta pemantauan pembatasan wilayah adalah meminta izin yang diperlukan. Untuk menggunakan pembatasan wilayah, aplikasi Anda harus meminta izin berikut:

Untuk mempelajarinya lebih lanjut, lihat panduan cara meminta izin akses lokasi.

Jika Anda ingin menggunakan BroadcastReceiver untuk mendeteksi transisi pembatasan wilayah, tambahkan elemen yang menentukan nama layanan. Elemen ini harus berupa turunan dari elemen <application>:

<application
   android:allowBackup="true">
   ...
   <receiver android:name=".GeofenceBroadcastReceiver"/>
<application/>

Untuk mengakses location API, Anda harus membuat instance klien Pembatasan Wilayah. Untuk mempelajari cara menghubungkan klien Anda:

Kotlin

lateinit var geofencingClient: GeofencingClient

override fun onCreate(savedInstanceState: Bundle?) {
    // ...
    geofencingClient = LocationServices.getGeofencingClient(this)
}

Java

private GeofencingClient geofencingClient;

@Override
public void onCreate(Bundle savedInstanceState) {
    // ...
    geofencingClient = LocationServices.getGeofencingClient(this);
}

Membuat dan menambahkan pembatasan wilayah

Aplikasi Anda harus membuat dan menambahkan pembatasan wilayah menggunakan class builder location API untuk membuat objek Pembatasan Wilayah, dan class praktis untuk menambahkannya. Selain itu, untuk menangani intent yang dikirim dari Layanan Lokasi saat transisi pembatasan wilayah terjadi, Anda dapat menentukan PendingIntent seperti yang ditunjukkan dalam bagian ini.

Catatan: Pada perangkat pengguna tunggal, ada batas 100 pembatasan wilayah per aplikasi. Untuk perangkat multi-pengguna, batasnya sebanyak 100 pembatasan wilayah per aplikasi per pengguna perangkat.

Membuat objek pembatasan wilayah

Pertama, gunakan Geofence.Builder untuk membuat pembatasan wilayah, dengan menyetel radius, durasi, dan jenis transisi untuk pembatasan wilayah. Misalnya, untuk mengisi objek daftar:

Kotlin

geofenceList.add(Geofence.Builder()
        // Set the request ID of the geofence. This is a string to identify this
        // geofence.
        .setRequestId(entry.key)

        // Set the circular region of this geofence.
        .setCircularRegion(
                entry.value.latitude,
                entry.value.longitude,
                Constants.GEOFENCE_RADIUS_IN_METERS
        )

        // Set the expiration duration of the geofence. This geofence gets automatically
        // removed after this period of time.
        .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)

        // Set the transition types of interest. Alerts are only generated for these
        // transition. We track entry and exit transitions in this sample.
        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)

        // Create the geofence.
        .build())

Java

geofenceList.add(new Geofence.Builder()
    // Set the request ID of the geofence. This is a string to identify this
    // geofence.
    .setRequestId(entry.getKey())

    .setCircularRegion(
            entry.getValue().latitude,
            entry.getValue().longitude,
            Constants.GEOFENCE_RADIUS_IN_METERS
    )
    .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
            Geofence.GEOFENCE_TRANSITION_EXIT)
    .build());

Contoh ini menarik data dari file konstanta. Dalam praktik nyata, aplikasi mungkin secara dinamis akan membuat pembatasan wilayah berdasarkan lokasi pengguna.

Menentukan pembatasan wilayah dan pemicu awal

Cuplikan berikut menggunakan class GeofencingRequest dan class GeofencingRequestBuilder bertingkatnya untuk menentukan pembatasan wilayah yang akan dipantau dan untuk menyetel cara memicu peristiwa pembatasan wilayah terkait:

Kotlin

private fun getGeofencingRequest(): GeofencingRequest {
    return GeofencingRequest.Builder().apply {
        setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
        addGeofences(geofenceList)
    }.build()
}

Java

private GeofencingRequest getGeofencingRequest() {
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
    builder.addGeofences(geofenceList);
    return builder.build();
}

Contoh berikut menunjukkan penggunaan dua pemicu pembatasan wilayah. Transisi GEOFENCE_TRANSITION_ENTER dipicu saat perangkat memasuki pembatasan wilayah, dan transisi GEOFENCE_TRANSITION_EXIT dipicu saat perangkat keluar dari pembatasan wilayah. Menentukan INITIAL_TRIGGER_ENTER akan memberi tahu Layanan lokasi bahwa GEOFENCE_TRANSITION_ENTER harus dipicu jika perangkat sudah berada di dalam pembatasan wilayah.

Dalam banyak kasus, mungkin lebih baik gunakan INITIAL_TRIGGER_DWELL, yang memicu peristiwa hanya saat pengguna berhenti selama durasi yang ditentukan dalam pembatasan wilayah. Pendekatan ini dapat membantu mengurangi "notifikasi spam" yang dihasilkan dari notifikasi dalam jumlah banyak saat perangkat masuk dan keluar sebentar dari pembatasan wilayah. Strategi lain untuk mendapatkan hasil terbaik dari pembatasan wilayah Anda adalah menetapkan radius minimum sejauh 100 meter. Cara ini membantu memperhitungkan akurasi lokasi jaringan Wi-Fi biasa, dan juga membantu mengurangi konsumsi daya perangkat.

Menentukan penerima siaran untuk transisi pembatasan wilayah

Suatu Intent yang dikirim dari Layanan Lokasi dapat memicu berbagai tindakan di aplikasi Anda, tetapi Anda tidak boleh membiarkannya memulai aktivitas atau fragmen, karena komponen seharusnya hanya terlihat sebagai respons terhadap tindakan pengguna. Dalam banyak kasus, BroadcastReceiver adalah cara yang baik untuk menangani transisi pembatasan wilayah. Suatu BroadcastReceiver akan mendapatkan update saat suatu peristiwa terjadi, seperti transisi masuk atau keluar dari pembatasan wilayah, dan dapat memulai tugas latar belakang yang berjalan lama.

Cuplikan berikut menunjukkan cara menentukan PendingIntent yang memulai BroadcastReceiver:

Kotlin

class MainActivity : AppCompatActivity() {

    // ...

    private val geofencePendingIntent: PendingIntent by lazy {
        val intent = Intent(this, GeofenceBroadcastReceiver::class.java)
        // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
        // addGeofences() and removeGeofences().
        PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
    }
}

Java

public class MainActivity extends AppCompatActivity {

    // ...

    private PendingIntent getGeofencePendingIntent() {
        // Reuse the PendingIntent if we already have it.
        if (geofencePendingIntent != null) {
            return geofencePendingIntent;
        }
        Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
        // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
        // calling addGeofences() and removeGeofences().
        geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.
                FLAG_UPDATE_CURRENT);
        return geofencePendingIntent;
    }

Menambahkan pembatasan wilayah

Untuk menambahkan pembatasan wilayah, gunakan metode GeofencingClient.addGeofences(). Berikan objek GeofencingRequest, dan PendingIntent. Cuplikan berikut menunjukkan pemrosesan hasilnya:

Kotlin

geofencingClient?.addGeofences(getGeofencingRequest(), geofencePendingIntent)?.run {
    addOnSuccessListener {
        // Geofences added
        // ...
    }
    addOnFailureListener {
        // Failed to add geofences
        // ...
    }
}

Java

geofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
        .addOnSuccessListener(this, new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                // Geofences added
                // ...
            }
        })
        .addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Failed to add geofences
                // ...
            }
        });

Menangani transisi pembatasan wilayah

Saat mendeteksi bahwa pengguna telah masuk atau keluar dari pembatasan wilayah, Layanan Lokasi akan mengirimkan Intent yang ada di dalam PendingIntent yang Anda sertakan dalam permintaan untuk menambahkan pembatasan wilayah. Penerima siaran seperti GeofenceBroadcastReceiver mengetahui bahwa Intent dipanggil, kemudian dapat memperoleh peristiwa pembatasan wilayah dari intent, menentukan jenis transisi Pembatasan Wilayah, dan menentukan pembatasan wilayah yang ditetapkan mana yang dipicu. Penerima siaran dapat mengarahkan aplikasi agar mulai menjalankan tugas di latar belakang atau, jika diinginkan, mengirim notifikasi sebagai output.

Catatan: Di Android 8.0 (API level 26) dan yang lebih baru, jika aplikasi berjalan di latar belakang sambil memantau pembatasan wilayah, perangkat akan merespons peristiwa pembatasan wilayah setiap beberapa menit. Untuk mempelajari cara menyesuaikan aplikasi Anda dengan batas respons ini, baca Batas Lokasi Latar Belakang.

Cuplikan berikut menunjukkan cara menentukan BroadcastReceiver yang memposting notifikasi jika transisi pembatasan wilayah terjadi. Saat pengguna mengklik notifikasi, aktivitas utama aplikasi akan muncul:

Kotlin

class GeofenceBroadcastReceiver : BroadcastReceiver() {
    // ...
    override fun onReceive(context: Context?, intent: Intent?) {
        val geofencingEvent = GeofencingEvent.fromIntent(intent)
        if (geofencingEvent.hasError()) {
            val errorMessage = GeofenceStatusCodes
                    .getStatusCodeString(geofencingEvent.errorCode)
            Log.e(TAG, errorMessage)
            return
        }

        // Get the transition type.
        val geofenceTransition = geofencingEvent.geofenceTransition

        // Test that the reported transition was of interest.
        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER |
                geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {

            // Get the geofences that were triggered. A single event can trigger
            // multiple geofences.
            val triggeringGeofences = geofencingEvent.triggeringGeofences

            // Get the transition details as a String.
            val geofenceTransitionDetails = getGeofenceTransitionDetails(
                    this,
                    geofenceTransition,
                    triggeringGeofences
            )

            // Send notification and log the transition details.
            sendNotification(geofenceTransitionDetails)
            Log.i(TAG, geofenceTransitionDetails)
        } else {
            // Log the error.
            Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
                    geofenceTransition))
        }
    }
}

Java

public class GeofenceBroadcastReceiver extends BroadcastReceiver {
    // ...
    protected void onReceive(Context context, Intent intent) {
        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
        if (geofencingEvent.hasError()) {
            String errorMessage = GeofenceStatusCodes
                    .getStatusCodeString(geofencingEvent.getErrorCode());
            Log.e(TAG, errorMessage);
            return;
        }

        // Get the transition type.
        int geofenceTransition = geofencingEvent.getGeofenceTransition();

        // Test that the reported transition was of interest.
        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
                geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {

            // Get the geofences that were triggered. A single event can trigger
            // multiple geofences.
            List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();

            // Get the transition details as a String.
            String geofenceTransitionDetails = getGeofenceTransitionDetails(
                    this,
                    geofenceTransition,
                    triggeringGeofences
            );

            // Send notification and log the transition details.
            sendNotification(geofenceTransitionDetails);
            Log.i(TAG, geofenceTransitionDetails);
        } else {
            // Log the error.
            Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
                    geofenceTransition));
        }
    }
}

Setelah mendeteksi peristiwa transisi melalui PendingIntent, BroadcastReceiver akan mendapatkan jenis transisi pembatasan wilayah dan menguji apakah peristiwa tersebut termasuk salah satu yang digunakan aplikasi untuk memicu notifikasi -- dalam hal ini entah GEOFENCE_TRANSITION_ENTER ataupun GEOFENCE_TRANSITION_EXIT. Layanan tersebut kemudian mengirimkan notifikasi dan mencatat detail transisi.

Menghentikan pemantauan pembatasan wilayah

Penghentian pemantauan pembatasan wilayah saat tidak lagi diperlukan atau diinginkan dapat membantu menghemat daya baterai dan siklus CPU pada perangkat. Anda dapat menghentikan pemantauan pembatasan wilayah dalam aktivitas utama yang digunakan untuk menambahkan dan menghapus pembatasan wilayah; penghapusan pembatasan wilayah akan menghentikannya secara langsung. API menyediakan metode untuk menghapus pembatasan wilayah dengan ID permintaan, atau dengan menghapus pembatasan wilayah yang terkait dengan PendingIntent tertentu.

Cuplikan berikut menghapus pembatasan wilayah dengan PendingIntent, yang akan menghentikan semua notifikasi berikutnya saat perangkat masuk atau keluar dari pembatasan wilayah yang telah ditambahkan sebelumnya:

Kotlin

geofencingClient?.removeGeofences(geofencePendingIntent)?.run {
    addOnSuccessListener {
        // Geofences removed
        // ...
    }
    addOnFailureListener {
        // Failed to remove geofences
        // ...
    }
}

Java

geofencingClient.removeGeofences(getGeofencePendingIntent())
        .addOnSuccessListener(this, new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                // Geofences removed
                // ...
            }
        })
        .addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Failed to remove geofences
                // ...
            }
        });

Anda dapat menggabungkan pembatasan wilayah dengan fitur kemampuan penentuan lokasi lainnya, seperti pembaruan lokasi berkala. Untuk informasi selengkapnya, lihat tutorial lain di kelas ini.

Menggunakan praktik terbaik untuk pembatasan wilayah

Bagian ini menguraikan rekomendasi untuk menggunakan pembatasan wilayah dengan location API bagi Android.

Mengurangi konsumsi daya

Anda dapat menggunakan teknik berikut untuk mengoptimalkan konsumsi daya di aplikasi Anda yang menggunakan pembatasan wilayah:

  • Tetapkan responsivitas notifikasi ke nilai yang lebih tinggi. Hal tersebut akan mengoptimalkan konsumsi daya dengan menambah latensi notifikasi pembatasan wilayah. Misalnya, jika Anda menyetel nilai respons selama lima menit, aplikasi Anda hanya akan memeriksa notifikasi masuk atau keluar satu kali setiap lima menit. Menyetel nilai yang lebih rendah tidak selalu berarti bahwa pengguna akan mendapat notifikasi dalam periode waktu tersebut (misalnya, jika Anda menyetel nilai 5 detik, mungkin butuh waktu sedikit lebih lama untuk menerima notifikasi).

  • Gunakan radius pembatasan wilayah yang lebih besar untuk lokasi tempat pengguna menghabiskan banyak waktu, seperti rumah atau kantor. Radius yang lebih besar tidak akan secara langsung mengurangi konsumsi daya, tetapi akan mengurangi frekuensi pemeriksaan masuk atau keluar oleh aplikasi, yang pada praktiknya akan menurunkan konsumsi daya secara keseluruhan.

Memilih radius optimal untuk pembatasan wilayah Anda

Untuk hasil terbaik, radius minimum pembatasan wilayah harus disetel 100 - 150 meter. Jika Wi-Fi tersedia, akurasi lokasi biasanya antara 20 - 50 meter. Jika lokasi dalam ruangan tersedia, rentang akurasi dapat sekecil 5 meter. Kecuali jika Anda tahu ada lokasi dalam ruangan yang tersedia di dalam pembatasan wilayah, anggaplah akurasi lokasi Wi-Fi sekitar 50 meter.

Jika lokasi Wi-Fi tidak tersedia (misalnya, ketika Anda mengemudi di daerah pedesaan) akurasi lokasi akan menurun. Rentang akurasi dapat mencapai beberapa ratus meter hingga beberapa kilometer. Dalam kasus seperti ini, Anda harus membuat pembatasan wilayah dengan radius yang lebih besar.

Menjelaskan kepada pengguna mengapa aplikasi Anda menggunakan pembatasan wilayah

Karena aplikasi Anda mengakses lokasi di latar belakang saat Anda menggunakan pembatasan wilayah, pertimbangkan cara aplikasi memberikan manfaat kepada pengguna. Jelaskan kepada mereka dengan jelas mengapa aplikasi Anda memerlukan akses ini untuk meningkatkan pemahaman pengguna dan transparansi.

Untuk informasi selengkapnya tentang praktik terbaik terkait akses lokasi, termasuk pembatasan wilayah, lihat halaman praktik terbaik privasi.

Menggunakan jenis transisi diam untuk mengurangi notifikasi spam

Jika Anda menerima banyak notifikasi saat berkendara sebentar melewati suatu pembatasan wilayah, cara terbaik untuk mengurangi notifikasi adalah dengan menggunakan jenis transisi GEOFENCE_TRANSITION_DWELL, bukan GEOFENCE_TRANSITION_ENTER. Dengan cara ini, notifikasi diam akan dikirim hanya saat pengguna berhenti di dalam pembatasan wilayah selama jangka waktu tertentu. Anda dapat memilih durasinya dengan menyetel penundaan loitering.

Mendaftarkan ulang pembatasan wilayah hanya jika diperlukan

Pembatasan wilayah terdaftar disimpan dalam proses com.google.process.location yang dimiliki oleh paket com.google.android.gms. Aplikasi tidak perlu melakukan apa pun untuk menangani peristiwa berikut, karena sistem akan memulihkan pembatasan wilayah setelah peristiwa ini:

  • Layanan Google Play diupgrade.
  • Layanan Google Play dimatikan dan dimulai ulang oleh sistem karena pembatasan resource.
  • Proses lokasi terhenti.

Aplikasi harus mendaftarkan ulang pembatasan wilayah jika masih diperlukan setelah peristiwa berikut, karena sistem tidak dapat memulihkan pembatasan wilayah dalam kasus berikut:

  • Perangkat dimulai ulang. Aplikasi harus memproses tindakan booting lengkap perangkat, kemudian mendaftarkan ulang pembatasan wilayah yang diperlukan.
  • Aplikasi dihapus dan diinstal ulang.
  • Data aplikasi dihapus.
  • Data layanan Google Play dihapus.
  • Aplikasi menerima pemberitahuan GEOFENCE_NOT_AVAILABLE. Ini biasanya terjadi setelah NLP (Penyedia Lokasi Jaringan Android) dinonaktifkan.

Memecahkan masalah peristiwa masuk pembatasan wilayah

Jika pembatasan wilayah tidak dipicu saat perangkat memasuki pembatasan wilayah (notifikasi GEOFENCE_TRANSITION_ENTER tidak dipicu), terlebih dahulu pastikan bahwa pembatasan wilayah Anda terdaftar dengan benar seperti yang dijelaskan dalam panduan ini.

Berikut adalah beberapa kemungkinan alasan notifikasi tidak berfungsi seperti yang diharapkan:

  • Lokasi akurat tidak tersedia dalam pembatasan wilayah Anda atau pembatasan wilayah Anda terlalu kecil. Di sebagian besar perangkat, layanan pembatasan wilayah hanya menggunakan lokasi jaringan untuk memicu pembatasan wilayah. Layanan menggunakan pendekatan ini karena lokasi jaringan mengonsumsi daya jauh lebih sedikit, perlu waktu lebih sedikit untuk mendapatkan lokasi diskret, dan yang paling penting, tersedia di dalam ruangan.
  • Wi-Fi dinonaktifkan pada perangkat. Mengaktifkan Wi-Fi dapat meningkatkan akurasi lokasi secara signifikan, sehingga jika Wi-Fi dimatikan, aplikasi Anda mungkin tidak akan pernah menerima notifikasi pembatasan wilayah, bergantung pada beberapa setelan termasuk radius pembatasan wilayah, model perangkat, atau versi Android. Mulai dari Android 4.3 (API level 18), kami menambahkan kemampuan "Mode hanya pemindaian Wi-Fi" yang memungkinkan pengguna untuk menonaktifkan Wi-Fi, tetapi masih mendapatkan lokasi jaringan yang baik. Praktik yang baik adalah meminta pengguna dan memberikan pintasan bagi pengguna untuk mengaktifkan mode Wi-Fi atau hanya pemindaian Wi-Fi jika keduanya dinonaktifkan. Gunakan SettingsClient untuk memastikan bahwa setelan sistem perangkat telah dikonfigurasi dengan benar untuk deteksi lokasi yang optimal.

    Catatan: Jika aplikasi Anda menargetkan Android 10 (API level 29) atau yang lebih baru, Anda tidak dapat memanggil WifiManager.setEnabled() secara langsung, kecuali jika aplikasi Anda adalah aplikasi sistem atau pengontrol kebijakan perangkat (DPC). Sebagai gantinya, gunakan panel setelan.

  • Tidak ada konektivitas jaringan yang andal dalam pembatasan wilayah Anda. Jika tidak ada koneksi data yang dapat diandalkan, notifikasi mungkin tidak dihasilkan. Hal ini dikarenakan layanan pembatasan wilayah bergantung pada penyedia lokasi jaringan, sedangkan penyedia tersebut memerlukan koneksi data.
  • Notifikasi dapat muncul terlambat. Layanan pembatasan wilayah tidak terus-menerus mencari lokasi, jadi akan ada sedikit latensi saat menerima pemberitahuan. Biasanya latensi terjadi kurang dari 2 menit, bahkan kurang jika perangkat telah bergerak. Jika Batas Lokasi Latar Belakang berlaku, latensi rata-rata berlangsung sekitar 2-3 menit. Jika perangkat tidak bergerak selama periode waktu yang cukup lama, latensi dapat meningkat (hingga 6 menit).

Referensi lainnya

Untuk mempelajari Pembatasan Wilayah lebih lanjut, lihat materi berikut:

Contoh

Aplikasi contoh untuk membuat dan memantau pembatasan wilayah.