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

Marcos Martínez picture Marcos Martínez · Jan 26, 2018 · Viewed 10k times · Source

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?

Answer

Mojtaba Izadmehr picture Mojtaba Izadmehr · Jan 30, 2018

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.