Разрешение проверки 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-координаты устройства?
5 ответов
На уровне 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. Надеюсь, что это работает для вас.
ПРОСТОЕ РЕШЕНИЕ
Я хотел поддерживать приложения до API 23 и вместо использования checkSelfPermission
Я использовал попытку / поймать
try {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (SecurityException e) {
dialogGPS(this.getContext()); // lets the user know there is a problem with the gps
}
Последняя часть сообщения об ошибке, которое вы цитировали, гласит:...with ("checkPermission") or explicitly handle a potential "SecurityException"
Гораздо быстрее / проще проверить, есть ли у вас разрешения, - окружить ваш код try { ... } catch (SecurityException e) { [insert error handling code here] }
, Если у вас есть разрешения, будет выполнена часть try, в противном случае - часть catch.
Используйте мой привычный класс, чтобы проверить или запросить разрешение
public class Permissons {
//Request Permisson
public static void Request_STORAGE(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},code);
}
public static void Request_CAMERA(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.CAMERA},code);
}
public static void Request_FINE_LOCATION(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.ACCESS_FINE_LOCATION},code);
}
public static void Request_READ_SMS(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.READ_SMS},code);
}
public static void Request_READ_CONTACTS(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.READ_CONTACTS},code);
}
public static void Request_READ_CALENDAR(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.READ_CALENDAR},code);
}
public static void Request_RECORD_AUDIO(Activity act,int code)
{
ActivityCompat.requestPermissions(act, new
String[]{Manifest.permission.RECORD_AUDIO},code);
}
//Check Permisson
public static boolean Check_STORAGE(Activity act)
{
int result = ContextCompat.checkSelfPermission(act,android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_CAMERA(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.CAMERA);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_FINE_LOCATION(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.ACCESS_FINE_LOCATION);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_READ_SMS(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_SMS);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_READ_CONTACTS(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_CONTACTS);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_READ_CALENDAR(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_CALENDAR);
return result == PackageManager.PERMISSION_GRANTED;
}
public static boolean Check_RECORD_AUDIO(Activity act)
{
int result = ContextCompat.checkSelfPermission(act, Manifest.permission.RECORD_AUDIO);
return result == PackageManager.PERMISSION_GRANTED;
}
}
пример
if(!Permissons.Check_STORAGE(MainActivity.this))
{
//if not permisson granted so request permisson with request code
Permissons.Request_STORAGE(MainActivity.this,22);
}
Если вы работаете с динамическими разрешениями и любыми разрешениями, такими как ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, выдающей ошибку "не удается разрешить метод PERMISSION_NAME", в этом случае напишите код с именем разрешения и затем пересоберите свой проект, что создаст файл манифеста (Manifest.permission).
Если вы просто хотите проверить разрешения (а не запросить разрешения), я написал такое простое расширение:
fun BaseActivity.checkPermission(permissionName: String): Boolean {
return if (Build.VERSION.SDK_INT >= 23) {
val granted =
ContextCompat.checkSelfPermission(this, permissionName)
granted == PackageManager.PERMISSION_GRANTED
} else {
val granted =
PermissionChecker.checkSelfPermission(this, permissionName)
granted == PermissionChecker.PERMISSION_GRANTED
}
}
Теперь, если я хочу проверить разрешение, я могу просто передать такое разрешение:
checkPermission(Manifest.permission.READ_CONTACTS)