Cannot get current position without GPS on react-native with navigator.geolocation
The problem you are dealing with here is with EXPO, because the location request API has changed after Android 5(API 21).
Before API 21, you needed to add to ACCESS_FINE_LOCATION
(Both Wifi/Network and GPS providers) and ACCESS_COARSE_LOCATION
(only GPS permission) location permissions. However, since Android 5, the apis changes to android.hardware.location.network
and android.hardware.location.gps
.
When your target users include both Android 5 +/-. you need to add both permission types to your android manifest, for example:
<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>
However, it seems that the people in expo, only included, the new permission in the android manifest. So what you need to do is to change android manifest. However, expo only gives access to pure JS part of the program and not to native codes. As a result, you need to detach from EXPO to add native modules or changes.
In expo documentation, the detachment process is explained in this link, the procedure is simple:
install expo package globally using npm:
npm install -g exp
Inside your project directory, run detachment code, it will build android and ios folders in your project directory:
exp detach
Then you can make the changes you need in android manifest file.
Common bug in Android. Try without using the third parameter:
getCurrentLocation = () =>
navigator.geolocation.getCurrentPosition(
(position) => {
let currentUserPosition = position.coords;
alert(JSON.stringify(currentUserPosition));
},
(error) => {
console.log(error);
}
);
So, I just digged a little into the code and basically all the LocationModule does is send the request directly to Android.
It just calls this method:
https://developer.android.com/reference/android/location/LocationManager.html#getLastKnownLocation(java.lang.String)
Now, if you read that, the location says FINE_LOCATION or COARSE_LOCATION.
Usually one just add the fine location permissions, but I am thinking that maybe to access the Wifi location you need to add the coarse permissions into the app. Do you have both?
https://developer.android.com/reference/android/Manifest.permission.html#ACCESS_COARSE_LOCATION
If not, I would add that permissions into the app and try again.
I was having the same issue and tried a lot of libraries to get the user location. navigator.geolocation API did not gave me location every time on android instead it just give mostly timeout error only. So then I tried react native background geolocation that start using the gps continuously then I find react native geolocation service and the author clearly mentioned that:
Since this library was meant to be a drop-in replacement for the RN's Geolocation API, the usage is pretty straight forward, with some extra error cases to handle.
thats what I needed always and I think you should also try this.
Have a look on this AndroidManifest
file, the author is using all type of location.
<?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" />
for the test example you'll simply follow the same instruction that RN Geolocation API suggesting. Here is the simple example using react native geolocation service:
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 }
);
}
}
So in the third parameter of the getCurrentPosition
use enableHighAccuracy
false to use network to get user location and true to get more accurate location using gps. See this option documentation.
Author of this repo also provided the example project you can try it with enableHighAccuracy
false and turn location off for the first time but when you run the app it will ask for the permission of the location it will show app want to access wifi or cell network provided location.
As you are using expo you cannot use react native geolocation service for that you need to follow Mojtaba answer for detachment and get the android and iOS project so that you can configure both projects. Let me know if you need more information.