Разрешение на проверку Android для LocationManager

Я пытаюсь отобразить координаты GPS, когда я нажимаю кнопку в макете активности. Ниже приведен метод, вызываемый при нажатии кнопки:

public void getLocation(View view) {
    TextView tv = (TextView) findViewById(R.id.gps_coord_view);
    LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
    Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    tv.setText("Latitude: " + loc.getLatitude() + "\nLongitude: " + loc.getLongitude());
}

Я получаю сообщение об ошибке

Для вызова требуется разрешение, которое может быть отклонено пользователем. Код должен явно проверять, доступно ли разрешение.

Я уже предоставил эти разрешения в своем AndroidManifest. Ошибка выполняется, и приложение компилируется, когда я добавляю следующее до вызова lm.getLastKnownLocation:

if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
        && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    return;
}

Тем не менее, приложение падает, когда я нажимаю кнопку, которая вызывает getLocation при нажатии. Что происходит? Есть ли лучший/более простой способ захвата GPS-координат устройства?

Ответ 1

С уровнем API Android (23) нам необходимо проверить разрешения. https://developer.android.com/training/permissions/requesting.html

У меня была такая же проблема, но для меня это работало, и я смог успешно получить данные о местоположении:

(1) Убедитесь, что у вас есть права, перечисленные в манифесте:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

(2) Убедитесь, что вы запрашиваете разрешения у пользователя:

if ( ContextCompat.checkSelfPermission( this, android.Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) {

            ActivityCompat.requestPermissions( this, new String[] {  android.Manifest.permission.ACCESS_COARSE_LOCATION  },
                                                LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION );
        }

(3) Убедитесь, что вы используете ContextCompat, поскольку это совместимо со старыми уровнями API.

(4) В вашем сервисе местоположения или классе, который инициализирует ваш LocationManager и получает последнее известное местоположение, нам нужно проверить разрешения:

if ( Build.VERSION.SDK_INT >= 23 &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return  ;
        }

(5) Этот подход работал только после того, как я включил @TargetApi (23) в начало моего метода initLocationService.

(6) Я также добавил это в мою конструкцию gradle:

compile 'com.android.support:support-v4:23.0.1'

Вот мой LocationService для справки:

public class LocationService implements LocationListener  {

    //The minimum distance to change updates in meters
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 10 meters

    //The minimum time between updates in milliseconds
    private static final long MIN_TIME_BW_UPDATES = 0;//1000 * 60 * 1; // 1 minute

    private final static boolean forceNetwork = false;

    private static LocationService instance = null;

    private LocationManager locationManager;
    public Location location;
    public double longitude;
    public double latitude; 


    /**
     * Singleton implementation
     * @return
     */
    public static LocationService getLocationManager(Context context)     {
        if (instance == null) {
            instance = new LocationService(context);
        }
        return instance;
    }

    /**
     * Local constructor
     */
    private LocationService( Context context )     {

        initLocationService(context); 
        LogService.log("LocationService created");
    }



    /**
     * Sets up location service after permissions is granted
     */
    @TargetApi(23)
    private void initLocationService(Context context) {


        if ( Build.VERSION.SDK_INT >= 23 &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return  ;
        }

        try   {
            this.longitude = 0.0;
            this.latitude = 0.0;
            this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

            // Get GPS and network status
            this.isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            this.isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (forceNetwork) isGPSEnabled = false;

            if (!isNetworkEnabled && !isGPSEnabled)    {
                // cannot get location
                this.locationServiceAvailable = false;
            }
            //else
            {
                this.locationServiceAvailable = true;

                if (isNetworkEnabled) {
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    if (locationManager != null)   {
                        location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        updateCoordinates();
                    }
                }//end if

                if (isGPSEnabled)  {
                    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null)  {
                        location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                        updateCoordinates();
                    }
                }
            }
        } catch (Exception ex)  {
            LogService.log( "Error creating location service: " + ex.getMessage() );

        }
    }       


    @Override
    public void onLocationChanged(Location location)     {
        // do stuff here with location object 
    }
}

Я тестировал только Android-устройство Lollipop. Надеюсь, что это работает для вас.

Ответ 2

В последней части приведенного вами сообщения об ошибке говорится: ...with ("checkPermission") or explicitly handle a potential "SecurityException"

Более быстрый/более простой способ проверки наличия у вас разрешений, чтобы окружить ваш код с помощью try { ... } catch (SecurityException e) { [insert error handling code here] }. Если у вас есть разрешения, часть "try" будет выполняться, если вы этого не сделаете, часть "catch" будет.

Ответ 3

ПРОСТОЕ РЕШЕНИЕ

Я хотел бы поддерживать приложения pre api 23 и вместо использования checkSelfPermission я использовал try/catch

try {
   location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (SecurityException e) {
   dialogGPS(this.getContext()); // lets the user know there is a problem with the gps
}

Ответ 4

если вы работаете с динамическими разрешениями и любое разрешение, такое как ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, дающее ошибку , не может разрешить метод PERMISSION_NAME ", в этом случае напишите код с именем разрешения, а затем перестройте свой проект, это восстановит манифест (Manifest.permission).