Не удается получить текущую позицию без GPS на основе реакции с navigator.geolocation
Краткое резюме после обсуждения и ответы:
используя EXPO SDK вы не можете получить местоположение устройства без предоставления FINE_LOCATION в Android. FINE_LOCATION - единственный метод для определения местоположения, поэтому вы не можете получить hardware.network.location. Это означает: с android> 6 вы не можете получить текущее местоположение, используя WIFI/мобильные сети, вы должны включить Location.
Обсуждение github на выставке: https://github.com/expo/expo/issues/1339
Начальная проблема:
Я работаю над собственным приложением реакции, используя expo и response-native-карты, и мне нужно получить широту и долготу текущей позиции пользователя.
Я использую Navigation.geolocation API для этого
с включенным GPS у меня нет проблем, но мне нужно получить текущее положение без GPS, основываясь на провайдере сети.
Проблема в том, что когда приложение работает с expo на androiod> 6, я получаю эту ошибку:
21:50:53: Завершено сборка JavaScript-пакета за 449 мс 21:50:55: Службы определения местоположения отключены - node_modules\реагировать-native\Libraries\BatchedBridge\NativeModules.js: 80: 57 in - node_modules\реагировать-native\Libraries\BatchedBridge\MessageQueue.js: 347: 19 в __invokeCallback -... еще 4 стековых фрейма из внутренних компонентов фреймворка
В IO и Android <= 5 это прекрасно работает.
Вот код компонента:
class MyComponent extends Component {
componentWillMount = () => {
this.getCurrentLocation();
}
getCurrentLocation = () =>
navigator.geolocation.getCurrentPosition(
(position) => {
let currentUserPosition = position.coords;
alert(JSON.stringify(currentUserPosition));
},
(error) => {
console.log(error);
},
{
enableHighAccuracy: false,
timeout: 20000,
maximumAge: 0,
distanceFilter: 10
}
);
}
И это мои зависимости package.json:
"dependencies": {
"expo": "23.0.4",
"native-base": "^2.3.5",
"react": "16.0.0",
"react-native": "0.50.4",
"react-native-extend-indicator": "^0.1.2",
"react-native-maps": "^0.19.0",
"react-native-maps-directions": "^1.3.0",
"react-native-router-flux": "4.0.0-beta.21",
"react-navigation": "1.0.0-beta.21",
"react-navigation-redux-debouncer": "^0.0.2",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
}
Я ожидаю, что navigator.geolocation получит местоположение на основе сетевого провайдера в этой ситуации (без gps), в спецификации сказано, что..
я также попробовал с API геолокации expo (попробовал этот пример: https://snack.expo.io/@schazers/expo-map-and-location-example), и с выключенным GPS я не могу получить свое местоположение.,
так.. есть ли способ добиться того, чего я хочу? я что-то упустил?
РЕДАКТИРОВАТЬ (EXPO CONTRIBUTOR ANSWER):
Я опубликовал то же самое на выставке github (https://github.com/expo/expo/issues/1339), по их мнению, невозможно получить текущую позицию с помощью navigator.geolocation без какого-либо уровня местоположения, включенного в Android устройство... так что... единственное, что может случиться, это то, что в версиях Android старше 5 по умолчанию включено местоположение, и вы можете включить только GPS, а в версиях 6 и выше вы должны указать уровень местоположения.
есть идеи?
РЕДАКТИРОВАТЬ 2 (ВАЖНО!):
Я подтвердил это:
![enter image description here]()
это настройки безопасности устройства Android 6, по умолчанию оно использует GPS, я думаю, что Android 5 или ниже не делает, так что вот в чем дело... когда я использую второй вариант, он получает мне местоположение!
Дело в том, что принуждение пользователя к включению Location похоже на "эй, используй свой GPS!", и есть много приложений, которые дают вам приблизительную позицию без включения Location (как, например, Uber), поэтому вопрос в том, Есть ли способ, что ТОЛЬКО с помощью Wi-Fi получить местоположение с этим API?
Ответы
Ответ 1
Проблема, с которой вы здесь работаете, связана с EXPO, потому что API запроса местоположения изменился после Android 5 (API 21).
До API 21 вам нужно было добавить к ACCESS_FINE_LOCATION
(как ACCESS_FINE_LOCATION
Wi-Fi/Network и GPS), так и ACCESS_COARSE_LOCATION
(только разрешения GPS) разрешения. Однако, начиная с Android 5, apis меняется на android.hardware.location.network
и android.hardware.location.gps
.
Когда ваши целевые пользователи включают Android 5 + / -. вам нужно добавить оба типа разрешений в ваш манифест Android, например:
<manifest ... >
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- for Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.location.network" />
</manifest>
Тем не менее, кажется, что люди в Экспо, только включены, новое разрешение в манифесте Android. Так что вам нужно изменить манифест Android. Однако expo предоставляет доступ только к чистой части программы JS, а не к собственным кодам. В результате вам необходимо отсоединиться от EXPO, чтобы добавить собственные модули или изменения.
В выставочной документации процесс ветки объясняется по этой ссылке, процедура проста:
-
установить пакет expo глобально, используя npm:
npm install -g exp
-
Внутри вашего проекта запустите код отсоединения, он создаст папки android и ios в вашем каталоге проекта:
exp detach
Затем вы можете внести необходимые изменения в файл манифеста Android.
Ответ 2
Общая ошибка в Android. Попробуйте без использования третьего параметра:
getCurrentLocation = () =>
navigator.geolocation.getCurrentPosition(
(position) => {
let currentUserPosition = position.coords;
alert(JSON.stringify(currentUserPosition));
},
(error) => {
console.log(error);
}
);
Итак, я просто немного вычислил код и в основном все, что делает LocationModule, отправляет запрос прямо на Android.
Он просто вызывает этот метод:
https://developer.android.com/reference/android/location/LocationManager.html#getLastKnownLocation(java.lang.String)
Теперь, если вы прочтете это, в местоположении указывается FINE_LOCATION или COARSE_LOCATION.
Обычно просто добавляются разрешения на точное расположение, но я думаю, что, возможно, для доступа к местоположению Wifi вам нужно добавить грубые разрешения в приложение. У вас есть оба?
https://developer.android.com/reference/android/Manifest.permission.html#ACCESS_COARSE_LOCATION
Если нет, я бы добавил, что разрешения в приложении и повторите попытку.
Ответ 3
У меня была такая же проблема, и я попробовал много библиотек, чтобы получить местоположение пользователя. navigator.geolocation API не дал мне место каждый раз на андроиде, а просто дал только ошибку с превышением времени. Итак, я попробовал отредактировать родную геолокацию фона, которая начнет использовать gps непрерывно, тогда я нахожу реагировать на родную геолокационную службу, а автор явно отметил, что:
Поскольку эта библиотека предназначалась для замены для RN's API геолокации, использование довольно прямолинейно, с некоторыми дополнительными ошибки для обработки.
Это то, что мне нужно всегда, и я думаю, вы также должны попробовать это.
Посмотрите на этот файл AndroidManifest
, автор использует все типы местоположений.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.agontuk.RNFusedLocation">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
для тестового примера вы просто выполните ту же инструкцию, что и предлагаемый API геолокации RN. Вот простой пример, использующий встроенную службу геолокации:
import Geolocation from 'react-native-geolocation-service';
componentDidMount() {
// Instead of navigator.geolocation, just use Geolocation.
if (hasLocationPermission) {
Geolocation.getCurrentPosition(
(position) => {
console.log(position);
},
(error) => {
// See error code charts below.
console.log(error.code, error.message);
},
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 }
);
}
}
Итак, в третьем параметре getCurrentPosition
используйте enableHighAccuracy
false, чтобы использовать сеть, чтобы получить местоположение пользователя и true, чтобы получить более точное местоположение с помощью gps. См. эту опционную документацию.
Автор этого репо также предоставил примерный проект, вы можете попробовать его с помощью enableHighAccuracy
false и отключить местоположение в первый раз, но когда вы запустите приложение, он попросит разрешения на местоположение, которое будет показывать приложение, чтобы получить доступ к Wi-Fi или сети сотовой сети.
Поскольку вы используете expo, вы не можете использовать отредактировать собственную службу геолокации, для чего вам нужно следовать Mojtaba ответьте для отстранения и получите проект android и iOS, чтобы вы могли настроить оба проекта. Дайте мне знать, если вам нужна дополнительная информация.
Ответ 4
В моем случае я решил свою проблему, добавив следующее в AndroidManifest.xml.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Ответ 5
Прежде всего, дайте разрешения в вашем приложении. Для Ios: вам нужно включить ключ NSLocationWhenInUseUsageDescription
в Info.plist
Для андроида:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Отсюда мы получаем широту и долготу КОД ==>
navigator.geolocation.getCurrentPosition(
(position) => {
const initialPosition = JSON.stringify(position);
// console.log(initialPosition);
this.setState({ initialPosition });
},
//(error) => alert(error.message),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
);
this.watchID = navigator.geolocation.watchPosition((position) => {
const lastPosition = JSON.stringify(position);
//this.setState({ longitude: position.coords.longitude, latitude: position.coords.latitude });
//this._getWheaterData();
AsyncStorage.setItem('latitude',position.coords.latitude.toString())
AsyncStorage.setItem('longitude',position.coords.longitude.toString())
},
// (error) => alert(error.message),
// console.log(error),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 });