在没有 GPS 的情况下,使用 navigator.geolocation 在 react-native 上无法获取当前位置
Posted
技术标签:
【中文标题】在没有 GPS 的情况下,使用 navigator.geolocation 在 react-native 上无法获取当前位置【英文标题】:Cannot get current position without GPS on react-native with navigator.geolocation 【发布时间】:2018-07-05 09:02:43 【问题描述】:讨论和回答后的简要总结:
使用 EXPO sdk 如果没有在 android 中授予 FINE_LOCATION,您将无法获取设备位置。 FINE_LOCATION 是获取位置的唯一方法,因此您无法获取hardware.network.location。这意味着:android > 6 您无法使用 WIFI/移动网络获取当前位置,您必须启用 Location。
世博github讨论:https://github.com/expo/expo/issues/1339
最初的问题:
我正在开发一个 react-native 应用程序,使用 expo 和 react-native-maps,我需要获取用户当前位置的纬度和经度。
我为此使用navigator.geolocation API
在打开 GPS 的情况下,我没有任何问题,但我需要根据网络提供商在没有 GPS 的情况下获取当前位置。
问题是当应用程序运行 with expo on android > 6 我得到这个错误:
21:50:53:在 449 毫秒内完成构建 javascript 包 21:50:55: 定位服务被禁用 - node_modules\react-native\Libraries\BatchedBridge\NativeModules.js:80:57 在 - node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:347:19 在 __invokeCallback - ... 来自框架内部的另外 4 个堆栈帧
在 IO 和 android
这是组件的代码:
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 依赖项:
"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)根据网络提供商获取位置,规范说..
我也尝试过使用 expo 的 Geolocation API(试过这个例子:https://snack.expo.io/@schazers/expo-map-and-location-example),在 GPS 关闭的情况下,我无法获取我的位置..
所以..有没有办法实现我想要的?我错过了什么?
编辑(世博会贡献者回答):
我在 expo github (https://github.com/expo/expo/issues/1339) 上发布了相同的内容,根据他们的说法,如果没有在 android 设备中启用任何级别的 Location ,使用 navigator.geolocation 获取当前位置是不可能的.. 所以 .. 唯一的事情可能发生的情况是,低于 5 的 android 版本默认启用位置,您可以只打开 GPS,而版本 6 及更高版本您必须指定位置级别..
有什么想法吗?
EDIT2(重要!!):
我已确认:
这是 Android 6 设备的安全设置,默认情况下它使用 GPS,我认为 android 5 或更低版本没有,所以事情就是这样。当我使用第二个选项时,它会告诉我位置!
事实上,强制用户启用位置功能就像“嘿,使用你的 GPS!”,并且有很多应用程序可以在不启用位置功能的情况下为您提供近似位置(例如优步),所以问题是,有没有办法只使用 wifi 获取这个 api 的位置?
【问题讨论】:
【参考方案1】:您在这里处理的问题是 EXPO,因为位置请求 API 在 Android 5(API 21) 之后发生了变化。
在 API 21 之前,您需要添加到ACCESS_FINE_LOCATION
(Wifi/网络和 GPS 提供商)和ACCESS_COARSE_LOCATION
(仅 GPS 权限)位置权限。但是,从 Android 5 开始,api 更改为 android.hardware.location.network
和 android.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>
但是,似乎世博会中的人,只包括了android清单中的新权限。所以你需要做的是改变android manifest。然而,expo 只允许访问程序的纯 JS 部分,而不是原生代码。因此,您需要从 EXPO 中分离以添加原生模块或更改。
在expo文档中,分离过程在this link中有说明,过程很简单:
使用 npm 全局安装 expo 包:
npm install -g exp
在您的项目目录中,运行分离代码,它将在您的项目目录中构建android和ios文件夹:
exp detach
然后你可以在android清单文件中进行你需要的更改。
【讨论】:
【参考方案2】: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
如果没有,我会将该权限添加到应用程序中,然后重试。
【讨论】:
我已经尝试过了,得到了同样的错误。问题是,如果没有打开位置,navigator.geolocation 会引发错误(“本地化服务已禁用”)。我觉得这很奇怪,因为 Expo 应用程序启用了 Location 权限,所以我希望 navigator.geolocation 在这种情况下使用 WIFI,但是当设备上的 Location 关闭时它会进入错误功能。 如果我尝试这个博览会示例:snack.expo.io/@schazers/expo-map-and-location-example 我无法仅使用 WIFI 获取位置,并且在 android 6 或更高版本中关闭智能手机的位置。 我会尝试的,但由于我使用 Expo,我无法修改 AndroidManifest.xml,我的意思是,我无法访问 android 本机代码,而 expo sems 只能访问“位置”权限类型docs.expo.io/versions/latest/sdk/permissions.html【参考方案3】:我遇到了同样的问题,并尝试了很多库来获取用户位置。 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 原生地理定位服务的简单示例:
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 使用网络获取用户位置,使用true 使用gps 获取更准确的位置。见this option documentation。
此 repo 的作者还提供了 example project,您可以尝试使用 enableHighAccuracy
false 并首次关闭位置,但是当您运行应用程序时,它会询问位置的许可,它将显示应用程序想要访问 wifi 或手机网络提供的位置。
当你使用expo时,你不能使用react native geolocation service,你需要按照Mojtaba answer进行分离并获取android和iOS项目,以便你可以配置这两个项目。如果您需要更多信息,请告诉我。
【讨论】:
【参考方案4】:就我而言,我通过在 AndroidManifest.xml 中添加以下内容解决了我的问题。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
【讨论】:
【参考方案5】:首先在您的应用中授予权限
对于 Ios:您需要在 Info.plist 中包含 NSLocationWhenInUseUsageDescription
键
对于安卓:
<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 );
【讨论】:
以上是关于在没有 GPS 的情况下,使用 navigator.geolocation 在 react-native 上无法获取当前位置的主要内容,如果未能解决你的问题,请参考以下文章
在没有互联网的情况下使用 Javascript 获取 GPS 位置 [重复]
核心位置,是不是可以在没有 GPS 芯片的情况下向 iPad 提供 GPS/位置日期,以便在 CLLocationManager 类中使用?