یکی از ویژگیهای منحصر به فرد برنامههای تلفن همراه، آگاهی از موقعیت مکانی است. کاربران تلفن همراه دستگاههای خود را همه جا با خود میبرند و افزودن آگاهی از موقعیت مکانی به برنامه شما، تجربهای زمینهایتر را برای کاربران فراهم میکند.
نمونههای کد
مخزن ApiDemos در گیتهاب شامل نمونههایی است که کاربرد مکان روی نقشه را نشان میدهند:
کاتلین
- MyLocationDemoActivity : استفاده از لایه My Location ، شامل مجوزهای زمان اجرا
- LocationSourceDemoActivity : استفاده از یک
LocationSourceسفارشی - CurrentPlaceDetailsOnMap : پیدا کردن مکان فعلی یک دستگاه اندروید و نمایش جزئیات مکان (تجارت یا سایر نقاط مورد علاقه) در آن مکان. به آموزش نمایش جزئیات مکان فعلی روی نقشه مراجعه کنید.
جاوا
- MyLocationDemoActivity : استفاده از لایه My Location ، شامل مجوزهای زمان اجرا
- LocationSourceDemoActivity : استفاده از یک
LocationSourceسفارشی - CurrentPlaceDetailsOnMap : پیدا کردن مکان فعلی یک دستگاه اندروید و نمایش جزئیات مکان (تجارت یا سایر نقاط مورد علاقه) در آن مکان. به آموزش نمایش جزئیات مکان فعلی روی نقشه مراجعه کنید.
کار با دادههای مکانی
دادههای مکانی موجود برای یک دستگاه اندروید شامل مکان فعلی دستگاه - که با استفاده از ترکیبی از فناوریها مشخص شده است - جهت و روش حرکت، و اینکه آیا دستگاه از یک مرز جغرافیایی از پیش تعریف شده یا geofence عبور کرده است یا خیر، میشود. بسته به نیازهای برنامه شما، میتوانید از بین چندین روش کار با دادههای مکانی انتخاب کنید:
- لایه «موقعیت مکانی من» روشی ساده برای نمایش موقعیت مکانی دستگاه روی نقشه ارائه میدهد. این لایه دادهای ارائه نمیدهد.
- API موقعیت مکانی سرویسهای گوگل پلی برای همه درخواستهای برنامهریزیشده برای دادههای موقعیت مکانی توصیه میشود.
- رابط
LocationSourceبه شما امکان میدهد یک ارائهدهنده موقعیت مکانی سفارشی ارائه دهید.
مجوزهای موقعیت مکانی
اگر برنامه شما نیاز به دسترسی به موقعیت مکانی کاربر دارد، باید با اضافه کردن مجوزهای موقعیت مکانی اندروید مربوطه به برنامه خود، درخواست مجوز کنید.
اندروید دو مجوز مکان ارائه میدهد: ACCESS_COARSE_LOCATION و ACCESS_FINE_LOCATION . مجوزی که انتخاب میکنید، دقت مکان برگردانده شده توسط API را تعیین میکند.
-
android.permission.ACCESS_COARSE_LOCATION– به API اجازه میدهد تا موقعیت مکانی تقریبی دستگاه را برگرداند. این مجوز، تخمینی از موقعیت مکانی دستگاه را از سرویسهای موقعیت مکانی ارائه میدهد، همانطور که در مستندات مربوط به دقت تقریبی موقعیت مکانی توضیح داده شده است. -
android.permission.ACCESS_FINE_LOCATION– به API اجازه میدهد تا با استفاده از ارائهدهندگان موقعیت مکانی موجود، از جمله سیستم موقعیتیابی جهانی (GPS) و همچنین وایفای و دادههای تلفن همراه، تا حد امکان یک مکان دقیق را تعیین کند.
اضافه کردن دسترسیها به مانیفست برنامه
اگر فقط برای عملکرد برنامه شما به موقعیت مکانی تقریبی نیاز است، مجوز ACCESS_COARSE_LOCATION را به فایل مانیفست برنامه خود اضافه کنید:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp" > ... <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> ... </manifest>
با این حال، اگر به مکان دقیق نیاز دارید، مجوزهای ACCESS_COARSE_LOCATION و ACCESS_FINE_LOCATION را به فایل مانیفست برنامه خود اضافه کنید:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp" > ... <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> ... </manifest>
درخواست مجوزهای زمان اجرا
اندروید ۶.۰ (مارشمالو) مدل جدیدی برای مدیریت مجوزها معرفی میکند که فرآیند نصب و ارتقاء برنامهها را برای کاربران سادهتر میکند. اگر برنامه شما سطح API 23 یا بالاتر را هدف قرار داده است، میتوانید از مدل جدید مجوزها استفاده کنید.
اگر برنامه شما از مدل جدید مجوزها پشتیبانی میکند و دستگاه شما اندروید ۶.۰ (مارشمالو) یا بالاتر را اجرا میکند، کاربر هنگام نصب یا ارتقاء برنامه نیازی به اعطای هیچ مجوزی ندارد. برنامه باید در زمان اجرا بررسی کند که آیا مجوز لازم را دارد یا خیر، و در صورت نداشتن مجوز، درخواست مجوز کند. سیستم یک کادر محاورهای به کاربر نمایش میدهد و درخواست مجوز میکند.
برای بهترین تجربه کاربری، درخواست مجوز در متن برنامه بسیار مهم است. اگر موقعیت مکانی برای عملکرد برنامه شما ضروری است، باید در هنگام راهاندازی برنامه درخواست مجوز موقعیت مکانی را بدهید. یک راه خوب برای انجام این کار، استفاده از یک صفحه خوشامدگویی گرم یا یک راهنما است که به کاربران در مورد دلیل نیاز به مجوز آموزش میدهد.
اگر برنامه فقط برای بخشی از عملکردهای خود به مجوز نیاز دارد، باید مجوز موقعیت مکانی را در زمانی که برنامه عملی را که نیاز به مجوز دارد انجام میدهد، درخواست کنید.
برنامه باید به شکلی مناسب، مواردی را که کاربر اجازه نمیدهد، مدیریت کند. برای مثال، اگر مجوز برای یک ویژگی خاص مورد نیاز باشد، برنامه میتواند آن ویژگی را غیرفعال کند. اگر مجوز برای عملکرد برنامه ضروری باشد، برنامه میتواند تمام عملکردهای آن را غیرفعال کند و به کاربر اطلاع دهد که باید مجوز را اعطا کند.
نمونه کد زیر قبل از فعال کردن لایه My Location، با استفاده از کتابخانه AndroidX، مجوزها را بررسی میکند. سپس با پیادهسازی ActivityCompat.OnRequestPermissionsResultCallback از کتابخانه Support، نتیجه درخواست مجوز را مدیریت میکند:
کاتلین
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.example.kotlindemos import android.Manifest import android.annotation.SuppressLint import android.content.pm.PackageManager import android.location.Location import android.os.Bundle import android.view.View import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback import androidx.core.content.ContextCompat import com.example.common_ui.R import com.example.kotlindemos.PermissionUtils.PermissionDeniedDialog.Companion.newInstance import com.example.kotlindemos.PermissionUtils.isPermissionGranted import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener import com.google.android.gms.maps.GoogleMap.OnMyLocationClickListener import com.google.android.gms.maps.OnMapReadyCallback import com.google.android.gms.maps.SupportMapFragment /** * This demo shows how GMS Location can be used to check for changes to the users location. The * "My Location" button uses GMS Location to set the blue dot representing the users location. * Permission for [Manifest.permission.ACCESS_FINE_LOCATION] and [Manifest.permission.ACCESS_COARSE_LOCATION] * are requested at run time. If either permission is not granted, the Activity is finished with an error message. */ class MyLocationDemoActivity : SamplesBaseActivity(), OnMyLocationButtonClickListener, OnMyLocationClickListener, OnMapReadyCallback, OnRequestPermissionsResultCallback { /** * Flag indicating whether a requested permission has been denied after returning in * [.onRequestPermissionsResult]. */ private var permissionDenied = false private lateinit var map: GoogleMap override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.my_location_demo) val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment? mapFragment?.getMapAsync(this) applyInsets(findViewById<View?>(R.id.map_container)) } override fun onMapReady(googleMap: GoogleMap) { map = googleMap googleMap.setOnMyLocationButtonClickListener(this) googleMap.setOnMyLocationClickListener(this) enableMyLocation() } /** * Enables the My Location layer if the fine location permission has been granted. */ @SuppressLint("MissingPermission") private fun enableMyLocation() { // 1. Check if permissions are granted, if so, enable the my location layer if (ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { map.isMyLocationEnabled = true return } // 2. If if a permission rationale dialog should be shown if (ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_FINE_LOCATION ) || ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_COARSE_LOCATION ) ) { PermissionUtils.RationaleDialog.newInstance( LOCATION_PERMISSION_REQUEST_CODE, true ).show(supportFragmentManager, "dialog") return } // 3. Otherwise, request permission ActivityCompat.requestPermissions( this, arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION ), LOCATION_PERMISSION_REQUEST_CODE ) } override fun onMyLocationButtonClick(): Boolean { Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT) .show() // Return false so that we don't consume the event and the default behavior still occurs // (the camera animates to the user's current position). return false } override fun onMyLocationClick(location: Location) { Toast.makeText(this, "Current location:\n$location", Toast.LENGTH_LONG) .show() } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray ) { if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) { super.onRequestPermissionsResult( requestCode, permissions, grantResults ) return } if (isPermissionGranted( permissions, grantResults, Manifest.permission.ACCESS_FINE_LOCATION ) || isPermissionGranted( permissions, grantResults, Manifest.permission.ACCESS_COARSE_LOCATION ) ) { // Enable the my location layer if the permission has been granted. enableMyLocation() } else { // Permission was denied. Display an error message // Display the missing permission error dialog when the fragments resume. permissionDenied = true } } override fun onResumeFragments() { super.onResumeFragments() if (permissionDenied) { // Permission was not granted, display error dialog. showMissingPermissionError() permissionDenied = false } } /** * Displays a dialog with error message explaining that the location permission is missing. */ private fun showMissingPermissionError() { newInstance(true).show(supportFragmentManager, "dialog") } companion object { /** * Request code for location permission request. * * @see .onRequestPermissionsResult */ private const val LOCATION_PERMISSION_REQUEST_CODE = 1 } }
جاوا
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.example.mapdemo; import android.Manifest.permission; import android.annotation.SuppressLint; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener; import com.google.android.gms.maps.GoogleMap.OnMyLocationClickListener; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import android.Manifest; import android.content.pm.PackageManager; import android.location.Location; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.widget.Toast; /** * This demo shows how GMS Location can be used to check for changes to the users location. The "My * Location" button uses GMS Location to set the blue dot representing the users location. * Permission for {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and {@link * android.Manifest.permission#ACCESS_COARSE_LOCATION} are requested at run time. If either * permission is not granted, the Activity is finished with an error message. */ public class MyLocationDemoActivity extends SamplesBaseActivity implements OnMyLocationButtonClickListener, OnMyLocationClickListener, OnMapReadyCallback, ActivityCompat.OnRequestPermissionsResultCallback { /** * Request code for location permission request. * * @see #onRequestPermissionsResult(int, String[], int[]) */ private static final int LOCATION_PERMISSION_REQUEST_CODE = 1; /** * Flag indicating whether a requested permission has been denied after returning in {@link * #onRequestPermissionsResult(int, String[], int[])}. */ private boolean permissionDenied = false; private GoogleMap map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(com.example.common_ui.R.layout.my_location_demo); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(com.example.common_ui.R.id.map); mapFragment.getMapAsync(this); applyInsets(findViewById(com.example.common_ui.R.id.map_container)); } @Override public void onMapReady(@NonNull GoogleMap googleMap) { map = googleMap; map.setOnMyLocationButtonClickListener(this); map.setOnMyLocationClickListener(this); enableMyLocation(); } /** * Enables the My Location layer if the fine location permission has been granted. */ @SuppressLint("MissingPermission") private void enableMyLocation() { // 1. Check if permissions are granted, if so, enable the my location layer if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { map.setMyLocationEnabled(true); return; } // 2. Otherwise, request location permissions from the user. PermissionUtils.requestLocationPermissions(this, LOCATION_PERMISSION_REQUEST_CODE, true); } @Override public boolean onMyLocationButtonClick() { Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT).show(); // Return false so that we don't consume the event and the default behavior still occurs // (the camera animates to the user's current position). return false; } @Override public void onMyLocationClick(@NonNull Location location) { Toast.makeText(this, "Current location:\n" + location, Toast.LENGTH_LONG).show(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); return; } if (PermissionUtils.isPermissionGranted(permissions, grantResults, Manifest.permission.ACCESS_FINE_LOCATION) || PermissionUtils .isPermissionGranted(permissions, grantResults, Manifest.permission.ACCESS_COARSE_LOCATION)) { // Enable the my location layer if the permission has been granted. enableMyLocation(); } else { // Permission was denied. Display an error message // Display the missing permission error dialog when the fragments resume. permissionDenied = true; } } @Override protected void onResumeFragments() { super.onResumeFragments(); if (permissionDenied) { // Permission was not granted, display error dialog. showMissingPermissionError(); permissionDenied = false; } } /** * Displays a dialog with error message explaining that the location permission is missing. */ private void showMissingPermissionError() { PermissionUtils.PermissionDeniedDialog .newInstance(true).show(getSupportFragmentManager(), "dialog"); } }
لایه مکان من
شما میتوانید از لایه «موقعیت مکانی من» و دکمه «موقعیت مکانی من» برای نمایش موقعیت فعلی کاربر روی نقشه استفاده کنید. برای فعال کردن لایه «موقعیت مکانی من» روی نقشه، تابع mMap.setMyLocationEnabled() را فراخوانی کنید.
مثال زیر یک کاربرد ساده از لایه «موقعیت مکانی من» را نشان میدهد:
کاتلین
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.maps.example.kotlin import android.annotation.SuppressLint import android.location.Location import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener import com.google.android.gms.maps.GoogleMap.OnMyLocationClickListener import com.google.android.gms.maps.OnMapReadyCallback import com.google.android.gms.maps.SupportMapFragment import com.google.maps.example.R internal class MyLocationLayerActivity : AppCompatActivity(), OnMyLocationButtonClickListener, OnMyLocationClickListener, OnMapReadyCallback { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_my_location) val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment mapFragment.getMapAsync(this) } @SuppressLint("MissingPermission") override fun onMapReady(map: GoogleMap) { // TODO: Before enabling the My Location layer, you must request // location permission from the user. This sample does not include // a request for location permission. map.isMyLocationEnabled = true map.setOnMyLocationButtonClickListener(this) map.setOnMyLocationClickListener(this) } override fun onMyLocationClick(location: Location) { Toast.makeText(this, "Current location:\n$location", Toast.LENGTH_LONG) .show() } override fun onMyLocationButtonClick(): Boolean { Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT) .show() // Return false so that we don't consume the event and the default behavior still occurs // (the camera animates to the user's current position). return false } }
جاوا
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.maps.example; import android.annotation.SuppressLint; import android.location.Location; import android.os.Bundle; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; class MyLocationLayerActivity extends AppCompatActivity implements GoogleMap.OnMyLocationButtonClickListener, GoogleMap.OnMyLocationClickListener, OnMapReadyCallback { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_location); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this); } @SuppressLint("MissingPermission") @Override public void onMapReady(GoogleMap map) { // TODO: Before enabling the My Location layer, you must request // location permission from the user. This sample does not include // a request for location permission. map.setMyLocationEnabled(true); map.setOnMyLocationButtonClickListener(this); map.setOnMyLocationClickListener(this); } @Override public void onMyLocationClick(@NonNull Location location) { Toast.makeText(this, "Current location:\n" + location, Toast.LENGTH_LONG) .show(); } @Override public boolean onMyLocationButtonClick() { Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT) .show(); // Return false so that we don't consume the event and the default behavior still occurs // (the camera animates to the user's current position). return false; } }
وقتی لایه «موقعیت مکانی من» فعال باشد، دکمه «موقعیت مکانی من» در گوشه بالا سمت راست نقشه ظاهر میشود. وقتی کاربر روی این دکمه کلیک میکند، دوربین نقشه را روی مکان فعلی دستگاه، در صورت مشخص بودن، متمرکز میکند. اگر دستگاه ثابت باشد، مکان با یک نقطه آبی کوچک روی نقشه نشان داده میشود، یا اگر دستگاه در حال حرکت باشد، به صورت یک علامت شورون نمایش داده میشود.
تصویر زیر دکمه «موقعیت مکانی من» را در بالا سمت راست و نقطه آبی «موقعیت مکانی من» را در مرکز نقشه نشان میدهد:

شما میتوانید با فراخوانی UiSettings.setMyLocationButtonEnabled(false) از نمایش دکمهی «موقعیت مکانی من» جلوگیری کنید.
برنامه شما میتواند به رویدادهای زیر پاسخ دهد:
- اگر کاربر روی دکمهی «موقعیت مکانی من» کلیک کند، برنامهی شما یک فراخوانی
onMyLocationButtonClick()ازGoogleMap.OnMyLocationButtonClickListenerدریافت میکند. - اگر کاربر روی نقطه آبی «موقعیت مکانی من» کلیک کند، برنامه شما یک فراخوانی
onMyLocationClick()ازGoogleMap.OnMyLocationClickListenerدریافت میکند.
API موقعیت مکانی سرویسهای گوگل پلی
API موقعیت مکانی سرویسهای گوگل پلی، روش ترجیحی برای افزودن آگاهی از موقعیت مکانی به برنامه اندروید شماست. این API شامل قابلیتهایی است که به شما امکان میدهد:
- محل دستگاه را تعیین کنید.
- به تغییرات مکان گوش دهید.
- اگر وسیله در حال حرکت است، نحوه حمل و نقل را تعیین کنید.
- ایجاد و نظارت بر مناطق جغرافیایی از پیش تعریف شده، که به عنوان حصارهای جغرافیایی شناخته میشوند.
APIهای موقعیت مکانی، ساخت برنامههای کاربردی با مصرف انرژی بهینه و آگاه از موقعیت مکانی را برای شما آسان میکنند. مانند Maps SDK برای اندروید، Location API به عنوان بخشی از SDK سرویسهای Google Play توزیع شده است. برای اطلاعات بیشتر در مورد Location API، لطفاً به کلاس آموزشی Android Making Your Location Aware یا مرجع Location API مراجعه کنید. نمونههای کد به عنوان بخشی از SDK سرویسهای Google Play گنجانده شدهاند.