داده های موقعیت مکانی

یکی از ویژگی های منحصر به فرد اپلیکیشن های موبایل، آگاهی از موقعیت مکانی است. کاربران تلفن همراه دستگاه‌های خود را همه جا با خود می‌آورند و افزودن آگاهی از موقعیت مکانی به برنامه شما تجربه متنی‌تری را به کاربران ارائه می‌دهد.

نمونه کد

مخزن ApiDemos در GitHub شامل نمونه هایی است که استفاده از مکان را بر روی نقشه نشان می دهد:

کاتلین

جاوا

کار با داده های مکان

داده‌های موقعیت مکانی موجود برای یک دستگاه Android شامل مکان فعلی دستگاه - با استفاده از ترکیبی از فناوری‌ها مشخص شده است - جهت و روش حرکت، و اینکه آیا دستگاه در یک مرز جغرافیایی از پیش تعریف‌شده یا زمین‌فنس حرکت کرده است یا خیر. بسته به نیاز برنامه‌تان، می‌توانید بین چندین روش کار با داده‌های مکان انتخاب کنید:

  • لایه My Location یک راه ساده برای نمایش موقعیت مکانی یک دستگاه بر روی نقشه ارائه می کند. داده ارائه نمی دهد.
  • API مکان خدمات Google Play برای همه درخواست‌های برنامه‌ریزی شده برای داده‌های مکان توصیه می‌شود.
  • رابط LocationSource به شما امکان می دهد یک ارائه دهنده مکان سفارشی ارائه دهید.

مجوزهای مکان

اگر برنامه شما نیاز به دسترسی به موقعیت مکانی کاربر دارد، باید با افزودن مجوزهای مکان Android مربوطه به برنامه خود، اجازه درخواست کنید.

Android دو مجوز مکان ارائه می‌کند: ACCESS_COARSE_LOCATION و ACCESS_FINE_LOCATION . مجوزی که انتخاب می‌کنید، دقت مکان بازگردانده شده توسط API را تعیین می‌کند.

  • android.permission.ACCESS_COARSE_LOCATION – به API اجازه می دهد مکان تقریبی دستگاه را برگرداند. این مجوز تخمین موقعیت مکانی دستگاه را از خدمات مکان ارائه می دهد، همانطور که در مستندات مربوط به دقت مکان تقریبی توضیح داده شده است.
  • android.permission.ACCESS_FINE_LOCATION - به API اجازه می دهد تا مکان ممکن را از ارائه دهندگان موقعیت مکانی موجود، از جمله سیستم موقعیت یابی جهانی (GPS) و همچنین WiFi و داده های تلفن همراه تعیین کند.

مجوزها را به مانیفست برنامه اضافه کنید

اگر مکان تقریبی فقط برای عملکرد برنامه شما مورد نیاز است، اجازه 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>

درخواست مجوزهای زمان اجرا

اندروید 6.0 (مارشملو) مدل جدیدی را برای مدیریت مجوزها معرفی می‌کند که فرآیند نصب و ارتقاء برنامه‌ها را برای کاربران ساده می‌کند. اگر برنامه شما سطح API 23 یا بالاتر را هدف قرار می دهد، می توانید از مدل مجوزهای جدید استفاده کنید.

اگر برنامه شما از مدل مجوزهای جدید پشتیبانی می کند و دستگاه دارای Android نسخه 6.0 (مارشملو) یا جدیدتر است، کاربر مجبور نیست هنگام نصب یا ارتقاء برنامه، هیچ مجوزی اعطا کند. برنامه باید بررسی کند که آیا مجوز لازم را در زمان اجرا دارد یا خیر، و اگر مجوز را ندارد، درخواست کند. سیستم یک دیالوگ را برای کاربر نمایش می دهد که درخواست مجوز می کند.

برای بهترین تجربه کاربری، درخواست مجوز در زمینه مهم است. اگر مکان برای عملکرد برنامه شما ضروری است، باید مجوز مکان را هنگام راه اندازی برنامه درخواست کنید. یک راه خوب برای انجام این کار، استفاده از یک صفحه خوشامدگویی گرم یا جادوگر است که به کاربران در مورد چرایی نیاز به مجوز آموزش می دهد.

