Tentang codelab ini
1. Sebelum memulai
Abstrak
Codelab ini mengajari Anda cara menggunakan data dari Google Maps Platform untuk menampilkan tempat-tempat terdekat dalam augmented reality (AR).
Prasyarat
- Pemahaman dasar tentang pengembangan Android menggunakan Android Studio
- Pemahaman tentang Kotlin
Yang akan Anda pelajari
- Meminta izin dari pengguna untuk mengakses kamera dan lokasi perangkat.
- Mengintegrasikan dengan Places API untuk mengambil data tempat-tempat terdekat di sekitar lokasi perangkat.
- Mengintegrasikan dengan ARCore untuk menemukan permukaan bidang horizontal sehingga objek virtual dapat didasarkan dan ditempatkan dalam ruang 3D menggunakan Sceneform.
- Mengumpulkan informasi tentang posisi perangkat di ruang menggunakan SensorManager dan menggunakan Library Utilitas Maps SDK for Android untuk menempatkan objek virtual pada arah tujuan yang benar.
Yang akan Anda perlukan
- Android Studio 2020.3.1 atau versi yang lebih baru
- Mesin pengembangan yang mendukung OpenGL ES 3.0 atau versi yang lebih baru
- Perangkat yang mendukung ARCore atau Android Emulator yang kompatibel dengan ARCore (petunjuk tersedia di langkah berikutnya)
2. Memulai persiapan
Android Studio
Codelab ini menggunakan Android 10.0 (API level 29) dan mengharuskan Anda menginstal layanan Google Play di Android Studio. Untuk menginstal kedua dependensi ini, selesaikan langkah-langkah berikut:
- Buka SDK Manager, yang dapat Anda akses dengan mengklik Tools > SDK Manager.
- Periksa apakah Android 10.0 telah diinstal. Jika belum, instal dengan memilih kotak centang di samping Android 10.0 (Q), lalu klik OK, dan klik OK lagi pada dialog yang muncul.
- Terakhir, instal layanan Google Play dengan membuka tab SDK Tools, centang kotak di samping Google Play services, klik OK, lalu pilih OK lagi di dialog yang muncul**.**
API yang diperlukan
Pada Langkah 3 dari bagian berikut, aktifkan Maps SDK for Android dan Places API untuk codelab ini.
Memulai Google Maps Platform
Jika Anda belum pernah menggunakan Google Maps Platform, ikuti panduan Memulai Google Maps Platform atau tonton playlist Memulai Google Maps Platform untuk menyelesaikan langkah-langkah berikut:
- Membuat akun penagihan.
- Membuat project.
- Mengaktifkan API dan SDK Google Maps Platform (tercantum di bagian sebelumnya).
- Membuat kunci API.
Opsional: Android Emulator
Jika tidak memiliki perangkat yang mendukung ARCore, Anda dapat menggunakan Android Emulator untuk menyimulasikan tampilan AR serta memalsukan lokasi perangkat. Karena Anda juga akan menggunakan Sceneform dalam latihan ini, Anda juga harus memastikan untuk mengikuti langkah-langkah di bagian "Konfigurasikan emulator untuk mendukung Sceneform".
3. Mulai cepat
Untuk membantu Anda memulai secepatnya, berikut beberapa kode awal untuk membantu Anda mengikuti codelab ini. Anda dapat langsung ke bagian solusi, tetapi jika Anda ingin melihat semua langkah, baca semuanya.
Anda dapat menggandakan repositori jika sudah menginstal git
.
git clone https://github.com/googlecodelabs/display-nearby-places-ar-android.git
Atau, Anda dapat mengklik tombol di bawah untuk mendownload kode sumber.
Setelah mendapatkan kode, lanjutkan dan buka project yang ada dalam direktori starter
.
4. Ringkasan project
Pelajari kode yang Anda download dari langkah sebelumnya. Di dalam repositori ini, Anda akan menemukan satu modul bernama app
, yang berisi paket com.google.codelabs.findnearbyplacesar
.
AndroidManifest.xml
Atribut berikut dideklarasikan dalam file AndroidManifest.xml
untuk memungkinkan Anda menggunakan fitur yang diperlukan pada codelab ini:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Sceneform requires OpenGL ES 3.0 or later. -->
<uses-feature
android:glEsVersion="0x00030000"
android:required="true" />
<!-- Indicates that app requires ARCore ("AR Required"). Ensures the app is visible only in the Google Play Store on devices that support ARCore. For "AR Optional" apps remove this line. -->
<uses-feature android:name="android.hardware.camera.ar" />
Untuk uses-permission
, yang menentukan izin mana yang harus diberikan oleh pengguna sebelum kemampuan tersebut dapat digunakan, hal-hal berikut dideklarasikan:
android.permission.INTERNET
—kode ini dideklarasikan agar aplikasi Anda dapat melakukan operasi jaringan dan mengambil data melalui internet, seperti informasi tempat via Places API.android.permission.CAMERA
—akses kamera diperlukan agar Anda dapat menggunakan kamera perangkat untuk menampilkan objek dalam augmented reality.android.permission.ACCESS_FINE_LOCATION
—akses lokasi diperlukan agar Anda dapat mengambil data tempat-tempat terdekat berdasarkan lokasi perangkat.
Untuk uses-feature
, yang menentukan fitur hardware mana yang diperlukan oleh aplikasi ini, hal-hal berikut dideklarasikan:
- OpenGL ES versi 3.0 diperlukan.
- Perangkat yang mendukung ARCore diperlukan.
Selain itu, tag metadata berikut ditambahkan di bagian objek aplikasi:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--
Indicates that this app requires Google Play Services for AR ("AR Required") and causes
the Google Play Store to download and install Google Play Services for AR along with
the app. For an "AR Optional" app, specify "optional" instead of "required".
-->
<meta-data
android:name="com.google.ar.core"
android:value="required" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<!-- Additional elements here -->
</application>
Entri metadata pertama menunjukkan bahwa ARCore adalah persyaratan untuk menjalankan aplikasi ini dan yang kedua adalah cara Anda memberikan kunci API Google Maps Platform ke Maps SDK for Android.
build.gradle
Dalam build.gradle
, dependensi tambahan berikut ditentukan:
dependencies {
// Maps & Location
implementation 'com.google.android.gms:play-services-location:17.0.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.maps.android:maps-utils-ktx:1.7.0'
// ARCore
implementation "com.google.ar.sceneform.ux:sceneform-ux:1.15.0"
// Retrofit
implementation "com.squareup.retrofit2:retrofit:2.7.1"
implementation "com.squareup.retrofit2:converter-gson:2.7.1"
}
Berikut deskripsi singkat untuk masing-masing dependensi:
- Library dengan ID grup
com.google.android.gms
, yaituplay-services-location
danplay-services-maps
, digunakan untuk mengakses informasi lokasi perangkat dan mengakses fungsi yang terkait dengan Google Maps. com.google.maps.android:maps-utils-ktx
adalah library ekstensi Kotlin (KTX) untuk Library Utilitas Maps SDK for Android. Fungsi akan digunakan dalam library ini untuk menempatkan objek virtual di ruang nyata nanti.com.google.ar.sceneform.ux:sceneform-ux
adalah library Sceneform, yang akan memungkinkan Anda merender tampilan 3D yang realistis tanpa harus mempelajari OpenGL.- Dependensi dalam ID grup
com.squareup.retrofit2
adalah dependensi Retrofit, yang memungkinkan Anda menulis klien HTTP dengan cepat untuk berinteraksi dengan Places API.
Struktur project
Di sini, Anda akan menemukan paket dan file berikut:
- **api—**paket ini berisi class yang digunakan untuk berinteraksi dengan Places API menggunakan Retrofit.
- **ar—**paket ini berisi semua file yang terkait dengan ARCore.
- **model—**paket ini berisi satu class data
Place
, yang digunakan untuk melakukan enkapsulasi satu tempat seperti yang ditampilkan oleh Places API. - MainActivity.kt—Ini adalah satu
Activity
yang terdapat dalam aplikasi Anda, yang akan menampilkan peta dan tampilan kamera.
5. Menyiapkan tampilan
Pahami komponen inti aplikasi, diawali dengan bagian-bagian augmented reality.
MainActivity
berisi SupportMapFragment
, yang akan menangani tampilan objek peta, dan subclass ArFragment
—PlacesArFragment
—yang menangani penayangan tampilan augmented reality.
Penyiapan augmented reality
Selain menampilkan tampilan augmented reality, PlacesArFragment
juga akan menangani permintaan izin kamera dari pengguna, jika belum diberikan. Izin tambahan juga dapat diminta dengan mengganti metode getAdditionalPermissions
. Karena Anda juga memerlukan izin akses lokasi dari pengguna, tentukan izin tersebut dan ganti metode getAdditionalPermissions
:
class PlacesArFragment : ArFragment() {
override fun getAdditionalPermissions(): Array<String> =
listOf(Manifest.permission.ACCESS_FINE_LOCATION)
.toTypedArray()
}
Menjalankan aplikasi
Lanjutkan dan buka kode kerangka di direktori starter
pada Android Studio. Jika mengklik Run > Run 'app' dari toolbar dan men-deploy aplikasi ke perangkat atau emulator, Anda akan diminta untuk menyetujui izin akses lokasi dan kamera terlebih dahulu. Lanjutkan dan klik Allow, lalu setelah itu, Anda akan melihat tampilan kamera dan tampilan peta secara berdampingan seperti ini:
Mendeteksi bidang
Setelah melihat sekeliling Anda menggunakan kamera, Anda mungkin melihat beberapa titik putih terhampar di permukaan horizontal, seperti titik putih pada karpet di gambar ini.
Titik putih ini adalah panduan yang disediakan oleh ARCore untuk menunjukkan bahwa bidang horizontal telah terdeteksi. Bidang yang terdeteksi ini memungkinkan Anda membuat "anchor" yang memungkinkan Anda menempatkan objek virtual di ruang nyata.
Untuk informasi selengkapnya tentang ARCore dan bagaimana ARCore memahami lingkungan di sekitar Anda, baca tentang konsep dasarnya.
6. Mendapatkan data tempat-tempat terdekat
Berikutnya, Anda perlu mengakses dan menampilkan lokasi perangkat saat ini, diikuti dengan mengambil data tempat-tempat terdekat menggunakan Places API.
Penyiapan Maps
Kunci API Google Maps Platform
Sebelumnya, Anda membuat kunci API Google Maps Platform untuk mengaktifkan pembuatan kueri Places API dan agar dapat menggunakan Maps SDK for Android. Lanjutkan dan buka file gradle.properties
, lalu ganti string "YOUR API KEY HERE"
dengan kunci API yang Anda buat.
Menampilkan lokasi perangkat di peta
Setelah Anda menambahkan kunci API, tambahkan bantuan di peta untuk membantu mengorientasikan posisi pengguna yang relatif terhadap peta. Untuk melakukannya, lihat metode setUpMaps
dan di dalam panggilan mapFragment.getMapAsync
, setel googleMap.isMyLocationEnabled
ke true.
Penyetelan tersebut akan menampilkan titik biru pada peta.
private fun setUpMaps() {
mapFragment.getMapAsync { googleMap ->
googleMap.isMyLocationEnabled = true
// ...
}
}
Mendapatkan lokasi saat ini
Untuk mendapatkan lokasi perangkat, Anda harus menggunakan class FusedLocationProviderClient
. Mendapatkan instance ini sudah dilakukan dalam metode onCreate
dari MainActivity
. Untuk memanfaatkan objek ini, lengkapi metode getCurrentLocation
, yang menerima argumen lambda sehingga lokasi dapat diteruskan ke pemanggil metode ini.
Untuk menyelesaikan metode ini, Anda dapat mengakses properti lastLocation
dari objek FusedLocationProviderClient
yang diikuti dengan menambahkan addOnSuccessListener
, seperti:
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
currentLocation = location
onSuccess(location)
}.addOnFailureListener {
Log.e(TAG, "Could not get location")
}
Metode getCurrentLocation
dipanggil dari dalam lambda yang disediakan di getMapAsync
dalam metode setUpMaps
, yang digunakan untuk mengambil data tempat-tempat terdekat.
Memulai panggilan jaringan tempat
Dalam panggilan metode getNearbyPlaces
, perhatikan bahwa parameter berikut diteruskan ke metode placesServices.nearbyPlaces
—kunci API, lokasi perangkat, radius dalam meter (yang ditetapkan ke 2 km), dan jenis tempat (saat ini ditetapkan ke park
).
val apiKey = "YOUR API KEY"
placesService.nearbyPlaces(
apiKey = apiKey,
location = "${location.latitude},${location.longitude}",
radiusInMeters = 2000,
placeType = "park"
)
Untuk menyelesaikan panggilan jaringan, lanjutkan dan teruskan kunci API yang Anda tentukan di file gradle.properties
. Cuplikan kode berikut ditentukan dalam file build.gradle
Anda pada konfigurasi android > defaultConfig:
android {
defaultConfig {
resValue "string", "google_maps_key", (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
}
}
Tindakan ini akan membuat nilai resource string google_maps_key
tersedia pada waktu build.
Untuk menyelesaikan panggilan jaringan, Anda dapat membaca resource string ini melalui getString
pada objek Context
.
val apiKey = this.getString(R.string.google_maps_key)
7. Tempat di AR
Hingga saat ini, Anda telah melakukan hal berikut:
- Meminta izin kamera dan akses lokasi dari pengguna saat pertama kali menjalankan aplikasi
- Menyiapkan ARCore untuk mulai melacak bidang horizontal
- Menyiapkan Maps SDK dengan kunci API Anda
- Mendapatkan lokasi perangkat saat ini
- Mengambil data tempat-tempat terdekat (khususnya taman) menggunakan Places API
Langkah selanjutnya untuk menyelesaikan latihan ini adalah dengan memosisikan tempat-tempat yang Anda ambil datanya di augmented reality.
Pemahaman tentang tampilan
ARCore dapat memahami tampilan dunia nyata melalui kamera perangkat dengan mendeteksi titik menarik dan berbeda yang disebut titik fitur di setiap frame gambar. Ketika titik fitur ini dikelompokkan dan tampak berada di bidang horizontal yang sama, seperti meja dan lantai, ARCore dapat menampilkan titik fitur ini di aplikasi sebagai bidang horizontal.
Seperti yang Anda lihat sebelumnya, ARCore membantu memandu pengguna saat bidang terdeteksi dengan menampilkan titik putih.
Menambahkan anchor
Setelah bidang terdeteksi, Anda dapat menambahkan objek yang disebut anchor. Dengan menggunakan anchor, Anda dapat menempatkan objek virtual dan menjamin bahwa objek tersebut akan tetap berada di posisi yang sama di ruang nyata. Lanjutkan dan ubah kode untuk mengaitkan anchor setelah bidang terdeteksi.
Di setUpAr
, OnTapArPlaneListener
dikaitkan ke PlacesArFragment
. Pemroses ini dipanggil setiap kali bidang terdeteksi di tampilan AR. Dalam panggilan ini, Anda dapat membuat Anchor
dan AnchorNode
dari HitResult
yang disediakan di pemroses, seperti:
arFragment.setOnTapArPlaneListener { hitResult, _, _ ->
val anchor = hitResult.createAnchor()
anchorNode = AnchorNode(anchor)
anchorNode?.setParent(arFragment.arSceneView.scene)
addPlaces(anchorNode!!)
}
AnchorNode
adalah tempat Anda akan menyertakan objek node turunan—instance PlaceNode
—pada tampilan yang ditangani dalam panggilan metode addPlaces
.
Menjalankan aplikasi
Jika Anda menjalankan aplikasi dengan modifikasi di atas, lihat di sekitar Anda hingga bidang terdeteksi. Lanjutkan dan ketuk titik putih yang menunjukkan sebuah bidang. Setelah melakukannya, Anda akan melihat penanda di peta untuk semua taman terdekat di sekitar Anda. Namun, jika Anda perhatikan, objek virtual tersebut tertahan di anchor yang dibuat dan tidak ditempatkan pada lokasi yang relatif terhadap tempat taman tersebut berada di ruang nyata.
Untuk langkah terakhir, Anda dapat memperbaikinya menggunakan Library Utilitas Maps SDK for Android dan SensorManager di perangkat.
8. Memosisikan tempat
Agar dapat menempatkan ikon tempat virtual dalam augmented reality pada arah tujuan yang akurat, Anda memerlukan dua informasi:
- Arah utara sebenarnya
- Sudut antara utara dan masing-masing tempat
Menentukan arah utara
Arah utara dapat ditentukan menggunakan sensor posisi (geomagnet dan akselerometer) yang tersedia di perangkat. Dengan menggunakan kedua sensor ini, Anda dapat mengumpulkan informasi real-time tentang posisi perangkat di ruang nyata. Untuk informasi selengkapnya tentang sensor posisi, baca Menghitung orientasi perangkat.
Untuk mengakses sensor ini, Anda harus mendapatkan SensorManager
, yang diikuti dengan mendaftarkan SensorEventListener
pada sensor tersebut. Langkah-langkah ini sudah dilakukan untuk Anda pada metode siklus proses MainActivity
:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
sensorManager = getSystemService()!!
// ...
}
override fun onResume() {
super.onResume()
sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)?.also {
sensorManager.registerListener(
this,
it,
SensorManager.SENSOR_DELAY_NORMAL
)
}
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)?.also {
sensorManager.registerListener(
this,
it,
SensorManager.SENSOR_DELAY_NORMAL
)
}
}
override fun onPause() {
super.onPause()
sensorManager.unregisterListener(this)
}
Dalam metode onSensorChanged
, objek SensorEvent
disediakan, yang berisi detail tentang data sensor tertentu yang berubah dari waktu ke waktu. Lanjutkan dan tambahkan kode berikut ke dalam metode tersebut:
override fun onSensorChanged(event: SensorEvent?) {
if (event == null) {
return
}
if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.size)
} else if (event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD) {
System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size)
}
// Update rotation matrix, which is needed to update orientation angles.
SensorManager.getRotationMatrix(
rotationMatrix,
null,
accelerometerReading,
magnetometerReading
)
SensorManager.getOrientation(rotationMatrix, orientationAngles)
}
Kode di atas memeriksa jenis sensor dan, bergantung pada jenisnya, kode tersebut akan memperbarui pembacaan sensor yang sesuai (baik pembacaan akselerometer atau magnetometer). Dengan menggunakan pembacaan sensor ini, jumlah derajat dari utara relatif terhadap perangkat sekarang dapat ditentukan (yaitu, nilai orientationAngles[0]
).
Arah tujuan sferikal
Karena utara telah ditentukan, langkah berikutnya adalah menentukan sudut antara utara dan masing-masing tempat, diikuti dengan menggunakan informasi tersebut untuk memosisikan tempat pada arah tujuan yang tepat di augmented reality.
Untuk menghitung arah tujuan, Anda akan menggunakan Library Utilitas Maps SDK for Android, yang berisi sejumlah fungsi bantuan untuk menghitung jarak dan arah tujuan melalui geometri sferikal. Untuk informasi selengkapnya, baca ringkasan library ini.
Selanjutnya, Anda akan menggunakan metode sphericalHeading
di library utilitas, yang menghitung arah tujuan/sudut arah antara dua objek LatLng
. Informasi ini diperlukan di dalam metode getPositionVector
yang ditentukan di Place.kt
. Metode ini pasti akan menampilkan objek Vector3
, yang kemudian akan digunakan oleh setiap PlaceNode
sebagai posisi lokalnya di ruang AR.
Lanjutkan dan ganti definisi arah tujuan dalam metode tersebut dengan kode berikut:
val heading = latLng.sphericalHeading(placeLatLng)
Tindakan ini akan menghasilkan definisi metode berikut:
fun Place.getPositionVector(azimuth: Float, latLng: LatLng): Vector3 {
val placeLatLng = this.geometry.location.latLng
val heading = latLng.sphericalHeading(placeLatLng)
val r = -2f
val x = r * sin(azimuth + heading).toFloat()
val y = 1f
val z = r * cos(azimuth + heading).toFloat()
return Vector3(x, y, z)
}
Posisi lokal
Langkah terakhir untuk mengorientasikan tempat secara tepat di AR adalah dengan menggunakan hasil getPositionVector
saat objek PlaceNode
ditambahkan ke tampilan. Lanjutkan dan buka addPlaces
di MainActivity
, tepat di bawah baris tempat induk ditetapkan pada setiap placeNode
(tepat di bawah placeNode.setParent(anchorNode)
). Setel localPosition
placeNode
ke hasil pemanggilan getPositionVector
seperti berikut:
val placeNode = PlaceNode(this, place)
placeNode.setParent(anchorNode)
placeNode.localPosition = place.getPositionVector(orientationAngles[0], currentLocation.latLng)
Secara default, metode getPositionVector
menetapkan jarak y node menjadi 1 meter seperti yang ditetapkan oleh nilai y
pada metode getPositionVector
. Jika Anda ingin menyesuaikan jarak ini, misalnya 2 meter, lanjutkan dan ubah nilai tersebut sesuai kebutuhan.
Dengan perubahan ini, objek PlaceNode
yang ditambahkan kini berorientasi ke arah tujuan yang benar. Sekarang lanjutkan dan jalankan aplikasi untuk melihat hasilnya.