Mendapatkan data lokasi pengguna di Android

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.

minta izin dulu

null

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 `, misalnya seperti ini:

geo fix 0 0
OK

Kembali ke emulator, mari kita coba lagi.

masih ngaco

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.

Datanya sesuai

Alhamdulillah, kali ini ternyata berhasil. Selamat!
Untuk kode lengkapnya bisa dilihat di sini :D.

Ada komentar?

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: