如果没有带有GPS的当前位置,则无法使用navigator.geolocation

时间:2018-01-26 00:52:51

标签: react-native gps location expo

讨论和答案后的简短摘要

使用EXPO sdk,如果没有在android中授予FINE_LOCATION,则无法获取设备位置。 FINE_LOCATION是获取位置的唯一方法,因此,您无法获得hardware.network.location。这意味着:使用android> 6您无法使用WIFI /移动网络获取当前位置,您必须启用位置。

Expo github讨论: https://github.com/expo/expo/issues/1339

最初的问题:

我正在使用 react-native 应用程序,使用expo和react-native-maps ,我需要获取用户当前位置的纬度和纵向。

我正在使用navigator.geolocation API

打开GPS后,我没有任何问题,但我需要根据网络提供商获得没有GPS的当前位置。

问题是,当应用程序在androiod>上运行带有expo的时6 我收到此错误:

  

21:50:53:在449ms 21:50:55完成构建JavaScript包:   位置服务已停用    - node_modules \ react-native \ Libraries \ BatchedBridge \ NativeModules.js:80:57   在    - node_modules \ react-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 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",
  }

我希望navigator.geolocation在那种情况下获得基于网络提供商的位置(没有gps),规范说明了......

我也尝试过世博会的Geolocation API(试过这个例子:https://snack.expo.io/@schazers/expo-map-and-location-example),并且关闭了GPS我无法获得我的位置..

所以..有没有办法实现我想要的?我错过了什么?

编辑(EXPO贡献者答案):

我在expo github(https://github.com/expo/expo/issues/1339)发布了相同内容,据他们说,使用navigator.geolocation获取当前位置是不可能的,而Android设备中没有启用任何级别的位置..所以...唯一可能发生的事情是,5岁以上的Android版本默认启用了位置,你可以只启用GPS,版本6和转发你必须指定位置级别..

任何想法?

EDIT2(重要!!):

我已经证实了这一点:

enter image description here

这是Android 6设备的安全设置,默认情况下它使用GPS,我认为android 5或更低版本没有,所以那就是.. 当我使用第二个选项时,它会让我获得位置!< /强>

事实是,强制用户启用位置就像“嘿,使用你的GPS!”,并且有很多应用程序可以在不打开位置的情况下为你提供近似位置(例如Uber),所以问题是,有没有办法只使用wifi获取此API的位置?

5 个答案:

答案 0 :(得分:9)

您在此处理的问题是使用EXPO,因为在Android 5(API 21)之后位置请求API已更改。

在API 21之前,您需要添加ACCESS_FINE_LOCATION(Wifi /网络和GPS提供商)和ACCESS_COARSE_LOCATION(仅限GPS权限)位置权限。但是,从Android 5开始,api会更改为android.hardware.location.networkandroid.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>

但是,似乎人们在expo中只包含了android清单中的新权限。所以你需要做的是改变android清单。但是,expo只允许访问程序的纯JS部分而不是本机代码。因此,您需要从EXPO分离以添加本机模块或更改。

在expo文档中,分离过程在this link中解释,过程很简单:

  1. 使用npm:

    全局安装expo包

    npm install -g exp

  2. 在项目目录中运行分离代码,它将在项目目录中构建android和ios文件夹:

    exp detach

  3. 然后你可以在android清单文件中进行所需的更改。

答案 1 :(得分:3)

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

如果没有,我会将这些权限添加到应用中,然后重试。

答案 2 :(得分:2)

我遇到了同样的问题并尝试了很多库来获取用户位置。 navigator.geolocation API每次在android上都没有给我位置,而只是给出了大部分超时错误。那么我尝试react native background geolocation开始连续使用gps,然后我找到react native geolocation service,作者清楚mentioned

  

由于这个库本来是RN's Geolocation 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" />

对于测试示例,您只需遵循RN Geolocation API建议的相同说明。以下是使用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 }
        );
    }
}

因此,在getCurrentPosition使用enableHighAccuracy false的第三个参数中,使用网络获取用户位置,使用gps获取更准确的位置。见this option documentation

此回购的作者还提供了example project您可以尝试使用enableHighAccuracy false并首次关闭位置但是当您运行该应用时,它会要求获得该位置的许可将显示应用程序想要访问wifi或蜂窝网络提供的位置。

当您使用世博会时,您不能使用react native geolocation service,因为您需要关注Mojtaba answer以获取分离并获取Android和iOS项目,以便您可以配置这两个项目。如果您需要更多信息,请与我们联系。

答案 3 :(得分:0)

就我而言,我通过在AndroidManifest.xml中添加以下内容解决了我的问题。

tmpWin = window;

答案 4 :(得分:0)

首先在您的应用中授予权限 对于Ios:您需要在Info.plist中包含NSLocationWhenInUseUsageDescription

对于android:

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