1. Başlamadan önce
Soyut
Bu codelab'de, yakındaki yerleri Android'de artırılmış gerçeklik (AR) ile göstermek için Google Haritalar Platformu'ndaki verileri nasıl kullanacağınızı öğretiyoruz.
Ön koşullar
- Android Studio'yu kullanarak Android geliştirmeyle ilgili temel bilgiler
- Kotlin aşinalığı
Neler öğreneceksiniz?
- Cihazın kamerasına ve konumuna erişmek için kullanıcıdan izin isteyin.
- Cihazın konumunu etrafındaki yerleri getirmek için Places API ile entegrasyon yapın.
- Yatay düzlem yüzeylerini bulmak için ARCore ile entegre edin. Böylece, sanal nesneler Sceneform kullanılarak sabitlenebilir ve 3D bir alana eklenebilir.
- SensorManager'ı kullanarak cihazın uzaydaki konumu hakkında bilgi toplayın. Ayrıca, sanal nesneleri doğru başlığa yerleştirmek için Android Yardımcı Kitaplık Kitaplığı'nı kullanın.
Gerekenler
- Android Studio 2020.3.1 veya sonraki sürümler
- OpenGL ES 3.0 veya sonraki sürümlerini destekleyen bir geliştirme makinesi
- ARCore destekli bir cihaz veya ARCore destekli Android Emülatör (talimatlar sonraki adımda sağlanmıştır)
2. Hazırlanın
Android Studio
Bu codelab'de Android 10.0 (API düzeyi 29) kullanılmaktadır ve Android Studio'da Google Play hizmetlerinin yüklü olması gerekir. Bu bağımlılıkların her ikisini de yüklemek için aşağıdaki adımları tamamlayın:
- Araçlar > SDK Manager'ı tıklayarak erişebileceğiniz SDK Yöneticisi'ne gidin.
- Android 10.0'ın yüklü olup olmadığını kontrol edin. Açık değilse Android 10.0 (Q) seçeneğinin yanındaki onay kutusunu işaretleyip Tamam'ı tıkladıktan sonra açılan iletişim kutusunda tekrar Tamam'ı tıklayın.
- Son olarak, SDK Tools (SDK Araçları) sekmesine gidip Google Play hizmetleri'nin yanındaki onay kutusunu işaretleyin, Tamam'ı tıklayın ve açılan iletişim kutusunda tekrar OK'i (Tamam) seçin**.**
Gerekli API'ler
Aşağıdaki bölümün 3. adımında, bu codelab için Android için Haritalar SDK'sı ve Places API'yi etkinleştirin.
Google Haritalar Platformu'nu kullanmaya başlayın
Google Haritalar Platformu'nu daha önce kullanmadıysanız Google Haritalar Platformu'nu Kullanmaya Başlama rehberini izleyerek veya Google Haritalar Platformu oynatma listesini izleyerek aşağıdaki adımları tamamlayın:
- Faturalandırma hesabı oluşturun.
- Bir proje oluşturun.
- Google Haritalar Platformu API'lerini ve SDK'larını etkinleştirin (bir önceki bölümde listelenmiştir).
- API anahtarı oluşturun.
İsteğe bağlı: Android Emülatör
ARCore destekli bir cihazınız yoksa alternatif olarak AR sahnesi simüle etmek ve cihazınızın konumunu taklit etmek için Android Emülatör'ü kullanabilirsiniz. Bu egzersizde Sceneform da kullanacağınız göz önünde bulundurulduğunda, "Emülatörü "Sceneform"u destekleyecek şekilde yapılandırma" bölümündeki adımları da uygulamanız gerekir.
3. Hızlı başlangıç
En kısa sürede başlamanıza yardımcı olmak için aşağıda, bu codelab'i takip etmenize yardımcı olacak bazı başlangıç kodları verilmiştir. Çözüme geçebilirsiniz, ancak tüm adımları görmek isterseniz okumaya devam edin.
git
yüklediyseniz kod deposunu klonlayabilirsiniz.
git clone https://github.com/googlecodelabs/display-nearby-places-ar-android.git
Alternatif olarak, kaynak kodu indirmek için aşağıdaki düğmeyi tıklayabilirsiniz.
Kodu aldıktan sonra starter
dizininde bulunan projeyi açın.
4. Projeye genel bakış
Önceki adımda indirdiğiniz kodu keşfedin. Bu veri havuzunun içinde com.google.codelabs.findnearbyplacesar
paketini içeren app
adlı tek bir modül göreceksiniz.
AndroidManifest.xml
Bu codelab'de gerekli özellikleri kullanabilmeniz için AndroidManifest.xml
dosyasında aşağıdaki özellikler beyan edilir:
<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" />
Bu özelliklerin kullanılabilmesi için önce kullanıcı tarafından hangi izinlerin verilmesi gerektiğini belirten uses-permission
öğesinde şunlar beyan edilir:
android.permission.INTERNET
: Böylece uygulamanızın ağ işlemleri yapabilir ve internet üzerinden Yerler API'si aracılığıyla yer bilgileri gibi verileri alabilirsiniz.android.permission.CAMERA
: Nesneleri artırılmış gerçeklikte görüntülemek için cihazın kamerasını kullanmak üzere kamera erişimi gereklidir.android.permission.ACCESS_FINE_LOCATION
: Yakındaki yerleri cihazın konumuna göre getirebilmeniz için konum erişimi gereklidir.
Bu uygulamanın ihtiyaç duyduğu donanım özelliklerini belirten uses-feature
için aşağıdakiler bildirilir:
- OpenGL ES sürüm 3.0 gereklidir.
- ARCore uyumlu cihaz gerekiyor.
Ayrıca, aşağıdaki meta veri etiketleri uygulama nesnesinin altına eklenir:
<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>
İlk meta veri girişi, ARCore'un bu uygulamanın çalışması için bir gereklilik olduğunu, ikincisi ise Android için Haritalar SDK'sına Google Maps Platform API anahtarınızı nasıl sağladığınızı belirtmektir.
build.gradle
build.gradle
içinde, aşağıdaki ek bağımlılıklar belirtilir:
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"
}
Aşağıda her bağımlının kısa bir açıklaması verilmiştir:
com.google.android.gms
grup kimliğine sahip kitaplıklar (play-services-location
veplay-services-maps
) cihazın konum bilgilerine erişmek ve Google Haritalar ile ilgili işlevlere erişmek için kullanılır.com.google.maps.android:maps-utils-ktx
, Android Yardımcı Program Kitaplığı'nın Haritalar SDK'sı için Kotlin uzantıları (KTX) kitaplığıdır. İşlevsellik bu kitaplıkta daha sonra sanal nesneleri gerçek zamanlı olarak konumlandırmak için kullanılır.com.google.ar.sceneform.ux:sceneform-ux
, OpenGL'yi öğrenmek zorunda kalmadan gerçekçi 3D sahneler oluşturmanıza olanak tanıyan Sceneform kitaplığıdır.com.squareup.retrofit2
grup kimliği içindeki bağımlılar, Places API ile etkileşim kurmak için hızlıca bir HTTP istemcisi yazmanıza olanak tanıyan Retrofit bağımlılıklarıdır.
Proje yapısı
Burada, aşağıdaki paketleri ve dosyaları bulabilirsiniz:
- **api:**Bu paket, Retrofit kullanarak Places API ile etkileşimde bulunmak için kullanılan sınıfları içerir.
- **ar—**Bu paket ARCore ile ilgili tüm dosyaları içermektedir.
- **model—**Bu paket, tek bir yeri Place API'nin döndürdüğü şekilde doldurmak için kullanılan tek bir veri sınıfı
Place
içerir. - MainActivity.kt: Bu, uygulama içinde yer alan ve bir harita ile kamera görünümünü gösteren tek
Activity
.
5. Sahne ayarlama
Artırılmış gerçeklik parçalarıyla başlayarak uygulamanın temel bileşenlerini inceleyin.
MainActivity
, harita nesnesinin işleneceği bir SupportMapFragment
ve artırılmış gerçeklik sahnesinin gösterilmesini sağlayan bir ArFragment
PlacesArFragment
öğesinin alt sınıfını içerir.
Artırılmış gerçeklik kurulumu
PlacesArFragment
, artırılmış gerçeklik sahnesini görüntülemenin yanı sıra, daha önce verilmediği takdirde kullanıcıdan kamera izni istemeyi de yerine getirir. getAdditionalPermissions
yöntemi geçersiz kılınarak ek izinler de istenebilir. Buna ek olarak, konum izni verilmesi içingetAdditionalPermissions
class PlacesArFragment : ArFragment() {
override fun getAdditionalPermissions(): Array<String> =
listOf(Manifest.permission.ACCESS_FINE_LOCATION)
.toTypedArray()
}
Çalıştır
Şimdi Android Studio'da starter
dizinindeki iskelet kodunu açın. Araç çubuğundan Çalıştır > Çalıştır 'uygulamasını##39; seçeneğini tıklayıp uygulamayı cihazınıza veya emülatöre dağıtıyorsanız öncelikle konum ve kamera iznini etkinleştirmeniz istenir. Artık İzin ver'i tıklayabilirsiniz. Bunu yaptığınızda aşağıdaki gibi bir kamera görünümü ve bir harita görünümü görürsünüz:
Uçakları algılama
Kameranızın bulunduğu ortamda etrafa baktığınızda, bu resimdeki halı üzerinde beyaz noktalar gibi yatay yüzeylerin üzerine yerleştirilmiş birkaç beyaz nokta görebilirsiniz.
Bu beyaz noktalar, yatay bir uçağın tespit edildiğini belirtmek için ARCore tarafından sağlanan yönergelerdir. Algılanan bu uçaklar, sanal nesneleri gerçek zamanlı olarak konumlandırabilmeniz için "sabit" adı verilen öğeler oluşturmanıza olanak tanır.
ARCore ve etrafınızdaki ortamı nasıl anladığı hakkında daha fazla bilgi edinmek için temel kavramları hakkında bilgi edinin.
6. Yakındaki yerleri alın
Daha sonra, cihazın mevcut konumuna erişip görüntülemeniz ve ardından Places API'sini kullanarak yakındaki yerleri getirmeniz gerekir.
Haritalar kurulumu
Google Maps Platform API anahtarı
Daha önce, Places API'yi sorgulamayı etkinleştirmek ve Android için Haritalar SDK'sını kullanabilmek amacıyla bir Google Maps Platform API anahtarı oluşturmuştunuz. Şimdi gradle.properties
dosyasını açıp "YOUR API KEY HERE"
dizesini oluşturduğunuz API anahtarıyla değiştirin.
Cihaz konumunu haritada göster
API anahtarınızı ekledikten sonra, kullanıcıları haritaya göre yönlendirmelerine yardımcı olmak için haritaya bir yardımcı ekleyin. Bunu yapmak için setUpMaps
yöntemine gidin ve mapFragment.getMapAsync
aramasının içinde googleMap.isMyLocationEnabled
değerini true.
olarak ayarlayın. Bunu yaptığınızda harita üzerinde mavi nokta gösterilir.
private fun setUpMaps() {
mapFragment.getMapAsync { googleMap ->
googleMap.isMyLocationEnabled = true
// ...
}
}
Mevcut konumu al
Cihazın konumunu almak için FusedLocationProviderClient
sınıfını kullanmanız gerekir. Bunun bir MainActivity
örneği, onCreate
yönteminde zaten kazanılmış. Bu nesneden yararlanmak için bir lambda bağımsız değişkenini kabul eden getCurrentLocation
yöntemini doldurun. Böylece bir yöntem, bu yöntemin arayanına iletilebilir.
Bu yöntemi tamamlamak için FusedLocationProviderClient
nesnesinin lastLocation
özelliğine erişebilir ve ardından aşağıdaki gibi bir addOnSuccessListener
ekleyebilirsiniz:
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
currentLocation = location
onSuccess(location)
}.addOnFailureListener {
Log.e(TAG, "Could not get location")
}
getCurrentLocation
yöntemi, getMapAsync
içinde sağlanan lambdanın içinden, yakındaki yerlerin getirildiği setUpMaps
yöntemiyle çağrılır.
Yer ağ çağrısını başlatma
getNearbyPlaces
yöntemi çağrısında, aşağıdaki parametrelerin placesServices.nearbyPlaces
yöntemine iletildiğini unutmayın: API anahtarı, cihazın konumu, metre cinsinden yarıçap (2 km olarak ayarlanır) ve bir yer türü (şu anda park
olarak ayarlanmıştır).
val apiKey = "YOUR API KEY"
placesService.nearbyPlaces(
apiKey = apiKey,
location = "${location.latitude},${location.longitude}",
radiusInMeters = 2000,
placeType = "park"
)
Ağ çağrısını tamamlamak için gradle.properties
dosyanızda tanımladığınız API anahtarını iletin. Aşağıdaki kod snippet'i build.gradle
dosyanızda android > defaultConfig yapılandırması altında tanımlanır:
android {
defaultConfig {
resValue "string", "google_maps_key", (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
}
}
Bu işlem, derleme sırasında google_maps_key
dize kaynağı değerini kullanılabilir hale getirir.
Ağ çağrısını tamamlamak için bu dize kaynağını getString
nesnesini Context
nesnesinde okuyabilirsiniz.
val apiKey = this.getString(R.string.google_maps_key)
7. Artırılmış Gerçeklik'te yerler
Şimdiye kadar aşağıdakileri yaptınız:
- Uygulamayı ilk kez çalıştırırken kullanıcıdan kamera ve konum izinleri istendi
- Yatay uçakları izlemeye başlamak için ARCore'u kurun
- Haritalar SDK'sını API anahtarınızla ayarlama
- Cihazın mevcut konumu alındı
- Yerler API'si kullanılarak yakındaki yerler (özellikle parklar) getirildi
Bu egzersizi tamamlamak için kalan adım, artırılmış gerçeklik olarak getirdiğiniz yerleri konumlandırmaktır.
Sahne anlama
ARCore, her karede özellik noktaları adı verilen ilginç ve farklı noktaları tespit ederek cihazın kamerasıyla gerçek dünyadaki sahneyi anlayabilir. Bu özellik noktaları birleştirilip masalar ve zeminler gibi yaygın olarak kullanılan yatay bir düzlemde yattığında ARCore, bu özelliği uygulamada yatay düzlem olarak kullanabilir.
Daha önce gördüğünüz gibi, ARCore, beyaz nokta görüntüleyerek bir uçak algılandığında kullanıcıya yol göstermeye yardımcı olur.
Sabitleme ekleme
Uçak algılandıktan sonra sabit adı verilen bir nesne ekleyebilirsiniz. Bir bağlantı aracı üzerinden, sanal nesneler yerleştirebilir ve bu nesnelerin uzayda aynı konumda kalacağını garanti edebilirsiniz. Devam edin ve uçağın algılandığı kodu eklemek için kodu değiştirin.
setUpAr
içinde, PlacesArFragment
öğesine bir OnTapArPlaneListener
eklenir. Bu dinleyici, AR sahnesinde bir uça dokunulduğunda çağrılır. Bu görüşmede, dinleyicide sağlanan HitResult
kaynağından şu şekilde bir Anchor
ve AnchorNode
oluşturabilirsiniz:
arFragment.setOnTapArPlaneListener { hitResult, _, _ ->
val anchor = hitResult.createAnchor()
anchorNode = AnchorNode(anchor)
anchorNode?.setParent(arFragment.arSceneView.scene)
addPlaces(anchorNode!!)
}
AnchorNode
, addPlaces
yöntem çağrısında işlenen sahnede alt düğüm nesnelerini (PlaceNode
örnek) ekleyeceğiniz yerdir.
Çalıştır
Uygulamayı yukarıdaki değişikliklerle çalıştırırsanız bir uçak algılanana kadar çevrenize bakın. Şimdi uçağı gösteren beyaz noktalara dokunabilirsin. Bunu yaptığınızda artık harita üzerinde, en yakın parkların işaretçilerini göreceksiniz. Ancak sanal nesneler, oluşturulmuş çapada takılı kalır ve bu parkların uzayda bulunduğu yere göre yerleştirilmez.
Son adımda, cihazınızda Android Yardımcı Program Kitaplığı için Haritalar SDK'sı ve SensorManager'ı kullanarak bu sorunu düzeltebilirsiniz.
8. Yerleri konumlandırma
Sanal yer simgesini artırılmış gerçeklikte doğru bir başlıkta konumlandırabilmek için iki bilgi gerekir:
- Doğru kuzey
- Kuzey ve her yer arasındaki açı
Kuzeyi belirleme
Cihazda bulunan konum sensörleri (jeomanyetik ve ivme ölçer) kullanılarak Kuzey değeri belirlenebilir. Bu iki sensörü kullanarak cihazın uzaydaki konumuyla ilgili gerçek zamanlı bilgileri toplayabilirsiniz. Konum sensörleri hakkında daha fazla bilgi edinmek için Cihazın yönünü işleme başlıklı makaleyi inceleyin.
Bu sensörlere erişmek için önce SensorManager
sensörü edinmeniz ve ardından bu sensörlere SensorEventListener
kaydettirmeniz gerekir. Bu adımlar sizin için MainActivity
'yaşam döngüsünde zaten yapılmış:
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)
}
onSensorChanged
yönteminde, zaman içinde değişen belirli bir sensörle ilgili ayrıntıları içeren bir SensorEvent
nesnesi sağlanır. Şimdi aşağıdaki kodu bu yönteme ekleyin:
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)
}
Yukarıdaki kod, sensör türünü kontrol eder ve türe bağlı olarak uygun sensör okuma işlemini (ivme ölçer veya manyetometre okuması) günceller. Bu sensör ölçümleri kullanılarak, kuzeyden cihaza göre kaç derecenin değeri artık belirlenebilir (yani orientationAngles[0]
değeri).
Küresel başlık
Kuzey bölümü belirlendiğine göre sonraki adım, kuzey ile her yer arasındaki açıyı belirlemek ve daha sonra bu bilgileri artırılmış gerçeklikte doğru başlıkta konumlandırmak için kullanmaktır.
Başlığı hesaplamak için, geometrik biçimdeki mesafeleri ve başlıkları hesaplamak üzere kullanılan bir dizi yardımcı işlev içeren Android Yardımcı Program Kitaplığı'nın SDK'sını kullanırsınız. Daha fazla bilgi için kitaplığa genel bakış başlıklı makaleyi okuyun.
Ardından, yardımcı program kitaplığındaki sphericalHeading
yöntemini kullanırsınız. Bu yöntem, iki LatLng
nesnesi arasındaki başlığı/konumu hesaplar. Bu bilgi, Place.kt
öğesinde tanımlanan getPositionVector
yöntemi içinde gereklidir. Bu yöntem, daha sonra, her bir PlaceNode
tarafından AR alanında yerel konumu olarak kullanılacak bir Vector3
nesnesi döndürür.
Devam edip bu yöntemdeki başlık tanımını aşağıdaki gibi değiştirin:
val heading = latLng.sphericalHeading(placeLatLng)
Bu, aşağıdaki yöntem tanımını gerektirir:
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)
}
Yerel konum
Artırılmış gerçeklikte (AR) yerleri doğru şekilde yönlendirmek için son adım, PlaceNode
nesneleri sahneye eklenirken getPositionVector
sonucunu kullanmaktır. Devam edip MainActivity
içinde, her placeNode
üzerinde ebeveynin bulunduğu satırın hemen altındaki addPlaces
bölümüne gidin (placeNode.setParent(anchorNode)
ifadesinin hemen altında). placeNode
localPosition
öğesini şu şekilde arayın:
val placeNode = PlaceNode(this, place)
placeNode.setParent(anchorNode)
placeNode.localPosition = place.getPositionVector(orientationAngles[0], currentLocation.latLng)
Varsayılan olarak, getPositionVector
yöntemi, düğümün y mesafesini getPositionVector
yönteminde y
değeriyle belirtildiği şekilde 1 metre olarak ayarlar. Örneğin, bu mesafeyi ayarlamak istiyorsanız 2 metreye gidip bu değeri gereken şekilde değiştirin.
Bu değişiklikle birlikte, eklenen PlaceNode
nesneleri artık doğru başlığa odaklanmalıdır. Şimdi sonucu görmek için uygulamayı çalıştırın.
9. Tebrikler
Tebrikler!