Cara Bekerja dengan Geofences di Android
() translation by (you can also view the original English article)
Sumber daya yang sadar lokasi memungkinkan aplikasi Anda berinteraksi dengan dunia fisik dan mereka ideal untuk meningkatkan keterlibatan pengguna. Meski banyak aplikasi mobile menggunakannya, topik tutorial ini adalah fitur yang sering diabaikan, geofencing.
Geofence adalah perimeter virtual yang berada pada area geografis yang nyata. Menggabungkan posisi pengguna dengan perimeter geofence, adalah mungkin untuk mengetahui apakah pengguna berada di dalam atau di luar geofence atau bahkan jika dia keluar atau memasuki area tersebut.



Geofence tahu jika lokasi ada di dalam atau di luar area yang dibatasi penggunaannyaBayangkan sebuah aplikasi universitas yang bisa memberi tahu Anda kolega dan profesor mana yang saat ini berada di kampus. Atau aplikasi untuk mal yang memberi penghargaan kepada pelanggan reguler. Ada banyak kemungkinan menarik lainnya yang bisa Anda jelajahi.
Dalam tutorial ini, Anda belajar bagaimana menggunakan geofences di Android dengan membuat aplikasi yang menunjukkan pemberitahuan kepada pengguna saat mereka masuk atau keluar dari geofence. Ini membantu jika Anda memiliki pengetahuan sebelumnya tentang Google Play Services, API Android Google Maps, atau IntentService
. Jika tidak, maka Anda masih bisa mengikuti, tapi Anda mungkin ingin melakukan penelitian tentang topik-topik ini setelah membaca tutorial ini.
1. Geofences di Android
Di Android, ada beberapa cara untuk bekerja dengan geofences. Anda bahkan bisa membuat implementasi sendiri untuk bekerja dengan geofences, namun lebih mudah menggunakan GeofencingApi
Google.
API ini adalah bagian dari API Location Google. Ini termasuk Geofence
, GeofencingRequest
, GeofenceApi
, GeofencingEvent
, dan GeofenceStatusCodes
. Dalam tutorial ini, kita menggunakan kelas-kelas ini untuk membuat dan bekerja dengan geofences.
Antarmuka Geofence
Geofence
adalah antarmuka yang mewakili area geografis yang harus dipantau. Ini dibuat dengan menggunakan Geofence.Builder
. Selama pembuatannya, Anda menetapkan wilayah yang dipantau, tanggal kedaluwarsa geofence, sifat responsif, pengenal, dan jenis transisi yang seharusnya dicari.
Untuk menjaga konsumsi daya seminimal mungkin, disarankan untuk menggunakan geofence dengan radius minimal 100 meter untuk kebanyakan situasi. Jika geofences berada di pedesaan, Anda harus meningkatkan radius menjadi 500 meter atau lebih tinggi untuk memastikan geofences efektif.
1 |
Geofence geofence = new Geofence.Builder() |
2 |
.setRequestId(GEOFENCE_REQ_ID) // Geofence ID |
3 |
.setCircularRegion( LATITUDE, LONGITUDE, RADIUS) // defining fence region |
4 |
.setExpirationDuration( DURANTION ) // expiring date |
5 |
// Transition types that it should look for
|
6 |
.setTransitionTypes( Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT ) |
7 |
.build(); |
Transisi Geofence
-
GEOFENCE_TRANSITION_DWELL
menunjukkan bahwa pengguna memasuki area tersebut dan menghabiskan beberapa waktu di sana. Hal ini berguna untuk menghindari banyak peringatan saat pengguna masuk dan keluar dari area terlalu cepat. Anda dapat mengkonfigurasi waktu tinggal dengan menggunakan parametersetLoiteringDelay
. -
GEOFENCE_TRANSITION_ENTER
menunjukkan kapan pengguna memasuki wilayah yang dipantau. -
GEOFENCE_TRANSITION_EXIT
menunjukkan kapan pengguna keluar dari wilayah ini.
GeofenceRequest
Kelas GeofencingRequest
menerima geofences yang harus dipantau. Anda dapat membuat sebuah instance dengan menggunakan Builder
, mengirimkan Geofence
atau List<Geofence>
, dan jenis notifikasi untuk dipicu saat geofence dibuat.
1 |
GeofencingRequest request = new GeofencingRequest.Builder() |
2 |
// Notification to trigger when the Geofence is created
|
3 |
.setInitialTrigger( GeofencingRequest.INITIAL_TRIGGER_ENTER ) |
4 |
.addGeofence( geofence ) // add a Geofence |
5 |
.build(); |
GeofencingApi
Kelas GeofencingApi
adalah titik masuk untuk semua interaksi dengan API geofencing Google. Ini adalah bagian dari API Location dan bergantung pada GoogleApiClient
untuk bekerja. Anda akan menggunakan GeofencingApi
untuk menambahkan dan menghapus geofence.
Untuk menambahkan geofence, Anda memanggil metode addGeofence()
. Ini memonitor area yang diberikan dengan menggunakan pengaturan yang dikirimkan ke GeofencingRequest
dan menembakkan PendingIntent
saat terjadi transisi geofence, masuk atau keluar dari area.
1 |
PendingResult<Status> addGeofences (GoogleApiClient client, |
2 |
GeofencingRequest geofencingRequest, |
3 |
PendingIntent pendingIntent) |
Untuk menghapus geofence, Anda memanggil removeGeofences()
. Anda bisa menghapus geofence menggunakan permintaan pengenal atau pending intent-nya.
1 |
PendingResult<Status> removeGeofences(GoogleApiClient client, |
2 |
List<String> geofenceRequestIds) |
1 |
PendingResult<Status> removeGeofences (GoogleApiClient client, |
2 |
PendingIntent pendingIntent) |
2. Membuat Aplikasi Geofencing
Dalam tutorial ini, kita membuat aplikasi sederhana yang memantau lokasi pengguna dan memposting notifikasi saat pengguna memasuki atau keluar dari area geofence. Aplikasi hanya terdiri dari satu Activity
dan IntentService
. Kita juga melihat sekilas GoogleMap
, GoogleApiClient
, dan FusedLocationProviderApi
, dan kita menjelajahi beberapa peringatan API geofence.



