1. قبل از شروع
این کد لبه به شما می آموزد که چگونه Places SDK برای اندروید را با برنامه خود ادغام کنید و از هر یک از ویژگی های Places SDK استفاده کنید.
پیش نیازها
- دانش اولیه کاتلین و توسعه اندروید
چیزی که یاد خواهید گرفت
- نحوه نصب Places SDK برای اندروید با برنامه های افزودنی Kotlin.
- نحوه بارگیری جزئیات مکان برای یک مکان خاص.
- چگونه ویجت تکمیل خودکار مکان را به برنامه خود اضافه کنید.
- نحوه بارگیری مکان کنونی بر اساس مکان گزارش شده فعلی دستگاه.
آنچه شما نیاز دارید
برای تکمیل این کد لبه، به حسابها، خدمات و ابزارهای زیر نیاز دارید:
- یک حساب Google با فعال کردن صورتحساب.
- Android Studio Bumblebee یا بالاتر.
- خدمات Google Play در Android Studio نصب شده است.
- یک دستگاه Android یا یک شبیهساز Android که پلتفرم Google APIs مبتنی بر Android 8 یا بالاتر را اجرا میکند (برای مراحل نصب به اجرای برنامهها در شبیهساز Android مراجعه کنید).
2. راه اندازی شوید
برای مرحله فعال سازی زیر، Places API و Maps SDK را برای Android فعال کنید.
پلتفرم نقشه های گوگل را راه اندازی کنید
اگر قبلاً یک حساب Google Cloud Platform و پروژهای با صورتحساب فعال ندارید، لطفاً راهنمای شروع به کار با Google Maps Platform را برای ایجاد یک حساب صورتحساب و یک پروژه ببینید.
- در Cloud Console ، روی منوی کشویی پروژه کلیک کنید و پروژه ای را که می خواهید برای این کد لبه استفاده کنید انتخاب کنید.
- APIها و SDKهای پلتفرم Google Maps مورد نیاز برای این لبه کد را در Google Cloud Marketplace فعال کنید. برای انجام این کار، مراحل این ویدیو یا این مستند را دنبال کنید.
- یک کلید API در صفحه Credentials در Cloud Console ایجاد کنید. می توانید مراحل این ویدئو یا این مستند را دنبال کنید. همه درخواستها به پلتفرم Google Maps به یک کلید API نیاز دارند.
3. شروع سریع
برای شروع هرچه سریعتر، کد شروع را دانلود کنید تا به شما کمک کند تا این نرمافزار را دنبال کنید. شما می توانید به سراغ راه حل بروید، اما اگر می خواهید تمام مراحل ساخت آن را خودتان دنبال کنید، به خواندن ادامه دهید.
- اگر
git
را نصب کرده اید، مخزن را کلون کنید.
git clone https://github.com/googlemaps/codelab-places-101-android-kotlin.git
یا برای دانلود کد منبع روی این دکمه کلیک کنید.
- پس از دانلود کد، پروژه ای را که در داخل پوشه
/starter
در اندروید استودیو یافت می شود، باز کنید. این پروژه شامل ساختار فایل اصلی است که برای تکمیل کد لبه نیاز دارید. هر چیزی که برای کار با آن نیاز دارید در پوشه/starter
قرار دارد.
اگر می خواهید کد راه حل کامل را در حال اجرا ببینید، می توانید کد تکمیل شده را در پوشه /solution
مشاهده کنید.
4. کلید API خود را به پروژه اضافه کنید
این بخش نحوه ذخیره کلید API خود را توضیح می دهد تا بتواند به طور ایمن توسط برنامه شما ارجاع داده شود. شما نباید کلید API خود را در سیستم کنترل نسخه خود بررسی کنید، بنابراین توصیه می کنیم آن را در فایل secrets.properties
ذخیره کنید، که در کپی محلی شما از دایرکتوری ریشه پروژه شما قرار می گیرد. برای اطلاعات بیشتر در مورد فایل secrets.properties
، به فایلهای خصوصیات Gradle مراجعه کنید.
برای سادهسازی این کار، توصیه میکنیم از افزونه Secrets Gradle برای اندروید استفاده کنید.
برای نصب افزونه Secrets Gradle برای اندروید در پروژه Google Maps:
- در Android Studio، فایل
build.gradle.kts
یاbuild.gradle
سطح بالای خود را باز کنید و کد زیر را به عنصرdependencies
در زیرbuildscript
اضافه کنید.
اگر از build.gradle.kts
استفاده می کنید، اضافه کنید:
buildscript {
dependencies {
classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1")
}
}
اگر از build.gradle
استفاده می کنید، اضافه کنید:
buildscript {
dependencies {
classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
}
}
- فایل
build.gradle.kts
یاbuild.gradle
سطح ماژول خود را باز کنید و کد زیر را به عنصرplugins
اضافه کنید.
اگر از build.gradle.kts
استفاده می کنید، اضافه کنید:
plugins {
// ...
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
}
اگر از build.gradle
استفاده می کنید، اضافه کنید:
plugins {
// ...
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
}
- در فایل
build.gradle.kts
یاbuild.gradle
در سطح ماژول، مطمئن شوید کهtargetSdk
وcompileSdk
روی 34 تنظیم شده اند. - فایل را ذخیره کنید و پروژه خود را با Gradle همگام کنید .
- فایل
secrets.properties
را در دایرکتوری سطح بالای خود باز کنید و سپس کد زیر را اضافه کنید. کلید API خود را جایگزینYOUR_API_KEY
کنید. کلید خود را در این فایل ذخیره کنید زیراsecrets.properties
از بررسی سیستم کنترل نسخه حذف شده است.
PLACES_API_KEY=YOUR_API_KEY
- فایل را ذخیره کنید.
- فایل
local.defaults.properties
را در پوشه سطح بالای خود، همان پوشه فایلsecrets.properties
ایجاد کنید و سپس کد زیر را اضافه کنید.
PLACES_API_KEY=DEFAULT_API_KEY
هدف این فایل ارائه یک مکان پشتیبان برای کلید API در صورت یافت نشدن فایل secrets.properties
است تا بیلدها خراب نشوند. اگر برنامه را از یک سیستم کنترل نسخه که secrets.properties
حذف می کند و هنوز فایل secrets.properties
را به صورت محلی برای ارائه کلید API خود ایجاد نکرده اید، ممکن است اتفاق بیفتد.
- فایل را ذخیره کنید.
- در Android Studio، فایل
build.gradle.kts
یاbuild.gradle
در سطح ماژول خود را باز کنید و ویژگیsecrets
را ویرایش کنید. اگر ویژگیsecrets
وجود ندارد، آن را اضافه کنید.
ویژگی های افزونه را ویرایش کنید تا propertiesFileName
روی secrets.properties
تنظیم کنید، defaultPropertiesFileName
را روی local.defaults.properties
تنظیم کنید و هر ویژگی دیگری را تنظیم کنید.
secrets {
// Optionally specify a different file name containing your secrets.
// The plugin defaults to "local.properties"
propertiesFileName = "secrets.properties"
// A properties file containing default secret values. This file can be
// checked in version control.
defaultPropertiesFileName = "local.defaults.properties"
}
5. Places SDK را برای اندروید نصب کنید
در این بخش، Places SDK برای اندروید را به وابستگی های برنامه خود اضافه می کنید.
- اکنون که کلید API شما در داخل برنامه قابل دسترسی است، وابستگی Places SDK for Android را به فایل
build.gradle
برنامه خود اضافه کنید.
فایل build.gradle
در سطح برنامه خود را تغییر دهید تا وابستگی به Places SDK برای Android اضافه شود:
build.gradle در سطح برنامه
dependencies {
// Dependency to include Places SDK for Android
implementation 'com.google.android.libraries.places:places:3.4.0'
}
- برنامه را اجرا کنید.
اکنون باید یک برنامه با صفحه خالی را ببینید. به پر کردن این صفحه با سه نسخه نمایشی ادامه دهید.
6. Places Android KTX را نصب کنید
برای برنامههای Kotlin که از یک یا چند SDK Android پلتفرم نقشههای Google استفاده میکنند، کتابخانههای برنامه افزودنی Kotlin (KTX) به شما امکان میدهند از ویژگیهای زبان Kotlin مانند برنامههای مشترک، ویژگیها/توابع برنامه افزودنی و غیره استفاده کنید. هر Google Maps SDK دارای یک کتابخانه KTX مربوطه است که در زیر نشان داده شده است:
در این کار، از کتابخانه Places Android KTX برای استفاده از ویژگی های زبان مخصوص Kotlin در برنامه خود استفاده کنید.
وابستگی Places Android KTX را اضافه کنید
برای بهرهگیری از ویژگیهای خاص Kotlin، کتابخانه KTX مربوطه را برای این SDK در فایل build.gradle
در سطح برنامه خود قرار دهید.
build.gradle
dependencies {
// ...
// Places SDK for Android KTX Library
implementation 'com.google.maps.android:places-ktx:3.1.1'
}
7. Places Client را راه اندازی کنید
Places SDK را برای محدوده برنامه راه اندازی کنید
در فایل DemoApplication.kt
پوشه app/src/main/java/com/google/codelabs/maps/placesdemo
، Places SDK برای Android را مقداردهی اولیه کنید. خطوط زیر را در انتهای تابع onCreate
قرار دهید:
// Initialize the SDK with the Google Maps Platform API key
Places.initialize(this, BuildConfig.PLACES_API_KEY)
وقتی برنامه خود را میسازید، افزونه Secrets Gradle برای Android، کلید API را در فایل secrets.properties
شما بهعنوان BuildConfig.PLACES_API_KEY
در دسترس قرار میدهد.
فایل برنامه را به مانیفست اضافه کنید
از آنجایی که Application
با DemoApplication
گسترش داده اید، باید مانیفست را به روز کنید. ویژگی android:name
را به عنصر application
در فایل AndroidManifest.xml
، واقع در app/src/main
اضافه کنید:
<application
android:name=".DemoApplication"
...
</application>
این کد مانیفست برنامه را به کلاس DemoApplication
در پوشه src/main/java/com/google/codelabs/maps/placesdemo/
هدایت میکند.
8. واکشی جزئیات مکان
یک صفحه جزئیات ایجاد کنید
یک طرحبندی activity_details.xml
با یک LinearLayout
خالی در پوشه app/src/main/res/layout/
موجود است. طرح خطی را با اضافه کردن کد زیر بین براکت های <LinearLayout>
پر کنید.
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/details_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/details_input_hint"
android:text="@string/details_input_default" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/details_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/button_details" />
<TextView
android:id="@+id/details_response_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:textIsSelectable="true" />
این کد یک فیلد ورودی متن اضافه می کند که در آن کاربر می تواند هر شناسه مکان را وارد کند یا از پیش فرض ارائه شده استفاده کند، یک دکمه برای شروع درخواست جزئیات مکان، و یک TextView برای نمایش اطلاعات از پاسخ. رشته های مرتبط برای شما در فایل src/main/res/values/strings.xml
تعریف شده است.
یک فعالیت Details ایجاد کنید
- یک فایل
DetailsActivity.kt
در پوشهsrc/main/java/com/google/codelabs/maps/placesdemo/
ایجاد کنید و آن را با طرحبندی که ایجاد کردهاید مرتبط کنید. این کد را در فایل قرار دهید:
@ExperimentalCoroutinesApi
class DetailsActivity : AppCompatActivity() {
private lateinit var placesClient: PlacesClient
private lateinit var detailsButton: Button
private lateinit var detailsInput: TextInputEditText
private lateinit var responseView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_details)
// Set up view objects
detailsInput = findViewById(R.id.details_input)
detailsButton = findViewById(R.id.details_button)
responseView = findViewById(R.id.details_response_content)
val apiKey = BuildConfig.PLACES_API_KEY
// Log an error if apiKey is not set.
if (apiKey.isEmpty() || apiKey == "DEFAULT_API_KEY") {
Log.e(TAG, "No api key")
finish()
return
}
}
}
- یک Places Client برای استفاده در این فعالیت ایجاد کنید. این کد را بعد از کد قرار دهید تا کلید API را در تابع
onCreate
بررسی کنید.
// Retrieve a PlacesClient (previously initialized - see DemoApplication)
placesClient = Places.createClient(this)
- پس از تنظیم Places Client، یک کلیک شنونده را به دکمه متصل کنید. این کد را بعد از ایجاد Places Client در تابع
onCreate
قرار دهید.
// Upon button click, fetch and display the Place Details
detailsButton.setOnClickListener { button ->
button.isEnabled = false
val placeId = detailsInput.text.toString()
val placeFields = listOf(
Place.Field.NAME,
Place.Field.ID,
Place.Field.LAT_LNG,
Place.Field.ADDRESS
)
lifecycleScope.launch {
try {
val response = placesClient.awaitFetchPlace(placeId, placeFields)
responseView.text = response.prettyPrint()
} catch (e: Exception) {
e.printStackTrace()
responseView.text = e.message
}
button.isEnabled = true
}
}
این کد شناسه مکانی را که در فیلد ورودی وارد شده است بازیابی میکند، تعیین میکند کدام فیلدها را برای مکان درخواست کند، یک FetchPlaceRequest
ایجاد میکند، کار را آغاز میکند و برای موفقیت یا شکست گوش میدهد. اگر درخواست موفقیت آمیز باشد، تابع TextView را با جزئیات درخواستی پر می کند.
فعالیت جزئیات را به مانیفست اضافه کنید
یک عنصر <activity>
برای DetailsActivity
به عنوان فرزند عنصر <application>
در فایل AndroidManifest.xml
، واقع در app/src/main
اضافه کنید:
<activity android:name=".DetailsActivity" android:label="@string/details_demo_title" />
فعالیت جزئیات را به منوی نمایشی اضافه کنید
یک ماژول Demo
خالی برای فهرست کردن دموهای موجود در صفحه اصلی ارائه شده است. اکنون که یک فعالیت جزئیات مکان ایجاد کردید، آن را با این کد به فایل Demo.kt
در پوشه src/main/java/com/google/codelabs/maps/placesdemo/
اضافه کنید:
DETAILS_FRAGMENT_DEMO(
R.string.details_demo_title,
R.string.details_demo_description,
DetailsActivity::class.java
),
رشته های مرتبط در فایل src/main/res/values/strings.xml
تعریف شده اند.
MainActivity.kt
را بررسی کنید و مشاهده کنید که یک ListView ایجاد می کند که با تکرار در محتویات ماژول Demo
پر می شود. اگر کاربر روی یک مورد در لیست ضربه بزند، شنونده کلیک فعالیت مرتبط را باز می کند.
برنامه را اجرا کنید
- برنامه را اجرا کنید. این بار باید یک مورد را در لیستی که نسخه نمایشی جزئیات مکان را ارائه می دهد، مشاهده کنید.
- روی متن جزئیات مکان ضربه بزنید. شما باید نمایی را که با یک فیلد ورودی و دکمه ایجاد کرده اید ببینید.
- روی دکمه «دریافت جزئیات» ضربه بزنید. اگر از شناسه مکان پیشفرض استفاده کردهاید، باید نام مکان، آدرس و مختصات نقشه را ببینید، همانطور که در شکل 1 نشان داده شده است.
شکل 1. فعالیت جزئیات مکان با نمایش پاسخ.
9. تکمیل خودکار مکان را اضافه کنید
یک صفحه تکمیل خودکار ایجاد کنید
یک طرحبندی activity_autocomplete.xml
با یک LinearLayout
خالی در پوشه app/src/main/res/layout/
ارائه شده است. طرح خطی را با اضافه کردن این کد بین براکت های <LinearLayout>
پر کنید.
<androidx.fragment.app.FragmentContainerView
android:id="@+id/autocomplete_fragment"
android:background="@android:color/white"
android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/autocomplete_response_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:textIsSelectable="true" />
این کد یک ویجت AutocompleteSupportFragment
و یک TextView برای نمایش اطلاعات از پاسخ اضافه می کند. رشته های مرتبط در فایل src/main/res/values/strings.xml
تعریف شده اند.
یک فعالیت تکمیل خودکار ایجاد کنید
- یک فایل
AutocompleteActivity.kt
در پوشهsrc/main/java/com/google/codelabs/maps/placesdemo/
ایجاد کنید و آن را با این کد تعریف کنید:
@ExperimentalCoroutinesApi
class AutocompleteActivity : AppCompatActivity() {
private lateinit var responseView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_autocomplete)
// Set up view objects
responseView = findViewById(R.id.autocomplete_response_content)
val autocompleteFragment =
supportFragmentManager.findFragmentById(R.id.autocomplete_fragment)
as AutocompleteSupportFragment
}
}
این کد فعالیت را با view ها و AutocompleteSupportFramgent
که در فایل طرح بندی تعریف کرده اید مرتبط می کند.
- در مرحله بعد، مشخص کنید وقتی کاربر یکی از پیش بینی های ارائه شده توسط Place Autocomplete را انتخاب می کند چه اتفاقی می افتد. این کد را به انتهای تابع
onCreate
اضافه کنید:
val placeFields: List<Place.Field> =
listOf(Place.Field.NAME, Place.Field.ID, Place.Field.ADDRESS, Place.Field.LAT_LNG)
autocompleteFragment.setPlaceFields(placeFields)
// Listen to place selection events
lifecycleScope.launchWhenCreated {
autocompleteFragment.placeSelectionEvents().collect { event ->
when (event) {
is PlaceSelectionSuccess -> {
val place = event.place
responseView.text = prettyPrintAutocompleteWidget(place, false)
}
is PlaceSelectionError -> Toast.makeText(
this@AutocompleteActivity,
"Failed to get place '${event.status.statusMessage}'",
Toast.LENGTH_SHORT
).show()
}
}
}
این کد مشخص می کند که کدام فیلدها را برای مکان درخواست کند، به رویداد انتخاب مکان گوش می دهد و برای موفقیت یا شکست گوش می دهد. اگر درخواست موفقیت آمیز باشد، تابع TextView را با جزئیات مکان پر می کند. توجه داشته باشید که Place Autocomplete یک شی Place را برمی گرداند. هنگام استفاده از ویجت تکمیل خودکار مکان، نیازی به درخواست جداگانه جزئیات مکان نیست.
فعالیت تکمیل خودکار را به مانیفست اضافه کنید
یک عنصر <activity>
برای AutocompleteActivity
به عنوان فرزند عنصر <application>
در فایل AndroidManifest.xml
، واقع در app/src/main
اضافه کنید:
<activity android:name=".AutocompleteActivity" android:label="@string/autocomplete_fragment_demo_title" />
فعالیت تکمیل خودکار را به منوی نمایشی اضافه کنید
مانند قبل، نسخه ی نمایشی تکمیل خودکار مکان را با اضافه کردن آن به لیست در ماژول Demo
، به صفحه اصلی اضافه کنید. اکنون که یک فعالیت تکمیل خودکار مکان ایجاد کرده اید، آن را به فایل Demo.kt
در پوشه src/main/java/com/google/codelabs/maps/placesdemo/
اضافه کنید. این کد را بلافاصله بعد از مورد DETAILS_FRAGMENT_DEMO
جایگذاری کنید:
AUTOCOMPLETE_FRAGMENT_DEMO(
R.string.autocomplete_fragment_demo_title,
R.string.autocomplete_fragment_demo_description,
AutocompleteActivity::class.java
),
رشته های مرتبط در فایل src/main/res/values/strings.xml
تعریف شده اند.
برنامه را اجرا کنید
- برنامه را اجرا کنید. این بار باید دو مورد را در لیست صفحه اصلی مشاهده کنید.
- روی ردیف تکمیل خودکار مکان ضربه بزنید. همانطور که در شکل 2 نشان داده شده است، باید یک ورودی تکمیل خودکار مکان ظاهر شود.
- شروع به تایپ نام یک مکان کنید. این می تواند نام مؤسسه، آدرس یا منطقه جغرافیایی باشد. پیشبینیها باید همانطور که تایپ میکنید ارائه شوند.
- یکی از پیش بینی ها را انتخاب کنید. پیش بینی ها باید ناپدید شوند و TextView اکنون باید جزئیات مکان انتخاب شده را همانطور که در شکل 3 نشان داده شده است نشان دهد.
شکل 2. تکمیل خودکار فعالیت پس از ضربه زدن کاربر به قسمت ورودی.
شکل 3. تکمیل خودکار فعالیت، نمایش جزئیات مکان پس از تایپ و انتخاب "آبشار نیاگارا" توسط کاربر.
10. مکان فعلی دستگاه را دریافت کنید
یک صفحه مکان فعلی ایجاد کنید
یک طرحبندی activity_current.xml
با یک LinearLayout
خالی در پوشه app/src/main/res/layout/
ارائه شده است. طرح خطی را با اضافه کردن کد زیر در بین براکتهای <LinearLayout>
پر کنید.
<Button
android:id="@+id/current_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/current_button" />
<TextView
android:id="@+id/current_response_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:scrollbars = "vertical"
android:textIsSelectable="true" />
یک فعالیت مکان فعلی ایجاد کنید
- یک فایل
CurrentPlaceActivity.kt
در پوشهsrc/main/java/com/google/codelabs/maps/placesdemo/
ایجاد کنید و آن را با این کد تعریف کنید:
@ExperimentalCoroutinesApi
class CurrentPlaceActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var placesClient: PlacesClient
private lateinit var currentButton: Button
private lateinit var responseView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_current)
// Retrieve a PlacesClient (previously initialized - see DemoApplication)
placesClient = Places.createClient(this)
// Set view objects
currentButton = findViewById(R.id.current_button)
responseView = findViewById(R.id.current_response_content)
// Set listener for initiating Current Place
currentButton.setOnClickListener {
checkPermissionThenFindCurrentPlace()
}
}
}
این کد فعالیت را با نماهایی که در فایل layout تعریف کرده اید مرتبط می کند. همچنین یک کلیک شنونده به دکمه اضافه می کند تا با کلیک روی دکمه، تابع checkPermissionThenFindCurrentPlace
فراخوانی کند.
-
checkPermissionThenFindCurrentPlace()
برای بررسی مجوز مکان دقیق و درخواست مجوز در صورتی که هنوز اعطا نشده است را تعریف کنید. این کد را بعد از تابعonCreate
قرار دهید.
/**
* Checks that the user has granted permission for fine or coarse location.
* If granted, finds current Place.
* If not yet granted, launches the permission request.
* See https://developer.android.com/training/permissions/requesting
*/
private fun checkPermissionThenFindCurrentPlace() {
when {
(ContextCompat.checkSelfPermission(
this,
ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
this,
ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED) -> {
// You can use the API that requires the permission.
findCurrentPlace()
}
shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)
-> {
Log.d(TAG, "Showing permission rationale dialog")
// TODO: In an educational UI, explain to the user why your app requires this
// permission for a specific feature to behave as expected. In this UI,
// include a "cancel" or "no thanks" button that allows the user to
// continue using your app without granting the permission.
}
else -> {
// Ask for both the ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions.
ActivityCompat.requestPermissions(
this,
arrayOf(
ACCESS_FINE_LOCATION,
ACCESS_COARSE_LOCATION
),
PERMISSION_REQUEST_CODE
)
}
}
}
companion object {
private const val TAG = "CurrentPlaceActivity"
private const val PERMISSION_REQUEST_CODE = 9
}
- هنگامی که شاخه
else
تابعcheckPermissionThenFindCurrentPlace
requestPermissions
فرا می خواند، برنامه یک گفتگوی درخواست مجوز را به کاربر ارائه می دهد. اگر کاربر از دستگاهی استفاده میکند که دارای سیستمعامل پایینتر از Android 12 است، کاربر فقط میتواند مجوز مکان دقیق (خوب) بدهد. اگر کاربر از دستگاهی با اندروید 12 یا بالاتر استفاده می کند، همانطور که در شکل 4 نشان داده شده است، این گزینه به او داده می شود که مکان تقریبی (درشت) را به جای مکان دقیق (دقیق) ارائه دهد.
شکل 4. درخواست مجوز کاربر در دستگاهی که دارای Android 12 یا بالاتر است، گزینه ای برای اعطای مکان دقیق یا تقریبی ارائه می دهد.
پس از پاسخ کاربر به گفتگوی مجوزهای سیستم، سیستم سپس اجرای برنامه شما از onRequestPermissionsResult
را فراخوانی می کند. سیستم در پاسخ کاربر به گفتگوی مجوز و همچنین کد درخواستی که شما تعریف کرده اید ارسال می کند. onRequestPermissionResult
لغو کنید تا با قرار دادن کد زیر در زیر checkPermissionThenFindCurrentPlace
، کد درخواست مجوزهای مکان مربوط به این فعالیت مکان فعلی را کنترل کنید.
@SuppressLint("MissingPermission")
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>, grantResults: IntArray
) {
if (requestCode != PERMISSION_REQUEST_CODE) {
super.onRequestPermissionsResult(
requestCode,
permissions,
grantResults
)
return
} else if (
permissions.toList().zip(grantResults.toList())
.firstOrNull { (permission, grantResult) ->
grantResult == PackageManager.PERMISSION_GRANTED && (permission == ACCESS_FINE_LOCATION || permission == ACCESS_COARSE_LOCATION)
} != null
)
// At least one location permission has been granted, so proceed with Find Current Place
findCurrentPlace()
}
- پس از اعطای مجوز، تابع
findCurrentPlace
اجرا خواهد شد. تابع را با این کد بعد از تابعonRequestPermissionsResult
تعریف کنید.
/**
* Fetches a list of [PlaceLikelihood] instances that represent the Places the user is
* most likely to be at currently.
*/
@RequiresPermission(anyOf = [ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION])
private fun findCurrentPlace() {
// Use fields to define the data types to return.
val placeFields: List<Place.Field> =
listOf(Place.Field.NAME, Place.Field.ID, Place.Field.ADDRESS, Place.Field.LAT_LNG)
// Call findCurrentPlace and handle the response (first check that the user has granted permission).
if (ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
) {
// Retrieve likely places based on the device's current location
currentButton.isEnabled = false
lifecycleScope.launch {
val response = placesClient.awaitFindCurrentPlace(placeFields)
responseView.text = response.prettyPrint()
// Enable scrolling on the long list of likely places
val movementMethod = ScrollingMovementMethod()
responseView.movementMethod = movementMethod
}
} else {
Log.d(TAG, "LOCATION permission not granted")
checkPermissionThenFindCurrentPlace()
}
}
این کد تعیین می کند که کدام فیلدها برای مکان های احتمالی درخواست شود، یک FindCurrentPlaceRequest
ایجاد می کند، کار را آغاز می کند، و TextView را با جزئیات درخواستی پر می کند.
فعالیت Current Place را به مانیفست اضافه کنید
یک عنصر <activity>
برای CurrentPlaceActivity
به عنوان فرزند عنصر <application>
در فایل AndroidManifest.xml
، واقع در app/src/main
اضافه کنید:
<activity android:name=".CurrentPlaceActivity" android:label="@string/current_demo_title" />
فعالیت Current Place را به منوی نمایشی اضافه کنید
دقیقاً مانند قبل، نسخه نمایشی Current Place را با افزودن آن به لیست در ماژول Demo
به صفحه اصلی اضافه کنید. اکنون که یک فعالیت Current Place ایجاد کرده اید، آن را به فایل Demo.kt
در پوشه src/main/java/com/google/codelabs/maps/placesdemo/
اضافه کنید. این کد را بلافاصله بعد از مورد AUTOCOMPLETE_FRAGMENT_DEMO
جایگذاری کنید:
CURRENT_FRAGMENT_DEMO(
R.string.current_demo_title,
R.string.current_demo_description,
CurrentPlaceActivity::class.java
),
رشته های مرتبط در فایل src/main/res/values/strings.xml
تعریف شده اند.
برنامه را اجرا کنید
- برنامه را اجرا کنید. این بار باید سه مورد را در لیست صفحه اصلی مشاهده کنید.
- روی ردیف مکان فعلی ضربه بزنید. باید دکمه ای را روی صفحه ببینید.
- روی دکمه ضربه بزنید. اگر قبلاً مجوز مکان را به این برنامه ندادهاید، یک درخواست مجوز باید ظاهر شود.
- به برنامه اجازه دسترسی به موقعیت مکانی دستگاه بدهید.
- دوباره روی دکمه ضربه بزنید. این بار، همانطور که در شکل 5 نشان داده شده است، فهرستی از حداکثر 20 مکان نزدیک و احتمالات آنها باید ظاهر شود.
شکل 5. ارائه منطبقات احتمالی مکان فعلی برای مکان گزارش شده دستگاه.
11. مکان فعلی را روی نقشه نمایش دهید
وابستگی Map را اضافه کنید
در فایل build.gradle
در سطح ماژول خود، وابستگی خدمات Google Play را برای Maps SDK برای Android اضافه کنید.
app/build.gradle
dependencies {
// ...
implementation 'com.google.android.gms:play-services-maps:18.2.0'
}
مانیفست اندروید را برای حساب نقشه ها به روز کنید
عناصر meta-data
زیر را در عنصر application
اضافه کنید.
اینها نسخه خدمات Google Play را که برنامه با آن کامپایل شده است جاسازی می کند و کلید API شما را مشخص می کند.
AndroidManifest.xml
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}" />
کلید api را به secrets.properties
اضافه کنید
فایل secrets.properties
را در دایرکتوری سطح بالای خود باز کنید و سپس کد زیر را اضافه کنید. کلید API خود را جایگزین YOUR_API_KEY
کنید.
MAPS_API_KEY=YOUR_API_KEY
فایل local.defaults.properties
را در پوشه سطح بالای خود باز کنید، همان پوشه فایل secrets.properties
، و سپس کد زیر را اضافه کنید.
MAPS_API_KEY=DEFAULT_API_KEY
کلید api را بررسی کنید
در onCreate()
برنامه کلید API maps را بررسی می کند و قطعه پشتیبانی نقشه ها را مقداردهی اولیه می کند. getMapAsync()
برای ثبت نام برای بازگشت به تماس نقشه استفاده می شود.
برای این کار کد زیر را اضافه کنید.
CurrentPlaceActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_current)
val apiKey = BuildConfig.MAPS_API_KEY
// Log an error if apiKey is not set.
if (apiKey.isEmpty() || apiKey == "DEFAULT_API_KEY") {
Log.e("Places test", "No api key")
finish()
return
}
// Retrieve a PlacesClient (previously initialized - see DemoApplication)
placesClient = Places.createClient(this)
(supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment?)?.getMapAsync(this)
// ...
}
طرح بندی نقشه را ایجاد کنید
- در پوشه
app/src/main/res/layout/
، فایل layoutfragment_map.xml
را ایجاد کنید و طرح را با کد زیر پر کنید.
res/layout/fragment_map.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.google.codelabs.maps.placesdemo.CurrentPlaceActivity" />
این یک SupportMapFragment
تعریف می کند تا به عنوان یک محفظه برای نقشه عمل کند و دسترسی به شی GoogleMap
را فراهم کند.
- در طرحبندی
activity_current.xml
موجود در پوشهapp/src/main/res/layout/
، کد زیر را به پایین طرحبندی خطی اضافه کنید.
res/layout/activity_current.xml
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:text="@string/showing_most_likely_place"
style="@style/TextAppearance.AppCompat.Title"/>
<include layout="@layout/fragment_map"/>
TextView
اضافه شده به یک منبع رشته جدیدی اشاره می کند که باید ایجاد شود.
- در
app/src/main/res/values/strings.xml
، منبع رشته زیر را اضافه کنید.
res/values/strings.xml
<string name="showing_most_likely_place">Showing most likely place</string>
از آنجایی که نماهای اضافی برای نقشه اضافه شده است، TextView
که لیست مکان ها را نمایش می دهد باید ارتفاع خود را تنظیم کند تا این نماها قابل مشاهده باشند.
- ویژگی
maxHeight
را بهTextView
با شناسهcurrent_response_content
اضافه کنید
res/layout/activity_current.xml
android:maxHeight="200dp"
OnMapReadyCallback
پیاده سازی کنید
رابط OnMapReadyCallback
را با افزودن آن به اعلان کلاس پیادهسازی کنید و متد onMapReady()
برای تنظیم نقشه زمانی که شی GoogleMap
در دسترس است، لغو کنید:
CurrentPlaceActivity.kt
class CurrentPlaceActivity : AppCompatActivity(), OnMapReadyCallback {
در پایان کلاس کد زیر را اضافه کنید:
CurrentPlaceActivity.kt
override fun onMapReady(map: GoogleMap) {
this.map = map
lastKnownLocation?.let { location ->
map.moveCamera(
CameraUpdateFactory.newLatLngZoom(
location,
DEFAULT_ZOOM
)
)
}
}
تماس برگشتی به برخی از متغیرهای کلاس نیاز دارد تا به درستی کار کنند. بلافاصله بعد از هدر کلاس، موارد زیر را اضافه کنید:
CurrentPlaceActivity.kt
private var map: GoogleMap? = null
private var lastKnownLocation: LatLng? = null
کد زیر را به شی کلاس companion اضافه کنید:
CurrentPlaceActivity.kt
private const val DEFAULT_ZOOM = 15f
برنامه را اجرا کنید
- برنامه را اجرا کنید.
- روی ردیف مکان فعلی ضربه بزنید. باید دکمه ای را روی صفحه ببینید.
- روی دکمه ضربه بزنید. اگر قبلاً مجوز مکان را به این برنامه ندادهاید، یک درخواست مجوز باید ظاهر شود.
- به برنامه اجازه دسترسی به موقعیت مکانی دستگاه بدهید.
- دوباره روی دکمه ضربه بزنید. نقشه نمایش داده خواهد شد.
شکل 6. فعالیت مکان فعلی که نقشه را نشان می دهد.
نقشه را با یک مکان به روز کنید
در پایان کلاس کد زیر را اضافه کنید:
CurrentPlaceActivity.kt
private data class LikelyPlace(
val name: String,
val address: String,
val attribution: List<String>,
val latLng: LatLng
)
private fun PlaceLikelihood.toLikelyPlace(): LikelyPlace? {
val name = this.place.name
val address = this.place.address
val latLng = this.place.latLng
val attributions = this.place.attributions ?: emptyList()
return if (name != null && address != null && latLng != null) {
LikelyPlace(name, address, attributions, latLng)
} else {
null
}
}
اینها برای ذخیره داده های Place و قالب بندی آن استفاده می شود.
در ابتدای کلاس، کد زیر را برای ایجاد متغیری که برای ذخیره داده های Place برگشتی استفاده می شود، اضافه کنید.
CurrentPlaceActivity.kt
private val likelyPlaces = mutableListOf<LikelyPlace>()
در این مرحله، کد تغییر می کند، بنابراین لیستی از مکان ها به کاربر نمایش داده می شود و آنها یکی را برای نمایش روی نقشه انتخاب می کنند. همه دادههای Places در فهرستی روی صفحه نمایش داده میشوند.
در تابع findCurrentPlace
، در بلوک lifecycleScope.launch
قبل از این خط کد
CurrentPlaceActivity.kt
responseView.text = response.prettyPrint()
کد زیر را اضافه کنید:
CurrentPlaceActivity.kt
likelyPlaces.clear()
likelyPlaces.addAll(
response.placeLikelihoods.take(M_MAX_ENTRIES).mapNotNull { placeLikelihood ->
placeLikelihood.toLikelyPlace()
}
)
openPlacesDialog()
این کد به یک ثابت برای نمایش حداکثر تعداد مکان نیاز دارد.
در شیء همراه، کد آن ثابت را اضافه کنید.
CurrentPlaceActivity.kt
private const val M_MAX_ENTRIES = 5
کد زیر را اضافه کنید که گفتگویی را ایجاد می کند که به کاربر اجازه می دهد مکان را انتخاب کند.
CurrentPlaceActivity.kt
/**
* Displays a form allowing the user to select a place from a list of likely places.
*/
private fun openPlacesDialog() {
// Ask the user to choose the place where they are now.
val listener =
DialogInterface.OnClickListener { _, which -> // The "which" argument contains the position of the selected item.
val likelyPlace = likelyPlaces[which]
lastKnownLocation = likelyPlace.latLng
val snippet = buildString {
append(likelyPlace.address)
if (likelyPlace.attribution.isNotEmpty()) {
append("\n")
append(likelyPlace.attribution.joinToString(", "))
}
}
val place = Place.builder().apply {
name = likelyPlace.name
latLng = likelyPlace.latLng
}.build()
map?.clear()
setPlaceOnMap(place, snippet)
}
// Display the dialog.
AlertDialog.Builder(this)
.setTitle(R.string.pick_place)
.setItems(likelyPlaces.map { it.name }.toTypedArray(), listener)
.setOnDismissListener {
currentButton.isEnabled = true
}
.show()
}
با پیروی از بهترین شیوه های Android، گفتگو به منبع رشته ای اشاره می کند که باید به فایل منبع strings.xml
واقع در پوشه app/src/main/res/values/
اضافه شود.
موارد زیر را به strings.xml
اضافه کنید:
res/values/strings.xml
<string name="pick_place">Choose a place</string>
سپس این توابع تابع setPlaceOnMap
را فراخوانی می کنند که دوربین را حرکت می دهد و یک نشانگر را در محل انتخاب شده قرار می دهد.
کد زیر را اضافه کنید:
CurrentPlaceActivity.kt
private fun setPlaceOnMap(place: Place?, markerSnippet: String?) {
val latLng = place?.latLng ?: defaultLocation
map?.moveCamera(
CameraUpdateFactory.newLatLngZoom(
latLng,
DEFAULT_ZOOM
)
)
map?.addMarker(
MarkerOptions()
.position(latLng)
.title(place?.name)
.snippet(markerSnippet)
)
}
همچنین توصیه می شود وضعیت نقشه ها را ذخیره و بازیابی کنید.
برای ذخیره وضعیت آن، تابع onSaveInstanceState
را لغو کنید و کد زیر را اضافه کنید:
CurrentPlaceActivity.kt
/**
* Saves the state of the map when the activity is paused.
*/
override fun onSaveInstanceState(outState: Bundle) {
outState.putParcelable(KEY_LOCATION, lastKnownLocation)
super.onSaveInstanceState(outState)
}
برای بازیابی حالت آن، در onCreate
پس از تماس با setContentView
کد زیر را اضافه کنید:
CurrentPlaceActivity.kt
if (savedInstanceState != null) {
lastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION)
}
ذخیره و بازیابی به یک کلید نیاز دارد، این یک ثابت از شی همراه است.
در بلوک شیء همراه، موارد زیر را اضافه کنید:
CurrentPlaceActivity.kt
// Key for storing activity state.
private const val KEY_LOCATION = "location"
برنامه را اجرا کنید
- برنامه را اجرا کنید.
- روی ردیف مکان فعلی ضربه بزنید. باید دکمه ای را روی صفحه ببینید.
- روی دکمه ضربه بزنید. اگر قبلاً مجوز مکان را به این برنامه ندادهاید، یک درخواست مجوز باید ظاهر شود.
- به برنامه اجازه دسترسی به موقعیت مکانی دستگاه بدهید.
- دوباره روی دکمه ضربه بزنید.
- با ضربه زدن روی آن مکان را انتخاب کنید. نقشه بزرگنمایی میشود و با نشانگری که در مکان انتخابی قرار میگیرد، در مرکز قرار میگیرد.
شکل 7. نقشه با نشانگر در محل انتخاب شده.
12. تبریک می گویم
شما با موفقیت برنامه Android را با Places SDK برای Android ساخته اید.
چیزی که یاد گرفتی
- نصب و پیکربندی Places SDK برای اندروید.
- نصب برنامه های افزودنی Kotlin برای Places SDK برای اندروید.
- در حال بارگیری جزئیات مکان
- افزودن تکمیل خودکار مکان
- بدست آوردن مکان فعلی
بعدش چی؟
- برای الهام بیشتر، مخزن
android-places-demos
GitHub از نمونهها و دموها را کاوش یا جدا کنید. - از کدهای Kotlin بیشتر برای ساخت برنامه های اندروید با پلتفرم نقشه های گوگل بیاموزید.
- با پاسخ دادن به سوال زیر به ما کمک کنید محتوایی را ایجاد کنیم که برای شما مفیدتر باشد:
دوست دارید چه کدهای دیگری را ببینید؟
آیا کد لبه مورد نظر شما در لیست نیست؟ آن را با یک شماره جدید در اینجا درخواست کنید .