Android “gps вимагає ACCESS_FINE_LOCATION” помилки, навіть якщо мій файл маніфесту містить це


104

Кожен раз, коли я запускаю програму, мій SecurityException викидається, а помилка від налагоджувача звучить так:

java.lang.SecurityException: постачальнику локації "gps" потрібен дозвіл ACCESS_COARSE_LOCATION або ACCESS_FINE_LOCATION.

Це здається простою помилкою, однак мій файл маніфесту є абсолютно правильним. Ось він, і ось мій код MapActivity:

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="com.dev.cromer.jason.coverme.permission.MAPS_RECEIVE" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
    <meta-data
        android:name="com.google.android.maps.v2.API_KEY"
        android:value= "@string/google_maps_key" />

    <activity
        android:name=".MapActivity"
        android:label="@string/title_activity_map" >
    </activity>
</application>

Моя активність:

    package com.dev.cromer.jason.coverme;

import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MapActivity extends FragmentActivity implements LocationListener {

    private GoogleMap mMap; // Might be null if Google Play services APK is not available.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map);

        setUpMapIfNeeded();
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();
    }



    private void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the map.
        if (mMap == null) {
            // Try to obtain the map from the SupportMapFragment.
            mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
                    .getMap();

            // Check if we were successful in obtaining the map.
            if (mMap != null) {
                //mMap.setMyLocationEnabled(true);
                //mMap.setOnMyLocationChangeListener(this);
                setUpMap();
            }
        }
    }


    private void setUpMap() {
        mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
        mMap.setMyLocationEnabled(true);

        LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

        try {
            Location myLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

            if (myLocation != null) {
                Log.d("TAG", "Not null");
            }
            else {
                Log.d("TAG", "NULL");
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
            }
        }
        catch (SecurityException se) {
            Log.d("TAG", "SE CAUGHT");
            se.printStackTrace();
        }
    }


    @Override
    public void onLocationChanged(Location location) {
        Log.d("CHANGED", "LOCATION UPDATED");

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }
}

На якій версії Android ви тестуєте це?
CommonsWare

4
Неспоріднене, але якщо ви вимагаєте прекрасного розташування, вам не потрібно запитувати грубе. Він включений.
joey_g216

Відповіді:


136

ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATIONі WRITE_EXTERNAL_STORAGEвсі вони є частиною дозвольної системи виконання 6.0 для Android 6.0 . Крім того, щоб вони були у маніфесті, як і ви, ви також повинні запитувати їх у користувача під час виконання (за допомогою requestPermissions()) та бачити, чи є вони у вас (використовуючи checkSelfPermission()).

Одним із варіантів вирішення за короткий термін є зниження ваших показників targetSdkVersionнижче 23.

Але, зрештою, ви захочете оновити свій додаток, щоб використовувати систему дозволів виконання.

Наприклад, ця діяльність працює з п'ятьма дозволами. Чотири - це дозволи на виконання, хоча в даний час обробляють лише три (я писав це раніше, WRITE_EXTERNAL_STORAGEбуло додано до списку дозволів виконання).

/***
 Copyright (c) 2015 CommonsWare, 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.

 From _The Busy Coder's Guide to Android Development_
 https://commonsware.com/Android
 */

package com.commonsware.android.permmonger;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
  private static final String[] INITIAL_PERMS={
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.READ_CONTACTS
  };
  private static final String[] CAMERA_PERMS={
    Manifest.permission.CAMERA
  };
  private static final String[] CONTACTS_PERMS={
      Manifest.permission.READ_CONTACTS
  };
  private static final String[] LOCATION_PERMS={
      Manifest.permission.ACCESS_FINE_LOCATION
  };
  private static final int INITIAL_REQUEST=1337;
  private static final int CAMERA_REQUEST=INITIAL_REQUEST+1;
  private static final int CONTACTS_REQUEST=INITIAL_REQUEST+2;
  private static final int LOCATION_REQUEST=INITIAL_REQUEST+3;
  private TextView location;
  private TextView camera;
  private TextView internet;
  private TextView contacts;
  private TextView storage;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    location=(TextView)findViewById(R.id.location_value);
    camera=(TextView)findViewById(R.id.camera_value);
    internet=(TextView)findViewById(R.id.internet_value);
    contacts=(TextView)findViewById(R.id.contacts_value);
    storage=(TextView)findViewById(R.id.storage_value);

    if (!canAccessLocation() || !canAccessContacts()) {
      requestPermissions(INITIAL_PERMS, INITIAL_REQUEST);
    }
  }

  @Override
  protected void onResume() {
    super.onResume();

    updateTable();
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.actions, menu);

    return(super.onCreateOptionsMenu(menu));
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch(item.getItemId()) {
      case R.id.camera:
        if (canAccessCamera()) {
          doCameraThing();
        }
        else {
          requestPermissions(CAMERA_PERMS, CAMERA_REQUEST);
        }
        return(true);

      case R.id.contacts:
        if (canAccessContacts()) {
          doContactsThing();
        }
        else {
          requestPermissions(CONTACTS_PERMS, CONTACTS_REQUEST);
        }
        return(true);

      case R.id.location:
        if (canAccessLocation()) {
          doLocationThing();
        }
        else {
          requestPermissions(LOCATION_PERMS, LOCATION_REQUEST);
        }
        return(true);
    }

    return(super.onOptionsItemSelected(item));
  }

  @Override
  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    updateTable();

    switch(requestCode) {
      case CAMERA_REQUEST:
        if (canAccessCamera()) {
          doCameraThing();
        }
        else {
          bzzzt();
        }
        break;

      case CONTACTS_REQUEST:
        if (canAccessContacts()) {
          doContactsThing();
        }
        else {
          bzzzt();
        }
        break;

      case LOCATION_REQUEST:
        if (canAccessLocation()) {
          doLocationThing();
        }
        else {
          bzzzt();
        }
        break;
    }
  }

  private void updateTable() {
    location.setText(String.valueOf(canAccessLocation()));
    camera.setText(String.valueOf(canAccessCamera()));
    internet.setText(String.valueOf(hasPermission(Manifest.permission.INTERNET)));
    contacts.setText(String.valueOf(canAccessContacts()));
    storage.setText(String.valueOf(hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)));
  }

  private boolean canAccessLocation() {
    return(hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));
  }

  private boolean canAccessCamera() {
    return(hasPermission(Manifest.permission.CAMERA));
  }

  private boolean canAccessContacts() {
    return(hasPermission(Manifest.permission.READ_CONTACTS));
  }

  private boolean hasPermission(String perm) {
    return(PackageManager.PERMISSION_GRANTED==checkSelfPermission(perm));
  }

  private void bzzzt() {
    Toast.makeText(this, R.string.toast_bzzzt, Toast.LENGTH_LONG).show();
  }

  private void doCameraThing() {
    Toast.makeText(this, R.string.toast_camera, Toast.LENGTH_SHORT).show();
  }

  private void doContactsThing() {
    Toast.makeText(this, R.string.toast_contacts, Toast.LENGTH_SHORT).show();
  }

  private void doLocationThing() {
    Toast.makeText(this, R.string.toast_location, Toast.LENGTH_SHORT).show();
  }
}

