Cannot get current position without GPS on react-native with navigator.geolocation

12,104

Solution 1

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:

  1. install expo package globally using npm:

    npm install -g exp

  2. 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.

Solution 2

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.

Solution 3

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.

Share:
12,104

Related videos on Youtube

Marcos Martínez
Author by

Marcos Martínez

https://marcosmartinez.io/

Updated on June 04, 2022

Comments

  • Marcos Martínez
    Marcos Martínez almost 2 years

    Brief summary after discussion and answers:

    using EXPO sdk you cannot get the device location without grant FINE_LOCATION in android. FINE_LOCATION is the only method to get location, so, you cannot get the hardware.network.location. That means: with android > 6 you cannot get the current location using WIFI/mobile networks, you must enable Location.

    Expo github discussion: https://github.com/expo/expo/issues/1339

    The initial problem:

    im working on a react-native application, using expo and react-native-maps, and i need to get the latitude and longitud of the user current position.

    Im using navigator.geolocation API for that

    with the GPS turned on i have no problems, but i need to get the current position without GPS, based on the network provider.

    The problem is that when the application runs with expo on androiod > 6 i get this error:

    21:50:53: Finished building JavaScript bundle in 449ms 21:50:55: Location services are disabled - node_modules\react-native\Libraries\BatchedBridge\NativeModules.js:80:57 in - node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:347:19 in __invokeCallback - ... 4 more stack frames from framework internals

    In IOs and android <=5 it works great.

    Here is the code of the component:

    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
                }
            );
    
    }
    

    And this are my package.json depencendies:

    "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",
      }
    

    I expect that navigator.geolocation get the location based on the network provider in that situation (without gps), the specification saids that..

    i also tried with the Geolocation API of expo (tried this example: https://snack.expo.io/@schazers/expo-map-and-location-example) , and with the GPS turned OFF i cant get my location..

    so.. is there a way to achieve what i want? i am missing something?

    EDIT (EXPO CONTRIBUTOR ANSWER):

    I have posted the same at expo github (https://github.com/expo/expo/issues/1339), according to them it is imposible to get the current position using navigator.geolocation without any level of Location enabled in a android device.. so .. the only thing that could happen is that android versions older than 5 has location enabled by default and you can turn on just the GPS, and the versions 6 and forward you must specify the location level ..

    any ideas?

    EDIT2 (IMPORTANT !!):

    I have confirmed this:

    enter image description here

    this is security settings of a Android 6 device, by default it uses GPS, i think that android 5 or lower doesnt, so thats the thing.. when i use the 2nd option it gets me the location !

    the fact is that forcing a user to enable Location is like "hey, use your GPS!", and there are a lot of applications that gives you a aproximated position without turning on Location (like Uber for example), so the question is, is there a way that ONLY using wifi get the location with this api?

  • Marcos Martínez
    Marcos Martínez about 6 years
    I've already tried that, getting the same error. The thing is that without the Location turned on the navigator.geolocation throws an error ("Localization services are disabled"). I think it is weird, because the Expo app has the Location permissions enabled, so i expect that navigator.geolocation uses WIFI in this situation, but it goes to the error function when the Location is OFF at the device.
  • Marcos Martínez
    Marcos Martínez about 6 years
    If I try this expo example:snack.expo.io/@schazers/expo-map-and-location-exampl‌​e I cannot get the Location using only WIFI and with the Location of the smartphone off in android 6 or greater.
  • Marcos Martínez
    Marcos Martínez about 6 years
    I will try that, but since im using Expo i cannot modify the AndroidManifest.xml, i mean, i dont have access to the android native code, and expo sems like only can get access to a "Location" permission type docs.expo.io/versions/latest/sdk/permissions.html