Langkah 1: Setup Proyek
GeofencingApi
adalah bagian dari Layanan Google Play. Untuk mengaksesnya, Anda harus menyiapkan lingkungan pengembangan dengan benar dan membuat instance dari GoogleApiClient
. Buat proyek baru dengan Activity
kosong, edit file build.gradle proyek seperti yang ditunjukkan di bawah ini, dan sinkronkan proyek Anda.
Langkah 2: Izin
Kita perlu mengatur hak akses yang benar untuk membuat dan menggunakan geofences. Tambahkan izin berikut ke manifest proyek:
1 |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> |
Dimulai dengan Android 6.0, aplikasi meminta izin pada waktu berjalan dan tidak selama penginstalan. Kita membahasnya nanti di tutorial.
Langkah 3: Membuat Layout
Proyek ini terdiri dari satu layout, layout MainActivity
. Ini berisi garis lintang dan bujur perangkat saat ini, dan fragmen GoogleMap
yang menampilkan geofences dan posisi pengguna.
Karena activity_main.xml cukup mudah, saya ingin berkonsentrasi hanya pada elemen MapFragment
. Anda bisa melihat layout yang telah selesai di file sumber tutorial ini.
1 |
<!--GoogleMap fragment-->
|
2 |
<fragment xmlns:android="http://schemas.android.com/apk/res/android" |
3 |
android:name="com.google.android.gms.maps.MapFragment" |
4 |
android:id="@+id/map" |
5 |
android:layout_width="match_parent" |
6 |
android:layout_height="match_parent"/> |
Langkah 4: Kunci API Google Maps
Karena kita menggunakan MapFragment
, kita perlu menyiapkan dan menginisialisasi instance GoogleMap
. Pertama, Anda perlu mendapatkan kunci API. Begitu Anda memiliki kunci API, tambahkan ke manifest proyek.
1 |
<meta-data
|
2 |
android:name="com.google.android.geo.API_KEY" |
3 |
android:value="YOUR_API_KEY"/> |
Mari kita mulai dengan instance GoogleMap
. Terapkan GoogleMap.OnMapReadyCallback
, GoogleMap.OnMapClickListener
, dan GoogleMap.OnMarkerClickListener
di kelas Activity
dan inisialisasi peta.
1 |
public class MainActivity extends AppCompatActivity |
2 |
implements
|
3 |
OnMapReadyCallback, |
4 |
GoogleMap.OnMapClickListener, |
5 |
GoogleMap.OnMarkerClickListener |
6 |
{
|
7 |
|
8 |
private static final String TAG = MainActivity.class.getSimpleName(); |
9 |
|
10 |
private TextView textLat, textLong; |
11 |
private MapFragment mapFragment; |
12 |
private GoogleMap map; |
13 |
|
14 |
@Override
|
15 |
protected void onCreate(Bundle savedInstanceState) { |
16 |
super.onCreate(savedInstanceState); |
17 |
setContentView(R.layout.activity_main); |
18 |
textLat = (TextView) findViewById(R.id.lat); |
19 |
textLong = (TextView) findViewById(R.id.lon); |
20 |
|
21 |
// initialize GoogleMaps
|
22 |
initGMaps(); |
23 |
}
|
24 |
|
25 |
// Initialize GoogleMaps
|
26 |
private void initGMaps(){ |
27 |
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map); |
28 |
mapFragment.getMapAsync(this); |
29 |
}
|
30 |
|
31 |
// Callback called when Map is ready
|
32 |
@Override
|
33 |
public void onMapReady(GoogleMap googleMap) { |
34 |
Log.d(TAG, "onMapReady()"); |
35 |
map = googleMap; |
36 |
map.setOnMapClickListener(this); |
37 |
map.setOnMarkerClickListener(this); |
38 |
}
|
39 |
|
40 |
// Callback called when Map is touched
|
41 |
@Override
|
42 |
public void onMapClick(LatLng latLng) { |
43 |
Log.d(TAG, "onMapClick("+latLng +")"); |
44 |
}
|
45 |
|
46 |
// Callback called when Marker is touched
|
47 |
@Override
|
48 |
public boolean onMarkerClick(Marker marker) { |
49 |
Log.d(TAG, "onMarkerClickListener: " + marker.getPosition() ); |
50 |
return false; |
51 |
}
|
52 |
}
|
Langkah 5: GoogleApiClient
Untuk menggunakan antarmuka GeofencingApi
, kita memerlukan titik masuk GoogleApiClient
. Mari menerapkan GoogleApiClient.ConnectionCallbacks
dan GoogleApiClient.OnConnectionFailedListener
dalam Activity
seperti yang ditunjukkan di bawah ini.
1 |
public class MainActivity extends AppCompatActivity |
2 |
implements
|
3 |
GoogleApiClient.ConnectionCallbacks, |
4 |
GoogleApiClient.OnConnectionFailedListener, |
5 |
OnMapReadyCallback, |
6 |
GoogleMap.OnMapClickListener, |
7 |
GoogleMap.OnMarkerClickListener { |
8 |
|
9 |
// ...
|
10 |
private GoogleApiClient googleApiClient; |
11 |
|
12 |
@Override
|
13 |
protected void onCreate(Bundle savedInstanceState) { |
14 |
|
15 |
// ...
|
16 |
|
17 |
// create GoogleApiClient
|
18 |
createGoogleApi(); |
19 |
}
|
20 |
|
21 |
// Create GoogleApiClient instance
|
22 |
private void createGoogleApi() { |
23 |
Log.d(TAG, "createGoogleApi()"); |
24 |
if ( googleApiClient == null ) { |
25 |
googleApiClient = new GoogleApiClient.Builder( this ) |
26 |
.addConnectionCallbacks( this ) |
27 |
.addOnConnectionFailedListener( this ) |
28 |
.addApi( LocationServices.API ) |
29 |
.build(); |
30 |
}
|
31 |
}
|
32 |
|
33 |
@Override
|
34 |
protected void onStart() { |
35 |
super.onStart(); |
36 |
|
37 |
// Call GoogleApiClient connection when starting the Activity
|
38 |
googleApiClient.connect(); |
39 |
}
|
40 |
|
41 |
@Override
|
42 |
protected void onStop() { |
43 |
super.onStop(); |
44 |
|
45 |
// Disconnect GoogleApiClient when stopping Activity
|
46 |
googleApiClient.disconnect(); |
47 |
}
|
48 |
|
49 |
// GoogleApiClient.ConnectionCallbacks connected
|
50 |
@Override
|
51 |
public void onConnected(@Nullable Bundle bundle) { |
52 |
Log.i(TAG, "onConnected()"); |
53 |
}
|
54 |
|
55 |
// GoogleApiClient.ConnectionCallbacks suspended
|
56 |
@Override
|
57 |
public void onConnectionSuspended(int i) { |
58 |
Log.w(TAG, "onConnectionSuspended()"); |
59 |
}
|
60 |
|
61 |
// GoogleApiClient.OnConnectionFailedListener fail
|
62 |
@Override
|
63 |
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { |
64 |
Log.w(TAG, "onConnectionFailed()"); |
65 |
}
|
66 |
}
|
Langkah 6: FusedLocationProviderApi
Kita juga perlu mengakses lokasi pengguna saat ini. Antarmuka FusedLocationProviderApi
memberi kita informasi ini dan memungkinkan tingkat kontrol permintaan lokasi yang hebat. Ini sangat penting, mengingat permintaan lokasi memiliki efek langsung terhadap konsumsi baterai perangkat.
Sekarang, mari kita menerapkan LocationListener
. Periksa apakah pengguna memberi aplikasi izin yang sesuai dengan membuat permintaan Location
dan menampilkan lokasi mereka saat ini di layar.
1 |
public class MainActivity extends AppCompatActivity |
2 |
implements
|
3 |
// ....
|
4 |
LocationListener
|
5 |
{
|
6 |
|
7 |
private Location lastLocation; |
8 |
//...
|
9 |
|
10 |
// GoogleApiClient.ConnectionCallbacks connected
|
11 |
@Override
|
12 |
public void onConnected(@Nullable Bundle bundle) { |
13 |
Log.i(TAG, "onConnected()"); |
14 |
getLastKnownLocation(); |
15 |
}
|
16 |
|
17 |
// Get last known location
|
18 |
private void getLastKnownLocation() { |
19 |
Log.d(TAG, "getLastKnownLocation()"); |
20 |
if ( checkPermission() ) { |
21 |
lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient); |
22 |
if ( lastLocation != null ) { |
23 |
Log.i(TAG, "LasKnown location. " + |
24 |
"Long: " + lastLocation.getLongitude() + |
25 |
" | Lat: " + lastLocation.getLatitude()); |
26 |
writeLastLocation(); |
27 |
startLocationUpdates(); |
28 |
} else { |
29 |
Log.w(TAG, "No location retrieved yet"); |
30 |
startLocationUpdates(); |
31 |
}
|
32 |
}
|
33 |
else askPermission(); |
34 |
}
|
35 |
|
36 |
private LocationRequest locationRequest; |
37 |
// Defined in mili seconds.
|
38 |
// This number in extremely low, and should be used only for debug
|
39 |
private final int UPDATE_INTERVAL = 1000; |
40 |
private final int FASTEST_INTERVAL = 900; |
41 |
|
42 |
// Start location Updates
|
43 |
private void startLocationUpdates(){ |
44 |
Log.i(TAG, "startLocationUpdates()"); |
45 |
locationRequest = LocationRequest.create() |
46 |
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) |
47 |
.setInterval(UPDATE_INTERVAL) |
48 |
.setFastestInterval(FASTEST_INTERVAL); |
49 |
|
50 |
if ( checkPermission() ) |
51 |
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this); |
52 |
}
|
53 |
|
54 |
@Override
|
55 |
public void onLocationChanged(Location location) { |
56 |
Log.d(TAG, "onLocationChanged ["+location+"]"); |
57 |
lastLocation = location; |
58 |
writeActualLocation(location); |
59 |
}
|
60 |
|
61 |
// Write location coordinates on UI
|
62 |
private void writeActualLocation(Location location) { |
63 |
textLat.setText( "Lat: " + location.getLatitude() ); |
64 |
textLong.setText( "Long: " + location.getLongitude() ); |
65 |
}
|
66 |
|
67 |
private void writeLastLocation() { |
68 |
writeActualLocation(lastLocation); |
69 |
}
|
70 |
|
71 |
// Check for permission to access Location
|
72 |
private boolean checkPermission() { |
73 |
Log.d(TAG, "checkPermission()"); |
74 |
// Ask for permission if it wasn't granted yet
|
75 |
return (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) |
76 |
== PackageManager.PERMISSION_GRANTED ); |
77 |
}
|
78 |
|
79 |
// Asks for permission
|
80 |
private void askPermission() { |
81 |
Log.d(TAG, "askPermission()"); |
82 |
ActivityCompat.requestPermissions( |
83 |
this, |
84 |
new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, |
85 |
REQ_PERMISSION
|
86 |
);
|
87 |
}
|
88 |
|
89 |
// Verify user's response of the permission requested
|
90 |
@Override
|
91 |
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { |
92 |
Log.d(TAG, "onRequestPermissionsResult()"); |
93 |
super.onRequestPermissionsResult(requestCode, permissions, grantResults); |
94 |
switch ( requestCode ) { |
95 |
case REQ_PERMISSION: { |
96 |
if ( grantResults.length > 0 |
97 |
&& grantResults[0] == PackageManager.PERMISSION_GRANTED ){ |
98 |
// Permission granted
|
99 |
getLastKnownLocation(); |
100 |
|
101 |
} else { |
102 |
// Permission denied
|
103 |
permissionsDenied(); |
104 |
}
|
105 |
break; |
106 |
}
|
107 |
}
|
108 |
}
|
109 |
|
110 |
// App cannot work without the permissions
|
111 |
private void permissionsDenied() { |
112 |
Log.w(TAG, "permissionsDenied()"); |
113 |
}
|
114 |
}
|
Penting untuk memperhatikan bahwa LocationRequest
yang dibuat di atas tidak dioptimalkan untuk lingkungan produksi. UPDATE_INTERVAL
terlalu pendek dan akan mengkonsumsi terlalu banyak daya baterai. Konfigurasi yang lebih realistis untuk produksi bisa menjadi:
1 |
private final int UPDATE_INTERVAL = 3 * 60 * 1000; // 3 minutes |
2 |
private final int FASTEST_INTERVAL = 30 * 1000; // 30 secs |
3 |
private void startLocationUpdates(){ |
4 |
Log.i(TAG, "startLocationUpdates()"); |
5 |
locationRequest = LocationRequest.create() |
6 |
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) |
7 |
.setInterval(UPDATE_INTERVAL) |
8 |
.setFastestInterval(FASTEST_INTERVAL); |
9 |
|
10 |
if ( checkPermission() ) |
11 |
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this); |
12 |
}
|
Langkah 7: Penanda GoogleMap
Activity
kita membutuhkan dua penanda yang berbeda. locationMarker
menggunakan garis lintang dan bujur yang diberikan oleh FusedLocationProviderApi
untuk menginformasikan lokasi perangkat saat ini. geoFenceMarker
adalah target pembuatan geofence karena menggunakan sentuhan terakhir yang diberikan pada peta untuk mengambil posisinya.
1 |
@Override
|
2 |
public void onMapClick(LatLng latLng) { |
3 |
Log.d(TAG, "onMapClick("+latLng +")"); |
4 |
markerForGeofence(latLng); |
5 |
}
|
6 |
|
7 |
private void writeActualLocation(Location location) { |
8 |
// ...
|
9 |
markerLocation(new LatLng(location.getLatitude(), location.getLongitude())); |
10 |
}
|
11 |
|
12 |
private Marker locationMarker; |
13 |
// Create a Location Marker
|
14 |
private void markerLocation(LatLng latLng) { |
15 |
Log.i(TAG, "markerLocation("+latLng+")"); |
16 |
String title = latLng.latitude + ", " + latLng.longitude; |
17 |
MarkerOptions markerOptions = new MarkerOptions() |
18 |
.position(latLng) |
19 |
.title(title); |
20 |
if ( map!=null ) { |
21 |
// Remove the anterior marker
|
22 |
if ( locationMarker != null ) |
23 |
locationMarker.remove(); |
24 |
locationMarker = map.addMarker(markerOptions); |
25 |
float zoom = 14f; |
26 |
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, zoom); |
27 |
map.animateCamera(cameraUpdate); |
28 |
}
|
29 |
}
|
30 |
|
31 |
private Marker geoFenceMarker; |
32 |
// Create a marker for the geofence creation
|
33 |
private void markerForGeofence(LatLng latLng) { |
34 |
Log.i(TAG, "markerForGeofence("+latLng+")"); |
35 |
String title = latLng.latitude + ", " + latLng.longitude; |
36 |
// Define marker options
|
37 |
MarkerOptions markerOptions = new MarkerOptions() |
38 |
.position(latLng) |
39 |
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)) |
40 |
.title(title); |
41 |
if ( map!=null ) { |
42 |
// Remove last geoFenceMarker
|
43 |
if (geoFenceMarker != null) |
44 |
geoFenceMarker.remove(); |
45 |
|
46 |
geoFenceMarker = map.addMarker(markerOptions); |
47 |
}
|
48 |
}
|
Langkah 8: Membuat Geofence
Akhirnya, sekarang saatnya menciptakan geofence. Kita menggunakan geoFenceMarker
sebagai titik pusat geofence.
1 |
private static final long GEO_DURATION = 60 * 60 * 1000; |
2 |
private static final String GEOFENCE_REQ_ID = "My Geofence"; |
3 |
private static final float GEOFENCE_RADIUS = 500.0f; // in meters |
4 |
|
5 |
// Create a Geofence
|
6 |
private Geofence createGeofence( LatLng latLng, float radius ) { |
7 |
Log.d(TAG, "createGeofence"); |
8 |
return new Geofence.Builder() |
9 |
.setRequestId(GEOFENCE_REQ_ID) |
10 |
.setCircularRegion( latLng.latitude, latLng.longitude, radius) |
11 |
.setExpirationDuration( GEO_DURATION ) |
12 |
.setTransitionTypes( Geofence.GEOFENCE_TRANSITION_ENTER |
13 |
| Geofence.GEOFENCE_TRANSITION_EXIT ) |
14 |
.build(); |
15 |
}
|
Selanjutnya, kita membuat objek GeofencingRequest
.
1 |
// Create a Geofence Request
|
2 |
private GeofencingRequest createGeofenceRequest( Geofence geofence ) { |
3 |
Log.d(TAG, "createGeofenceRequest"); |
4 |
return new GeofencingRequest.Builder() |
5 |
.setInitialTrigger( GeofencingRequest.INITIAL_TRIGGER_ENTER ) |
6 |
.addGeofence( geofence ) |
7 |
.build(); |
8 |
}
|
Kita menggunakan objek PendingIntent
untuk memanggil IntentService
yang akan menangani GeofenceEvent
. Kita membuat GeofenceTrasitionService.class
nanti.
1 |
private PendingIntent geoFencePendingIntent; |
2 |
private final int GEOFENCE_REQ_CODE = 0; |
3 |
private PendingIntent createGeofencePendingIntent() { |
4 |
Log.d(TAG, "createGeofencePendingIntent"); |
5 |
if ( geoFencePendingIntent != null ) |
6 |
return geoFencePendingIntent; |
7 |
|
8 |
Intent intent = new Intent( this, GeofenceTrasitionService.class); |
9 |
return PendingIntent.getService( |
10 |
this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT ); |
11 |
}
|
12 |
|
13 |
// Add the created GeofenceRequest to the device's monitoring list
|
14 |
private void addGeofence(GeofencingRequest request) { |
15 |
Log.d(TAG, "addGeofence"); |
16 |
if (checkPermission()) |
17 |
LocationServices.GeofencingApi.addGeofences( |
18 |
googleApiClient, |
19 |
request, |
20 |
createGeofencePendingIntent() |
21 |
).setResultCallback(this); |
22 |
}
|
Kita juga menggambar geofence di peta sebagai referensi visual.
1 |
@Override
|
2 |
public void onResult(@NonNull Status status) { |
3 |
Log.i(TAG, "onResult: " + status); |
4 |
if ( status.isSuccess() ) { |
5 |
drawGeofence(); |
6 |
} else { |
7 |
// inform about fail
|
8 |
}
|
9 |
}
|
10 |
|
11 |
// Draw Geofence circle on GoogleMap
|
12 |
private Circle geoFenceLimits; |
13 |
private void drawGeofence() { |
14 |
Log.d(TAG, "drawGeofence()"); |
15 |
|
16 |
if ( geoFenceLimits != null ) |
17 |
geoFenceLimits.remove(); |
18 |
|
19 |
CircleOptions circleOptions = new CircleOptions() |
20 |
.center( geoFenceMarker.getPosition()) |
21 |
.strokeColor(Color.argb(50, 70,70,70)) |
22 |
.fillColor( Color.argb(100, 150,150,150) ) |
23 |
.radius( GEOFENCE_RADIUS ); |
24 |
geoFenceLimits = map.addCircle( circleOptions ); |
25 |
}
|
Metode startGeofence()
bertanggung jawab untuk memulai proses geofencing di kelas MainActivity
.
1 |
@Override
|
2 |
public boolean onOptionsItemSelected(MenuItem item) { |
3 |
switch ( item.getItemId() ) { |
4 |
case R.id.geofence: { |
5 |
startGeofence(); |
6 |
return true; |
7 |
}
|
8 |
}
|
9 |
return super.onOptionsItemSelected(item); |
10 |
}
|
11 |
|
12 |
// Start Geofence creation process
|
13 |
private void startGeofence() { |
14 |
Log.i(TAG, "startGeofence()"); |
15 |
if( geoFenceMarker != null ) { |
16 |
Geofence geofence = createGeofence( geoFenceMarker.getPosition(), GEOFENCE_RADIUS ); |
17 |
GeofencingRequest geofenceRequest = createGeofenceRequest( geofence ); |
18 |
addGeofence( geofenceRequest ); |
19 |
} else { |
20 |
Log.e(TAG, "Geofence marker is null"); |
21 |
}
|
22 |
}
|
Langkah 9: Layanan Transisi Geofence
Sekarang kita dapat akhirnya membuat GeofenceTrasitionService.class
yang disebutkan sebelumnya. Kelas ini memperluas IntentService
dan bertanggung jawab untuk menangani GeofencingEvent
. Pertama, kita mendapatkan event ini dari intent yang diterima.
1 |
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); |
Kita kemudian memeriksa apakah jenis transisi geofencing yang terjadi sangat menarik bagi kita. Jika iya, kita mengambil daftar geofensi yang dipicu dan membuat pemberitahuan dengan tindakan yang sesuai.
1 |
// Retrieve GeofenceTrasition
|
2 |
int geoFenceTransition = geofencingEvent.getGeofenceTransition(); |
3 |
// Check if the transition type
|
4 |
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || |
5 |
geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT ) { |
6 |
// Get the geofence that were triggered
|
7 |
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences(); |
8 |
// Create a detail message with Geofences received
|
9 |
String geofenceTransitionDetails = getGeofenceTrasitionDetails(geoFenceTransition, triggeringGeofences ); |
10 |
// Send notification details as a String
|
11 |
sendNotification( geofenceTransitionDetails ); |
12 |
}
|
Saya juga telah menerapkan beberapa metode helper untuk membuat penerapan kelas lebih mudah dipahami.
1 |
public class GeofenceTrasitionService extends IntentService { |
2 |
|
3 |
private static final String TAG = GeofenceTrasitionService.class.getSimpleName(); |
4 |
public static final int GEOFENCE_NOTIFICATION_ID = 0; |
5 |
|
6 |
public GeofenceTrasitionService() { |
7 |
super(TAG); |
8 |
}
|
9 |
|
10 |
@Override
|
11 |
protected void onHandleIntent(Intent intent) { |
12 |
// Retrieve the Geofencing intent
|
13 |
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); |
14 |
|
15 |
// Handling errors
|
16 |
if ( geofencingEvent.hasError() ) { |
17 |
String errorMsg = getErrorString(geofencingEvent.getErrorCode() ); |
18 |
Log.e( TAG, errorMsg ); |
19 |
return; |
20 |
}
|
21 |
|
22 |
// Retrieve GeofenceTrasition
|
23 |
int geoFenceTransition = geofencingEvent.getGeofenceTransition(); |
24 |
// Check if the transition type
|
25 |
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || |
26 |
geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT ) { |
27 |
// Get the geofence that were triggered
|
28 |
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences(); |
29 |
// Create a detail message with Geofences received
|
30 |
String geofenceTransitionDetails = getGeofenceTrasitionDetails(geoFenceTransition, triggeringGeofences ); |
31 |
// Send notification details as a String
|
32 |
sendNotification( geofenceTransitionDetails ); |
33 |
}
|
34 |
}
|
35 |
|
36 |
// Create a detail message with Geofences received
|
37 |
private String getGeofenceTrasitionDetails(int geoFenceTransition, List<Geofence> triggeringGeofences) { |
38 |
// get the ID of each geofence triggered
|
39 |
ArrayList<String> triggeringGeofencesList = new ArrayList<>(); |
40 |
for ( Geofence geofence : triggeringGeofences ) { |
41 |
triggeringGeofencesList.add( geofence.getRequestId() ); |
42 |
}
|
43 |
|
44 |
String status = null; |
45 |
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ) |
46 |
status = "Entering "; |
47 |
else if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT ) |
48 |
status = "Exiting "; |
49 |
return status + TextUtils.join( ", ", triggeringGeofencesList); |
50 |
}
|
51 |
|
52 |
// Send a notification
|
53 |
private void sendNotification( String msg ) { |
54 |
Log.i(TAG, "sendNotification: " + msg ); |
55 |
|
56 |
// Intent to start the main Activity
|
57 |
Intent notificationIntent = MainActivity.makeNotificationIntent( |
58 |
getApplicationContext(), msg |
59 |
);
|
60 |
|
61 |
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); |
62 |
stackBuilder.addParentStack(MainActivity.class); |
63 |
stackBuilder.addNextIntent(notificationIntent); |
64 |
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); |
65 |
|
66 |
// Creating and sending Notification
|
67 |
NotificationManager notificatioMng = |
68 |
(NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE ); |
69 |
notificatioMng.notify( |
70 |
GEOFENCE_NOTIFICATION_ID, |
71 |
createNotification(msg, notificationPendingIntent)); |
72 |
}
|
73 |
|
74 |
// Create a notification
|
75 |
private Notification createNotification(String msg, PendingIntent notificationPendingIntent) { |
76 |
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this); |
77 |
notificationBuilder
|
78 |
.setSmallIcon(R.drawable.ic_action_location) |
79 |
.setColor(Color.RED) |
80 |
.setContentTitle(msg) |
81 |
.setContentText("Geofence Notification!") |
82 |
.setContentIntent(notificationPendingIntent) |
83 |
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND) |
84 |
.setAutoCancel(true); |
85 |
return notificationBuilder.build(); |
86 |
}
|
87 |
|
88 |
// Handle errors
|
89 |
private static String getErrorString(int errorCode) { |
90 |
switch (errorCode) { |
91 |
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE: |
92 |
return "GeoFence not available"; |
93 |
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES: |
94 |
return "Too many GeoFences"; |
95 |
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS: |
96 |
return "Too many pending intents"; |
97 |
default: |
98 |
return "Unknown error."; |
99 |
}
|
100 |
}
|
101 |
}
|
3. Pengujian
Pengujian pada Perangkat Virtual
Jauh lebih mudah untuk menguji geofencing pada perangkat virtual. Ada beberapa cara untuk melakukan ini. Di Android Studio, buka perangkat virtual dan klik tombol more options di kanan bawah.
Di tab Location di sebelah kiri, masukkan koordinat lokasi.