цього зразкового проекту )

Для функції requestPermissions (), параметри повинні бути "ACCESS_COARSE_LOCATION"? Або я повинен включати повне ім’я "android.permission.ACCESS_COARSE_LOCATION"?

Я б використовував константи, визначені на Manifest.permission, як показано вище.

Також, що таке код запиту?

Це буде передано вам як перший параметр onRequestPermissionsResult(), так що ви можете повідомити один requestPermissions()дзвінок від іншого.


1
Для функції requestPermissions (), параметри повинні бути "ACCESS_COARSE_LOCATION"? Або я повинен включати повне ім’я "android.permission.ACCESS_COARSE_LOCATION"?
Джейсон Кромер

1
Дякую, це позбулося помилки. У мене все ще виникають проблеми з доступом до мого місцезнаходження, оскільки мій locationManager постійно повертає моє місцезнаходження як нулеве, але це не стосується цієї помилки. Дякую за ваше рішення!
Джейсон Кромер

@CommonsWare: Що ви маєте на увазі під словом "зрештою"? Вибачте, я не розумію цієї частини.
theapache64

1
@ theapache64: Колись щось стане причиною того, що ви захочете встановити targetSdkVersionзначення 23 або вище. Після цього вам потрібно буде прийняти систему дозволів виконання. Поки цей час не наблизиться, ви можете тримати targetSdkVersionменше 23 і ігнорувати дозволи на виконання.
CommonsWare

@CommonsWare: Тепер я це отримав. :)
theapache64

39

Моє просте рішення це

if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) ==
        PackageManager.PERMISSION_GRANTED &&
        ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
        PackageManager.PERMISSION_GRANTED) {
    googleMap.setMyLocationEnabled(true);
    googleMap.getUiSettings().setMyLocationButtonEnabled(true);
} else {
    Toast.makeText(this, R.string.error_permission_map, Toast.LENGTH_LONG).show();
}

або можна відкрити діалогове вікно дозволу в іншому подібному

} else {
   ActivityCompat.requestPermissions(this, new String[] {
      Manifest.permission.ACCESS_FINE_LOCATION, 
      Manifest.permission.ACCESS_COARSE_LOCATION }, 
      TAG_CODE_PERMISSION_LOCATION);
}

laways переходимо до іншої частини bro :(
Ashana.Jackol

2
Додайте діалогове вікно, щоб додати дозволи в цьому "ще", і ви добре піти.
Василь Валчев

Це фактично без сумнівів виправлення для Android 6. Слід зазначити, що ви повинні помістити запити на дозвіл в інше.
Кіт Адлер

Я отримав цю помилку з цільовим SDK як 22 та на Android 5.1 на пристрої S plus (GiONEE_WBL7511). Я розгублений, чому сталася ця аварія. Будь-які підказки? java.lang.SecurityException: Клієнт повинен мати дозвіл ACCESS_FINE_LOCATION, щоб запитувати місця розташування PRIORITY_HIGH_ACCURACY.
arpitgoyal2008

5

ПРИЧИНА: "Починаючи з Android 6.0 (рівень API 23), користувачі надають дозволи додаткам під час роботи програми, а не під час встановлення програми." У цьому випадку "ACCESS_FINE_LOCATION" є "небезпечним дозволом, і з цієї причини ви отримуєте цей" java.lang.SecurityException: "Провайдеру розташування" gps "потрібен дозвіл ACCESS_FINE_LOCATION." помилка ( https://developer.android.com/training/permissions/requesting.html ).

РІШЕННЯ: Реалізація коду, наданого на веб-сторінці https://developer.android.com/training/permissions/requesting.html у розділі "Запити потрібні дозволи" та "Обробляти відповіді на запит на отримання дозволів".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.