Bref résumé après discussion et réponses:
en utilisant EXPO sdk, vous ne pouvez pas obtenir l'emplacement de l'appareil sans accorder FINE_LOCATION dans Android. FINE_LOCATION est la seule méthode pour obtenir l'emplacement, vous ne pouvez donc pas obtenir le hardware.network.location. Cela signifie: avec Android> 6, vous ne pouvez pas obtenir l'emplacement actuel en utilisant les réseaux WIFI/mobiles, vous devez activer la localisation.
Discussion sur l'Expo Github:https://github.com/expo/expo/issues/1339
Le problème initial:
je travaille sur une react-native application, en utilisant expo et react-native-maps, et j'ai besoin d'obtenir la latitude et la longitude de la position actuelle de l'utilisateur .
J'utilise API navigator.geolocation pour cela
avec le GPS allumé, je n'ai aucun problème, mais j'ai besoin d'obtenir la position actuelle sans GPS, en fonction du fournisseur de réseau.
Le problème est que lorsque l'application s'exécute avec expo sur androiod> 6 j'obtiens cette erreur:
21:50:53: Construction du bundle JavaScript terminée en 449ms 21:50:55: Les services de localisation sont désactivés - node_modules\react-native\Libraries\BatchedBridge\NativeModules.js: 80: 57 dans - node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js: 347: 19 dans __invokeCallback - ... 4 autres cadres de pile à partir du cadre interne
Dans les IO et Android <= 5, cela fonctionne très bien.
Voici le code du composant:
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
}
);
}
Et voici mes dépendances 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",
}
Je m'attends à ce que navigator.geolocation obtienne l'emplacement basé sur le fournisseur de réseau dans cette situation (sans gps), la spécification dit que ..
j'ai également essayé avec l'API de géolocalisation d'expo (essayé cet exemple: https://snack.expo.io/@schazers/expo-map-and-location-example ), et avec le GPS tourné OFF je ne peux pas obtenir mon emplacement ..
alors .. y a-t-il un moyen de réaliser ce que je veux? il me manque quelque chose?
EDIT (EXPO CONTRIBUTEUR RÉPONSE):
J'ai posté la même chose sur expo github ( https://github.com/expo/expo/issues/1339 ), selon eux, il est impossible d'obtenir la position actuelle en utilisant navigator.geolocation sans aucune niveau de localisation activé dans un Android .. donc .. la seule chose qui pourrait arriver est que Android antérieures à 5 ont la localisation activée par défaut et vous pouvez activer uniquement le GPS, et les versions 6 et suivantes, vous devez spécifier le niveau de localisation ..
des idées?
EDIT2 (IMPORTANT !!):
Je l'ai confirmé:
ce sont les paramètres de sécurité d'un appareil Android 6, par défaut, il utilise le GPS, je pense que Android 5 ou inférieur ne fonctionne pas, donc c'est la chose .. = lorsque j'utilise la 2ème option, cela me donne l'emplacement !
le fait est que forcer un utilisateur à activer la localisation est comme "hé, utilisez votre GPS!", et il existe de nombreuses applications qui vous donnent une position approximative sans activer la localisation (comme Uber par exemple), donc la question est, existe-t-il un moyen d'utiliser UNIQUEMENT le wifi avec cet api?
Le problème que vous traitez ici est avec EXPO, car l'API de demande de localisation a changé après Android 5 (API 21).
Avant l'API 21, vous deviez ajouter à ACCESS_FINE_LOCATION
(Fournisseurs Wifi/Réseau et GPS) et ACCESS_COARSE_LOCATION
(autorisation GPS uniquement) autorisations de localisation. Cependant, depuis Android 5, les API se transforment en Android.hardware.location.network
et Android.hardware.location.gps
.
Lorsque vos utilisateurs cibles incluent les deux Android 5 +/-. Vous devez ajouter les deux types d'autorisation à votre Android, par exemple:
<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>
Cependant, il semble que les gens de l'expo, uniquement inclus, la nouvelle autorisation dans le manifeste Android. Donc, ce que vous devez faire est de changer Android manifeste Cependant, expo ne donne accès qu'à une partie JS pure du programme et non à des codes natifs. Par conséquent, vous devez vous détacher d'EXPO pour ajouter des modules natifs ou des modifications.
Dans la documentation de l'expo, le processus de détachement est expliqué dans ce lien , la procédure est simple:
installez le paquet expo globalement en utilisant npm:
npm install -g exp
Dans votre répertoire de projet, exécutez le code de détachement, il créera Android et dossiers ios dans votre répertoire de projet:
exp detach
Ensuite, vous pouvez apporter les modifications dont vous avez besoin dans le fichier manifeste Android.
Bug commun dans Android. Essayez sans utiliser le troisième paramètre:
getCurrentLocation = () =>
navigator.geolocation.getCurrentPosition(
(position) => {
let currentUserPosition = position.coords;
alert(JSON.stringify(currentUserPosition));
},
(error) => {
console.log(error);
}
);
Donc, je viens de creuser un peu dans le code et, fondamentalement, tout le LocationModule fait est d'envoyer la demande directement à Android.
Il appelle simplement cette méthode:
Maintenant, si vous lisez cela, l'emplacement indique FINE_LOCATION ou COARSE_LOCATION.
Habituellement, il suffit d'ajouter les autorisations de localisation fines, mais je pense que peut-être pour accéder à l'emplacement Wifi, vous devez ajouter les autorisations grossières dans l'application. Avez-vous les deux?
https://developer.Android.com/reference/Android/Manifest.permission.html#ACCESS_COARSE_LOCATION
Sinon, j'ajouterais ces autorisations dans l'application et réessayer.
J'avais le même problème et j'ai essayé beaucoup de bibliothèques pour obtenir l'emplacement de l'utilisateur. API navigator.geolocation ne m'a pas donné de localisation à chaque fois sur Android au lieu de cela, il ne donne principalement qu'une erreur de timeout. Alors j'ai essayé réagir à la géolocalisation en arrière-plan natif) qui commencent à utiliser le gps en continu puis je trouve réagit au service de géolocalisation natif et l'auteur clairement mentionné que:
Étant donné que cette bibliothèque était censée être un remplacement pour le API de géolocalisation de RN, l'utilisation est assez simple, avec quelques cas d'erreur supplémentaires à gérer.
c'est ce dont j'avais toujours besoin et je pense que vous devriez également essayer cela.
Jetez un oeil sur ce fichier AndroidManifest
, l'auteur utilise tout type d'emplacement.
<?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" />
pour l'exemple de test, vous suivrez simplement les mêmes instructions que celles suggérées par l'API RN Geolocation. Voici un exemple simple d'utilisation du service de géolocalisation native react:
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 }
);
}
}
Ainsi, dans le troisième paramètre de getCurrentPosition
, utilisez enableHighAccuracy
false pour utiliser le réseau pour obtenir l'emplacement utilisateur et true pour obtenir un emplacement plus précis à l'aide de gps. Voir la documentation de cette option .
L'auteur de ce dépôt a également fourni le exemple de projet vous pouvez l'essayer avec enableHighAccuracy
false et désactiver l'emplacement pour la première fois, mais lorsque vous exécutez l'application, il demandera l'autorisation du l'emplacement, il montrera que l'application souhaite accéder au wifi ou à l'emplacement fourni par le réseau cellulaire.
Comme vous utilisez expo, vous ne pouvez pas utiliser réagir au service de géolocalisation natif pour cela, vous devez suivre réponse Mojtaba pour le détachement et obtenir le Android et Projet iOS pour que vous puissiez configurer les deux projets. Faites-moi savoir si vous avez besoin de plus d'informations.
Dans mon cas, j'ai résolu mon problème en ajoutant ce qui suit dans AndroidManifest.xml.
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />
Tout d'abord, donnez des autorisations dans votre application Pour Ios: vous devez inclure la clé NSLocationWhenInUseUsageDescription
dans Info.plist
Pour Android:
<uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />
De là, nous obtenons le code de lat et de longitude ==>
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 });