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 به آن دسترسی پیدا کنید.
- بررسی کنید که آیا اندروید 10.0 نصب شده است یا خیر. در غیر این صورت، با انتخاب کادر کنار Android 10.0 (Q) آن را نصب کنید، سپس روی OK کلیک کنید و در نهایت دوباره روی OK در گفتگوی ظاهر شده کلیک کنید.
- در نهایت، با رفتن به برگه ابزار SDK ، سرویسهای Google Play را نصب کنید، کادر کنار خدمات Google Play را انتخاب کنید، روی OK کلیک کنید، سپس دوباره تأیید را در گفتگوی ظاهر شده انتخاب کنید**.**
API های مورد نیاز
در مرحله 3 از بخش زیر، Maps SDK برای Android و Places API را برای این کد لبه فعال کنید.
با پلتفرم نقشه های گوگل شروع کنید
اگر قبلاً از 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
کتابخانه Sceneform است که به شما امکان می دهد صحنه های سه بعدی واقعی را بدون نیاز به یادگیری OpenGL ارائه دهید. - وابستگیهای درون گروه ID
com.squareup.retrofit2
، وابستگیهای Retrofit هستند که به شما امکان میدهند به سرعت یک کلاینت 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 پلت فرم Google Maps
پیش از این، یک کلید API پلتفرم Google Maps ایجاد کردید تا پرس و جو در API مکانها را فعال کند و بتوانید از Maps SDK برای Android استفاده کنید. ادامه دهید و فایل 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
جایی است که در صحنه ای که در فراخوانی متد addPlaces
کنترل می شود، اشیاء گره فرزند – نمونه های PlaceNode
– را متصل می کنید.
اجراش کن
اگر برنامه را با تغییرات بالا اجرا می کنید، به اطراف خود نگاه کنید تا زمانی که هواپیما شناسایی شود. پیش بروید و روی نقاط سفیدی که نشان دهنده یک هواپیما هستند ضربه بزنید. پس از انجام این کار، اکنون باید نشانگرهای تمام نزدیکترین پارک های اطراف خود را روی نقشه ببینید. با این حال، اگر متوجه شده باشید، اشیاء مجازی روی لنگر ایجاد شده چسبیده اند و نسبت به جایی که آن پارک ها در فضا هستند قرار نمی گیرند.
برای آخرین مرحله، این مورد را با استفاده از 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
در کتابخانه ابزار استفاده خواهید کرد، که عنوان/برینگ بین دو شی LatLng
محاسبه می کند. این اطلاعات در داخل متد getPositionVector
تعریف شده در Place.kt
مورد نیاز است. این روش در نهایت یک شی Vector3
را برمی گرداند، که سپس توسط هر PlaceNode
به عنوان موقعیت محلی خود در فضای 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. تبریک می گویم
تبریک می گویم برای رسیدن به اینجا!