Salah satu fitur aplikasi jaman now adalah mampu mengenali lokasi si pengguna. Dengan mengetahui lokasi pengguna, aplikasi yang kita jalankan bisa memberikan informasi yang lebih mengena, menyesuaikan konteks. Begitulah kira-kira. Untuk di Android, bagaimana cara si aplikasi mengetahui lokasi seseorang?
Di Android, salah satu cara mengetahui lokasi pengguna adalah dengan mendapatkan data Last Known Location. Dengan data ini, si aplikasi bisa mendapatkan koordinat lokasi pengguna. Untuk memanfaatkan fitur ini, kita harus memasang Google Play Services. Karena itu, dalam berkas `build.gradle`, sertakan librari Google Play Services location. Saya pakai yang versi 11.0.4.
dependencies { ... compile 'com.google.android.gms:play-services-location:11.0.4' ... }
Sebenarnya di dokumentasinya sudah ada versi terbaru, tapi entah kenapa selalu gagal ketika sinkronisasi gradle.
Setelah itu, di bagian `AndroidManifest.xml`, tambahkan permission yang berhubungan dengan lokasi. Ada dua izin yang bisa digunakan, yaitu `ACCESS_COARSE_LOCATION` dan `ACCESS_FINE_LOCATION`. Perbedaannya terletak pada tingkat akurasi. Untuk yang COARSE, tingkat akurasinya tidak terlalu tinggi dibanding yang FINE. Untuk percobaan sekarang, saya pakai yang pertama.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="id.web.hn.lokasi"> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> ... </manifest>
Sekarang mari kita mulai menuliskan kodenya. Tapi sebelumnya kita buat dulu layoutnya. Untuk layout, sederhana saja, kita siapkan satu buah button dan textview. Setiap button diklik, textview diisi dengan data koordinat lokasi pengguna.
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="id.web.hn.lokasi.MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:id="@+id/textView" android:layout_marginTop="32dp" /> <Button android:id="@+id/btn_lokasi" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginTop="32dp" android:text="Lokasi" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" android:layout_marginRight="8dp" app:layout_constraintRight_toRightOf="parent" android:layout_marginLeft="8dp" app:layout_constraintLeft_toLeftOf="parent" /> </android.support.constraint.ConstraintLayout>
Oh iya, di sini saya pakai Kotlin, bukan Java. Ya hitung-hitung belajar Kotlin :D. Untuk dapat mengakses lokasi, pada bagian `OnCreate()` di activity yang dipilih, buat objek instan `FusedLocationProviderClient`. Si objek inilah yang nantinya akan mendapatkan koordinat pengguna.
class MainActivity : AppCompatActivity() { lateinit var fusedLocationClient: FusedLocationProviderClient private val LOCATION_PERMISSION = 9001 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) ... } }
Ngomong-ngomong soal Kotlin, salah satu fitur menarik untuk Android dari bahasa asal Rusia itu adalah plugin Kotlin-android-extensions. Dengan plugin ini, kita tidak perlu lagi menuliskan `findViewById(R.id.namawidgetnya)`, tapi cukup langsung akses nama id-nya. Seperti untuk button di atas, jadinya seperti ini:
btn_lokasi.setOnClickListener { //cek perizinannya, apakah sudah diizinkan atau belum val permission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) if(permission != PackageManager.PERMISSION_GRANTED){ //belum minta izin. Silakan minta izin dulu ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), LOCATION_PERMISSION) } else { //sudah diizinkan, mari dapatkan lokasinya getLokasi() } }
Untuk mencapatkan response perizinan dari pengguna, timpa fungsi onRequestPermissionsResult:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { when(requestCode){ LOCATION_PERMISSION -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED){ //diizinkan getLokasi() } else -> Toast.makeText(this, "gagal", Toast.LENGTH_SHORT).show() //ada kesalahan entah apa } }
Sementara fungsi untuk mendapatkan koordinatnya seperti ini:
private fun getLokasi(){ fusedLocationClient.lastLocation .addOnSuccessListener { val lat = it?.latitude val lng = it?.longitude Toast.makeText(this, "lat: $lat, long: $lng", Toast.LENGTH_SHORT).show() //tuliskan ke textview: textView.text = "lat: $lat, long: $lng" } }
Kalau sudah, mari kita coba di emulator.
Loh kok null? Ada apa ini? Dari hasil baca-baca di SO, katanya koordinatnya harus diedit manual. Mari kita coba perbaiki dulu koordinat bohongannya. Kita akses emulator lewat telnet:
$ telnet localhost 5554 Trying ::1... telnet: connect to address ::1: Connection refused Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Android Console: Authentication required Android Console: type 'auth <auth_token>' to authenticate Android Console: you can find your <auth_token> in '/home/hahn/.emulator_console_auth_token' OK auth I/GX0B6T9ZkkayP5 <<<<----- ini disalin dari berkas di /home/hahn/.emulator_console_auth_token Android Console: type 'help' for a list of commands OK
Untuk membetulkan koordinat emulator, lakukan perintah `geo fix
geo fix 0 0 OK
Kembali ke emulator, mari kita coba lagi.
Lumayan lah, sekarang sudah dapat membaca koordinat, tidak null lagi. Tapi kenapa tidak sesuai dengan data yang kita masukkan ya? Padahal saat coba di ponsel betulan, datanya sesuai. Apa karena kita tidak benar-benar meminta data koordinat sebenarnya? Dari dokumentasinya, akses COARSE -sesuai artinya, kasar- ya tidak akurat-akurat amat. Masih kasar.
Mari kita coba ganti COARSE dengan FINE. Ubah `use-permission` di `AndroidManifest.xml` dan di bagian pengecekan perizinan:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Di bagian setOnClikListener:
val permission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) if(permission != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION) } else { getLokasi() }
Mari kita coba lagi.
Alhamdulillah, kali ini ternyata berhasil. Selamat!
Untuk kode lengkapnya bisa dilihat di sini :D.