اگر برنامه فقط برای بخشی از عملکرد خود به مجوز نیاز دارد، باید در زمانی که برنامه اقدامی را انجام می‌دهد که به مجوز نیاز دارد، مجوز مکان را درخواست کنید.

برنامه باید با مهربانی مواردی را که کاربر اجازه نمی دهد رسیدگی کند. به عنوان مثال، اگر مجوز برای یک ویژگی خاص مورد نیاز باشد، برنامه می تواند آن ویژگی را غیرفعال کند. اگر مجوز برای عملکرد برنامه ضروری باشد، برنامه می‌تواند همه عملکردهای آن را غیرفعال کند و به کاربر اطلاع دهد که باید مجوز را اعطا کند.

نمونه کد زیر قبل از فعال کردن لایه My Location، مجوز را با استفاده از کتابخانه AndroidX بررسی می‌کند. سپس با اجرای ActivityCompat.OnRequestPermissionsResultCallback از کتابخانه پشتیبانی، نتیجه درخواست مجوز را مدیریت می کند:

کاتلین

// 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.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback
import androidx.core.content.ContextCompat
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 : AppCompatActivity(),
    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)
    }

    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 AppCompatActivity
    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(R.layout.my_location_demo);

        SupportMapFragment mapFragment =
            (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @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");
    }

}

لایه My Location

می توانید از لایه My Location و دکمه My Location برای نشان دادن موقعیت فعلی کاربر خود در نقشه استفاده کنید. برای فعال کردن لایه My Location روی نقشه، mMap.setMyLocationEnabled() را فراخوانی کنید.

نمونه زیر استفاده ساده از لایه My Location را نشان می دهد:

کاتلین

// 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;
    }
}


      

وقتی لایه My Location فعال است، دکمه My Location در گوشه سمت راست بالای نقشه ظاهر می شود. هنگامی که کاربر روی دکمه کلیک می کند، دوربین نقشه را روی مکان فعلی دستگاه متمرکز می کند، اگر مشخص باشد. اگر دستگاه ثابت است، مکان با یک نقطه آبی کوچک در نقشه یا اگر دستگاه در حال حرکت است، به صورت شورون نشان داده می شود.

تصویر زیر دکمه My Location را در بالا سمت راست و نقطه آبی My Location را در مرکز نقشه نشان می دهد:

می‌توانید با فراخوانی UiSettings.setMyLocationButtonEnabled(false) از نمایش دکمه موقعیت مکانی من جلوگیری کنید.

برنامه شما می تواند به رویدادهای زیر پاسخ دهد:

  • اگر کاربر روی دکمه موقعیت مکانی من کلیک کند، برنامه شما یک پاسخ تماس onMyLocationButtonClick() از GoogleMap.OnMyLocationButtonClickListener دریافت می کند.
  • اگر کاربر روی نقطه آبی My Location کلیک کند، برنامه شما یک پاسخ تماس onMyLocationClick() از GoogleMap.OnMyLocationClickListener دریافت می کند.

API مکان خدمات Google Play

Google Play Location API روش ترجیحی برای افزودن آگاهی از موقعیت مکانی به برنامه Android شما است. این شامل عملکردی است که به شما امکان می دهد:

  • محل دستگاه را تعیین کنید.
  • به تغییرات مکان گوش دهید.
  • اگر دستگاه در حال حرکت است، نحوه حمل و نقل را تعیین کنید.
  • ایجاد و نظارت بر مناطق جغرافیایی از پیش تعریف شده، معروف به geofences.

API های مکان ساختن برنامه های کاربردی آگاه از موقعیت مکانی را برای شما آسان می کنند. مانند Maps SDK برای Android، Location API به عنوان بخشی از SDK خدمات Google Play توزیع شده است. برای اطلاعات بیشتر در مورد Location API، لطفاً به کلاس آموزش Android Making Your App Location Aware یا Location API Reference مراجعه کنید. نمونه کد به عنوان بخشی از SDK خدمات Google Play گنجانده شده است.