Saya lebih suka menggunakan perintah telnet untuk mengendalikan perangkat virtual. Untuk menggunakan ini, Anda perlu menyambungkan ke perangkat dari baris perintah menggunakan perintah berikut:
1 |
telnet localhost [DEVICE_PORT]
|
Port perangkat ditampilkan di jendela perangkat virtual. Port perangkat biasanya sama dengan 5554.
Ada kemungkinan Anda perlu mengotorisasi koneksi ini menggunakan auth_token
Anda, namun baris perintah menunjukkan lokasi Anda berada. Arahkan ke lokasi itu dan salin token dan ketik, auth [YOUR_AUTH_TOKEN]
.
Anda sekarang dapat mengatur lokasi perangkat dengan menjalankan perintah berikut:
1 |
geo fix [LATITUDE] [LONGITUDE] |
Kesimpulan
Geofencing mungkin merupakan tambahan yang bagus untuk aplikasi Anda karena dapat meningkatkan keterlibatan pengguna dengan lebih baik. Ada banyak kemungkinan untuk dijelajahi dan Anda bahkan bisa menciptakan pengalaman yang canggih dengan menggunakan beacon dalam ruangan, seperti Estimote. Dengan beacon dalam ruangan, Anda tahu persis di mana pengguna telah masuk, misalnya, sebuah pusat perbelanjaan.
Menambahkan Geofencing ke sebuah proyek adalah sederhana, namun kita perlu selalu mengingat konsumsi daya setiap saat. Ini berarti kita perlu berhati-hati memilih ukuran geofence dan tingkat pembaruan karena keduanya langsung mempengaruhi konsumsi daya aplikasi Anda.
Oleh karena itu pengujian sangat penting untuk mendapatkan ide realistis tentang konsumsi daya aplikasi Anda. Juga pertimbangkan untuk memberi pengguna pilihan untuk menonaktifkan geofencing sama sekali jika mereka tidak menginginkan atau membutuhkan fitur ini.