1. قبل از شروع
خلاصه
این آزمایشگاه کد به شما می آموزد که چگونه از داده های پلتفرم نقشه های گوگل برای نمایش مکان های نزدیک در واقعیت افزوده (AR) در اندروید استفاده کنید.
پیش نیازها
- درک اولیه توسعه اندروید با استفاده از اندروید استودیو
- آشنایی با کاتلین
چیزی که یاد خواهید گرفت
- برای دسترسی به دوربین و مکان دستگاه از کاربر اجازه درخواست کنید.
- با Places API ادغام کنید تا مکانهای اطراف را در اطراف مکان دستگاه واکشی کنید.
- با ARCore یکپارچه شوید تا سطوح صفحه افقی را پیدا کنید تا اشیاء مجازی را بتوان با استفاده از Sceneform در فضای سه بعدی لنگر انداخت و قرار داد.
- با استفاده از SensorManager اطلاعاتی درباره موقعیت دستگاه در فضا جمع آوری کنید و از Maps SDK for Android Utility Library برای قرار دادن اشیاء مجازی در عنوان صحیح استفاده کنید.
آنچه شما نیاز دارید
- Android Studio 2020.3.1 یا بالاتر
- یک ماشین توسعه که از OpenGL ES 3.0 یا بالاتر پشتیبانی می کند
- یک دستگاه پشتیبانیشده از ARCore یا شبیهساز Android با قابلیت ARCore (دستورالعملها در مرحله بعدی ارائه میشوند)
2. راه اندازی شوید
اندروید استودیو
این کد لبه از اندروید 10.0 (سطح API 29) استفاده میکند و نیاز دارد که سرویسهای Google Play را در Android Studio نصب کرده باشید. برای نصب هر دوی این وابستگی ها، مراحل زیر را انجام دهید:
- به مدیر SDK بروید، که میتوانید با کلیک کردن روی Tools > SDK Manager به آن دسترسی پیدا کنید.
- بررسی کنید که آیا Android 10.0 نصب شده است یا خیر. در غیر این صورت، آن را با انتخاب کادر کنار Android 10.0 (Q) نصب کنید، سپس روی OK کلیک کنید و در نهایت مجدداً در گفتگوی ظاهر شده روی OK کلیک کنید.
- در نهایت، با رفتن به تب ابزار SDK ، سرویسهای Google Play را نصب کنید، کادر کنار خدمات Google Play را انتخاب کنید، روی OK کلیک کنید، سپس دوباره تأیید را در گفتگوی ظاهر شده انتخاب کنید**.**
API های مورد نیاز
در مرحله 3 از بخش زیر، Maps SDK برای Android و Places API را برای این کد لبه فعال کنید.
با پلتفرم Google Maps شروع کنید
اگر قبلاً از Google Maps Platform استفاده نکردهاید، راهنمای Get Started with Google Maps Platform را دنبال کنید یا لیست پخش Started with Google Maps Platform را برای تکمیل مراحل زیر تماشا کنید:
- یک حساب صورتحساب ایجاد کنید.
- یک پروژه ایجاد کنید.
- APIها و SDKهای پلتفرم Google Maps را فعال کنید (در قسمت قبل فهرست شده است).
- یک کلید API ایجاد کنید.
اختیاری: شبیه ساز اندروید
اگر دستگاهی با پشتیبانی ARCore ندارید، میتوانید از شبیهساز Android برای شبیهسازی صحنه واقعیت افزوده و همچنین جعل موقعیت مکانی دستگاه خود استفاده کنید. با توجه به اینکه در این تمرین از Sceneform نیز استفاده خواهید کرد، باید مراحل زیر "پیکربندی شبیه ساز برای پشتیبانی از Sceneform" را نیز دنبال کنید.
3. شروع سریع
برای شروع هرچه سریعتر، در اینجا چند کد شروع وجود دارد که به شما کمک میکند تا این نرمافزار را دنبال کنید. از شما استقبال می شود که به سراغ راه حل بروید، اما اگر می خواهید تمام مراحل را ببینید، به خواندن ادامه دهید.
اگر git
را نصب کرده اید، می توانید مخزن را کلون کنید.
git clone https://github.com/googlecodelabs/display-nearby-places-ar-android.git
همچنین میتوانید روی دکمه زیر کلیک کنید تا کد منبع را دانلود کنید.
پس از دریافت کد، ادامه دهید و پروژه ای را که در دایرکتوری starter
یافت می شود باز کنید.
4. نمای کلی پروژه
کدی را که از مرحله قبل دانلود کرده اید کاوش کنید. در داخل این مخزن، باید یک ماژول واحد به نام app
پیدا کنید که حاوی بسته com.google.codelabs.findnearbyplacesar
است.
AndroidManifest.xml
ویژگیهای زیر در فایل AndroidManifest.xml
اعلان شدهاند تا بتوانید از ویژگیهای مورد نیاز در این لبه کد استفاده کنید:
<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" />
برای uses-permission
، که مشخص می کند چه مجوزهایی باید توسط کاربر قبل از استفاده از آن قابلیت ها اعطا شود، موارد زیر اعلام شده است:
-
android.permission.INTERNET
— این به این دلیل است که برنامه شما می تواند عملیات شبکه را انجام دهد و داده ها را از طریق اینترنت واکشی کند، مانند اطلاعات مکان ها از طریق Places API. -
android.permission.CAMERA
— دسترسی به دوربین مورد نیاز است تا بتوانید از دوربین دستگاه برای نمایش اشیا در واقعیت افزوده استفاده کنید. -
android.permission.ACCESS_FINE_LOCATION
- دسترسی به مکان مورد نیاز است تا بتوانید مکانهای نزدیک را نسبت به موقعیت مکانی دستگاه واکشی کنید.
برای uses-feature
، که مشخص می کند کدام ویژگی های سخت افزاری مورد نیاز این برنامه است، موارد زیر اعلام شده است:
- OpenGL ES نسخه 3.0 مورد نیاز است.
- دستگاه با قابلیت ARCore مورد نیاز است.
علاوه بر این، تگ های ابرداده زیر در شی برنامه اضافه می شوند:
<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>
اولین ورودی متا داده نشان می دهد که ARCore برای اجرای این برنامه الزامی است و دومی نحوه ارائه کلید API پلتفرم Google Maps خود به Maps SDK برای Android است.
build.gradle
در build.gradle
، وابستگی های اضافی زیر مشخص شده است:
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"
}
در اینجا شرح مختصری از هر وابستگی آورده شده است:
- کتابخانههایی با شناسه گروه
com.google.android.gms
، یعنیplay-services-location
وplay-services-maps
، برای دسترسی به اطلاعات موقعیت مکانی دستگاه و دسترسی به عملکردهای مرتبط با Google Maps استفاده میشوند. -
com.google.maps.android:maps-utils-ktx
کتابخانه برنامههای افزودنی Kotlin (KTX) برای Maps SDK برای کتابخانه ابزار Android است. در این کتابخانه از عملکرد برای قرار دادن اشیاء مجازی در فضای واقعی استفاده خواهد شد. -
com.google.ar.sceneform.ux:sceneform-ux
ux کتابخانه Sceneform است که به شما امکان می دهد صحنه های سه بعدی واقعی را بدون نیاز به یادگیری OpenGL ارائه دهید. - وابستگیهای درون گروه ID com.squareup.retrofit2
com.squareup.retrofit2
هستند که به شما امکان میدهند به سرعت یک کلاینت HTTP بنویسید تا با Places API تعامل داشته باشید.
ساختار پروژه
در اینجا بسته ها و فایل های زیر را خواهید یافت:
- **api—**این بسته شامل کلاس هایی است که برای تعامل با Places API با استفاده از Retrofit استفاده می شود.
- **ar—**این بسته شامل تمامی فایل های مربوط به ARCore می باشد.
- **model—**این بسته شامل یک کلاس داده واحد
Place
است که برای کپسوله کردن یک مکان واحد که توسط Places API برگردانده می شود استفاده می شود. - MainActivity.kt — این تنها
Activity
موجود در برنامه شما است که نقشه و نمای دوربین را نمایش می دهد.
5. تنظیم صحنه
در اجزای اصلی برنامه با قطعات واقعیت افزوده شروع کنید.
MainActivity
شامل یک SupportMapFragment
است که نمایش شی نقشه را انجام می دهد و یک زیر کلاس از یک ArFragment
- PlacesArFragment
- که نمایش صحنه واقعیت افزوده را کنترل می کند.
راه اندازی واقعیت افزوده
جدا از نمایش صحنه واقعیت افزوده، PlacesArFragment
همچنین درخواست مجوز دوربین از کاربر را در صورتی که قبلاً اعطا نشده باشد، رسیدگی خواهد کرد. مجوزهای اضافی را نیز می توان با نادیده گرفتن روش getAdditionalPermissions
درخواست کرد. با توجه به اینکه برای اعطای مجوز مکان نیز نیاز دارید، آن را مشخص کنید و روش getAdditionalPermissions
را لغو کنید:
class PlacesArFragment : ArFragment() {
override fun getAdditionalPermissions(): Array<String> =
listOf(Manifest.permission.ACCESS_FINE_LOCATION)
.toTypedArray()
}
آن را اجرا کنید
ادامه دهید و کد اسکلت را در starter
دایرکتوری در Android Studio باز کنید. اگر روی Run > Run 'app' از نوار ابزار کلیک کنید و برنامه را در دستگاه یا شبیه ساز خود اجرا کنید، ابتدا باید از شما خواسته شود مجوز مکان و دوربین را فعال کنید. ادامه دهید و روی Allow کلیک کنید و پس از انجام این کار، یک نمای دوربین و یک نمای نقشه را در کنار هم مانند این مشاهده خواهید کرد:
شناسایی هواپیماها
با نگاهی به محیطی که با دوربین خود در آن هستید، ممکن است متوجه چند نقطه سفید روی سطوح افقی شوید که شبیه به نقاط سفید روی فرش در این تصویر است.
این نقاط سفید دستورالعمل هایی هستند که توسط ARCore برای نشان دادن اینکه یک صفحه افقی شناسایی شده است ارائه شده است. این هواپیماهای شناسایی شده به شما این امکان را می دهند که چیزی به نام "لنگر" ایجاد کنید تا بتوانید اشیاء مجازی را در فضای واقعی قرار دهید.
برای اطلاعات بیشتر در مورد ARCore و نحوه درک آن از محیط اطراف شما، در مورد مفاهیم اساسی آن مطالعه کنید.
6. مکان های نزدیک را دریافت کنید
در مرحله بعد، باید به مکان فعلی دستگاه دسترسی داشته باشید و سپس مکانهای اطراف را با استفاده از Places API واکشی کنید.
راه اندازی نقشه ها
کلید API پلتفرم نقشه های گوگل
پیش از این، یک کلید API پلتفرم Google Maps ایجاد کردید تا جستجو در Places API را فعال کند و بتوانید از Maps SDK برای اندروید استفاده کنید. ادامه دهید و فایل gradle.properties
را باز کنید و رشته "YOUR API KEY HERE"
را با کلید API که ایجاد کرده اید جایگزین کنید.
نمایش مکان دستگاه روی نقشه
هنگامی که کلید API خود را اضافه کردید، یک راهنما بر روی نقشه اضافه کنید تا به کاربران در جهت دهی آنها نسبت به نقشه کمک کند. برای انجام این کار، به روش setUpMaps
و در تماس mapFragment.getMapAsync
، googleMap.isMyLocationEnabled
را روی true.
با انجام این کار، نقطه آبی روی نقشه نشان داده می شود.
private fun setUpMaps() {
mapFragment.getMapAsync { googleMap ->
googleMap.isMyLocationEnabled = true
// ...
}
}
مکان فعلی را دریافت کنید
برای دریافت موقعیت مکانی دستگاه، باید از کلاس FusedLocationProviderClient
استفاده کنید. به دست آوردن یک نمونه از این قبلاً در روش onCreate
MainActivity
انجام شده است. برای استفاده از این شی، متد getCurrentLocation
را پر کنید، که آرگومان لامبدا را میپذیرد تا یک مکان به فراخواننده این متد ارسال شود.
برای تکمیل این روش، میتوانید به ویژگی lastLocation
شی FusedLocationProviderClient
و سپس افزودن یک addOnSuccessListener
به این صورت دسترسی داشته باشید:
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
currentLocation = location
onSuccess(location)
}.addOnFailureListener {
Log.e(TAG, "Could not get location")
}
متد getCurrentLocation
از داخل لامبدای ارائه شده در getMapAsync
در متد setUpMaps
فراخوانی می شود که مکان های نزدیک از آن واکشی می شوند.
تماس شبکه مکان ها را آغاز کنید
در فراخوانی متد getNearbyPlaces
، توجه داشته باشید که پارامترهای زیر به متد placesServices.nearbyPlaces
منتقل میشوند—یک کلید API، مکان دستگاه، شعاع بر حسب متر (که روی 2 کیلومتر تنظیم شده است) و نوع مکان (در حال حاضر تنظیم شده است). park
کردن).
val apiKey = "YOUR API KEY"
placesService.nearbyPlaces(
apiKey = apiKey,
location = "${location.latitude},${location.longitude}",
radiusInMeters = 2000,
placeType = "park"
)
برای تکمیل تماس شبکه، ادامه دهید و کلید API را که در فایل gradle.properties
خود تعریف کرده اید، وارد کنید. قطعه کد زیر در فایل build.gradle
شما در قسمت android > defaultConfig تعریف شده است:
android {
defaultConfig {
resValue "string", "google_maps_key", (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
}
}
این باعث می شود که مقدار منبع رشته google_maps_key
در زمان ساخت در دسترس باشد.
برای تکمیل تماس شبکه، میتوانید به سادگی این منبع رشته را از طریق getString
در شی Context
بخوانید.
val apiKey = this.getString(R.string.google_maps_key)
7. مکان ها در AR
تا به حال کارهای زیر را انجام داده اید:
- هنگامی که برای اولین بار برنامه را اجرا کرد، از کاربر مجوز دوربین و موقعیت مکانی درخواست کرد
- برای شروع ردیابی صفحات افقی، ARCore را راه اندازی کنید
- Maps SDK را با کلید API خود تنظیم کنید
- مکان فعلی دستگاه را دریافت کردم
- مکانهای نزدیک (مخصوصاً پارکها) با استفاده از Places API واکشی شد
مرحله باقی مانده برای تکمیل این تمرین این است که مکان هایی را که می گیرید در واقعیت افزوده قرار دهید.
درک صحنه
ARCore قادر است صحنه های دنیای واقعی را از طریق دوربین دستگاه با تشخیص نقاط جالب و متمایز به نام نقاط ویژگی در هر فریم تصویر درک کند. هنگامی که این نقاط ویژگی در یک صفحه افقی مشترک قرار دارند، مانند جداول و طبقات، ARCore می تواند این ویژگی را به عنوان یک صفحه افقی در دسترس برنامه قرار دهد.
همانطور که قبلاً دیدید، ARCore با نمایش نقاط سفید به کاربر کمک می کند تا زمانی که هواپیما شناسایی شده است.
اضافه کردن لنگرها
هنگامی که یک هواپیما شناسایی شد، می توانید جسمی به نام لنگر را متصل کنید. از طریق یک لنگر، می توانید اشیاء مجازی را قرار دهید و تضمین کنید که آن اشیا در همان موقعیت در فضا باقی می مانند. پیش بروید و کد را تغییر دهید تا زمانی که هواپیما شناسایی شد، یکی را به آن متصل کنید.
در setUpAr
، یک OnTapArPlaneListener
به PlacesArFragment
متصل است. این شنونده هر زمان که یک هواپیما در صحنه AR ضربه می زند فراخوانی می شود. در این فراخوانی، می توانید یک Anchor
و یک AnchorNode
از HitResult
ارائه شده در شنونده ایجاد کنید:
arFragment.setOnTapArPlaneListener { hitResult, _, _ ->
val anchor = hitResult.createAnchor()
anchorNode = AnchorNode(anchor)
anchorNode?.setParent(arFragment.arSceneView.scene)
addPlaces(anchorNode!!)
}
AnchorNode
جایی است که میتوانید اشیاء گره فرزند - نمونههای PlaceNode
- را در صحنهای که در فراخوانی متد addPlaces
مدیریت میشود، وصل کنید.
آن را اجرا کنید
اگر برنامه را با تغییرات بالا اجرا می کنید، به اطراف خود نگاه کنید تا زمانی که هواپیما شناسایی شود. پیش بروید و روی نقاط سفیدی که نشان دهنده یک هواپیما هستند ضربه بزنید. پس از انجام این کار، اکنون باید نشانگرهای تمام نزدیکترین پارک های اطراف خود را روی نقشه ببینید. با این حال، اگر متوجه شده باشید، اشیاء مجازی روی لنگر ایجاد شده چسبیده اند و نسبت به جایی که آن پارک ها در فضا هستند قرار نمی گیرند.
برای آخرین مرحله، این مورد را با استفاده از Maps SDK for Android Utility Library و SensorManager در دستگاه اصلاح خواهید کرد.
8. مکان یابی
برای اینکه بتوانید نماد مکان مجازی را در واقعیت افزوده در یک عنوان دقیق قرار دهید، به دو اطلاعات نیاز دارید:
- جایی که شمال واقعی است
- زاویه بین شمال و هر مکان
تعیین شمال
شمال را می توان با استفاده از سنسورهای موقعیت (ژئومغناطیسی و شتاب سنج) موجود در دستگاه تعیین کرد. با استفاده از این دو سنسور می توانید اطلاعات لحظه ای در مورد موقعیت دستگاه در فضا جمع آوری کنید. برای اطلاعات بیشتر درباره حسگرهای موقعیت، جهت گیری دستگاه را محاسبه کنید .
برای دسترسی به این حسگرها، باید یک SensorManager
و سپس یک SensorEventListener
در آن سنسورها ثبت کنید. این مراحل قبلاً در روشهای چرخه حیات 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)
}
در روش onSensorChanged
، یک شی SensorEvent
ارائه میشود که حاوی جزئیاتی در مورد دادههای یک سنسور معین که در طول زمان تغییر میکند. ادامه دهید و کد زیر را به آن متد اضافه کنید:
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)
}
کد بالا نوع سنسور را بررسی می کند و بسته به نوع، قرائت سنسور مناسب (شتاب سنج یا مغناطیس سنج) را به روز می کند. با استفاده از این خوانشهای حسگر، اکنون میتوان مقدار چند درجه از شمال نسبت به دستگاه را تعیین کرد (یعنی مقدار orientationAngles[0]
).
عنوان کروی
اکنون که شمال مشخص شده است، گام بعدی تعیین زاویه بین شمال و هر مکان است و سپس با استفاده از آن اطلاعات مکان ها را در عنوان صحیح در واقعیت افزوده قرار می دهیم.
برای محاسبه عنوان، از Maps SDK for Android Utility Library استفاده میکنید، که حاوی تعدادی توابع کمکی برای محاسبه فاصلهها و سرفصلها از طریق هندسه کروی است. برای اطلاعات بیشتر، این نمای کلی از کتابخانه را بخوانید.
در مرحله بعد، از روش sphericalHeading
Heading در کتابخانه ابزار استفاده خواهید کرد، که عنوان/برینگ را بین دو شی LatLng
محاسبه می کند. این اطلاعات در داخل متد getPositionVector
تعریف شده در Place.kt
مورد نیاز است. این روش در نهایت یک شی PlaceNode
Vector3
عنوان موقعیت محلی خود در فضای AR استفاده می شود.
ادامه دهید و تعریف عنوان را در آن متد با موارد زیر جایگزین کنید:
val heading = latLng.sphericalHeading(placeLatLng)
انجام این کار باید به تعریف روش زیر منجر شود:
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)
}
موقعیت محلی
آخرین مرحله برای جهت دهی صحیح مکان ها در AR استفاده از نتیجه getPositionVector
زمانی است که اشیاء PlaceNode
به صحنه اضافه می شوند. ادامه دهید و به addPlaces
در MainActivity
بروید، درست زیر خطی که والد در هر placeNode
تنظیم شده است (راست زیر placeNode.setParent(anchorNode)
). localPosition
را در placeNode
با نتیجه فراخوانی getPositionVector
تنظیم کنید:
val placeNode = PlaceNode(this, place)
placeNode.setParent(anchorNode)
placeNode.localPosition = place.getPositionVector(orientationAngles[0], currentLocation.latLng)
بهطور پیشفرض، متد getPositionVector
فاصله y گره را همانطور که توسط مقدار y
در متد getPositionVector
مشخص میشود، 1 متر تعیین میکند. اگر میخواهید این فاصله را تنظیم کنید، مثلاً 2 متر، ادامه دهید و آن مقدار را در صورت نیاز تغییر دهید.
با این تغییر، اشیاء اضافه شده PlaceNode
اکنون باید در عنوان صحیح جهت گیری شوند. حالا پیش بروید و برنامه را اجرا کنید تا نتیجه را ببینید!
9. تبریک می گویم
تبریک می گویم برای رسیدن به اینجا!