随着移动应用的使用不断增加,地理定位和跟踪功能可以在大多数应用程序中找到。实时地理位置跟踪在许多按需服务中起着重要作用,例如:
- 出租车服务,如Uber、Lyft或Ola
- 食品配送服务,如优步饮食,食品熊猫或佐马托
- 监测无人驾驶飞机机队
在本指南中,我们将使用Reaction本机创建一个实时位置跟踪应用程序。我们将构建两个本地应用程序。其中一个将充当跟踪应用程序(称为“跟踪应用程序”),另一个将作为跟踪应用(“Trackee应用程序”)。
本教程的最终输出如下所示:
视频播放器
00:00
00:10
想要从地面上学到本地人的反应吗?这篇文章是我们高级图书馆的摘录。获得一个完整的集合反应本土书籍涵盖基础,项目,技巧和工具&更多与SitePoint高级。现在就加入吧,每月只需9美元.
先决条件
本教程要求基本的反应本土化知识。若要设置您的开发机器,请按照官方指南进行操作。这里.
除了ReactiveNativeREAR之外,我们还将使用巴布提供实时数据传输和更新的第三方服务。我们将使用此服务实时更新用户坐标。
注册免费PubNub帐户这里.
由于我们将在Android上使用GoogleMaps,我们还需要一个GoogleMapsAPI密钥,您可以在GoogleMaps上获得它获取API密钥一页。
为了确保我们在同一个页面上,本教程中使用了以下版本:
- 节点v10.15.0
- 国家预防机制6.4.1
- 纱1.16.0
- 反应-本机0.59.9
- 反应-本机-地图0.24.2
- PubNub-Reaction 1.2.0
开始
如果您想立即查看我们的跟踪器和Trackee应用程序的源代码,下面是它们的GitHub链接:
让我们先从Trackee应用程序开始。
Trackee应用程序
若要创建新项目,请使用react-native-cli
,在终端中键入以下内容:
$ react-native init trackeeApp
$ cd trackeeApp
现在让我们来谈谈有趣的部分-编码。
添加ReactiveNativeMaps
由于我们将在我们的应用程序中使用地图,我们需要一个库。我们会用反应-本地地图.
安装react-native-maps
按照安装说明这里.
添加PubNub
除了地图之外,我们还将安装PubNub Reaction SDK来实时传输我们的数据:
$ yarn add pubnub-react
之后,您现在可以运行该应用程序:
$ react-native run-ios
$ react-native run-android
您应该在模拟器/模拟器上看到这样的内容:
Trackee码
现在,打开App.js
文件和下列导入:
import React from "react";
import {
StyleSheet,
View,
Platform,
Dimensions,
SafeAreaView
} from "react-native";
import MapView, { Marker, AnimatedRegion } from "react-native-maps";
import PubNubReact from "pubnub-react";
除了MapView将在组件中呈现Map之外,我们还导入了Marker
和AnimatedRegion
从…react-native-mas
.
Marker
标识地图上的位置。我们将使用它来识别地图上的用户位置。
AnimatedRegion
允许我们利用动画API来控制地图的中心和缩放。
导入必要的组件后,我们将为映射定义一些常量和初始值:
const { width, height } = Dimensions.get("window");
const ASPECT_RATIO = width / height;
const LATITUDE = 37.78825;
const LONGITUDE = -122.4324;
const LATITUDE_DELTA = 0.0922;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
然后,我们将使用一些状态、生命周期方法和自定义助手方法来定义类组件:
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
latitude: LATITUDE,
longitude: LONGITUDE,
coordinate: new AnimatedRegion({
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: 0,
longitudeDelta: 0
})
};
this.pubnub = new PubNubReact({
publishKey: "X",
subscribeKey: "X"
});
this.pubnub.init(this);
}
componentDidMount() {
this.watchLocation();
}
componentDidUpdate(prevProps, prevState) {
if (this.props.latitude !== prevState.latitude) {
this.pubnub.publish({
message: {
latitude: this.state.latitude,
longitude: this.state.longitude
},
channel: "location"
});
}
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchID);
}
watchLocation = () => {
const { coordinate } = this.state;
this.watchID = navigator.geolocation.watchPosition(
position => {
const { latitude, longitude } = position.coords;
const newCoordinate = {
latitude,
longitude
};
if (Platform.OS === "android") {
if (this.marker) {
this.marker._component.animateMarkerToCoordinate(
newCoordinate,
500 // 500 is the duration to animate the marker
);
}
} else {
coordinate.timing(newCoordinate).start();
}
this.setState({
latitude,
longitude
});
},
error => console.log(error),
{
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 1000,
distanceFilter: 10
}
);
};
getMapRegion = () => ({
latitude: this.state.latitude,
longitude: this.state.longitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA
});
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={styles.container}>
<MapView
style={styles.map}
showUserLocation
followUserLocation
loadingEnabled
region={this.getMapRegion()}
>
<Marker.Animated
ref={marker => {
this.marker = marker;
}}
coordinate={this.state.coordinate}
/>
</MapView>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
justifyContent: "flex-end",
alignItems: "center"
},
map: {
...StyleSheet.absoluteFillObject
}
});
呼!这是很多代码,所以让我们一步地看一遍。
首先,我们初始化了一些本地州constructor()
..我们还将初始化一个PubNub实例:
constructor(props) {
super(props);
this.state = {
latitude: LATITUDE,
longitude: LONGITUDE,
coordinate: new AnimatedRegion({
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: 0,
longitudeDelta: 0,
}),
};
// Initialize PubNub
this.pubnub = new PubNubReact({
publishKey: 'X',
subscribeKey: 'X',
});
this.pubnub.init(this);
}
您需要将“X”替换为您自己的PubNub发布和订阅键。要获得您的钥匙,登录到您的PubNub帐户,并进入仪表板。
你会发现演示项目应用程序已经在那里可用了。您可以自由地创建一个新应用程序,但是对于本教程,我们将使用以下内容演示项目。
复制并粘贴PubNub构造函数实例中的键。
之后,我们将使用componentDidMount()
生命周期调用watchLocation
方法:
componentDidMount() {
this.watchLocation();
}
watchLocation = () => {
const { coordinate } = this.state;
this.watchID = navigator.geolocation.watchPosition(
position => {
const { latitude, longitude } = position.coords;
const newCoordinate = {
latitude,
longitude,
};
if (Platform.OS === 'android') {
if (this.marker) {
this.marker._component.animateMarkerToCoordinate(newCoordinate, 500); // 500 is the duration to animate the marker
}
} else {
coordinate.timing(newCoordinate).start();
}
this.setState({
latitude,
longitude,
});
},
error => console.log(error),
{
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 1000,
distanceFilter: 10,
}
);
};
这个watchLocation
使用geolocation
用于监视用户位置坐标变化的API。所以每当用户移动和他的位置坐标发生变化时,watchPosition
将返回用户的新坐标。
这个watchPosition
接受两个参数-options
和callback
.
作为选择,我们会enableHighAccuracy
到true
为了高精度,和distanceInterval
到10
只有当位置变化至少10米时,才能接收更新。如果您希望获得最大的精度,请使用0
,但请注意,它将使用更多的带宽和数据。
在callback
,我们得到位置坐标,并调用这些坐标来设置本地状态变量。
const { latitude, longitude } = position.coords;
this.setState({
latitude,
longitude
});
现在我们有了用户坐标,我们将使用它们在地图上添加一个标记,然后随着用户坐标随其位置的变化而不断更新该标记。
为此,我们将使用animateMarkerToCoordinate()
为Android
和coordinate.timing()
为IOS。我们将传递一个对象newCoordinate
带着latitude
和longitude
作为这些方法的参数:
if (Platform.OS === "android") {
if (this.marker) {
this.marker._component.animateMarkerToCoordinate(newCoordinate, 500); // 500 is the duration to animate the marker
}
} else {
coordinate.timing(newCoordinate).start();
}
我们也希望用户的坐标被不断地发送到我们的跟踪应用程序。为了实现这一点,我们将使用Reaction的componentDidUpdate
生命周期方法:
componentDidUpdate(prevProps, prevState) {
if (this.props.latitude !== prevState.latitude) {
this.pubnub.publish({
message: {
latitude: this.state.latitude,
longitude: this.state.longitude,
},
channel: 'location',
});
}
}
这个componentDidUpdate
在更新发生后立即调用。因此,每次更改用户的坐标时都会调用它。
我们进一步使用了if
条件仅在纬度更改时发布坐标。
然后我们给PubNub打电话publish
方法来发布坐标以及通道名称。location
我们要公布这些坐标。
注意:确保channel
两个应用程序的名称都是相同的。否则,您将不会收到任何数据。
现在,我们已经完成了所有必需的方法,让我们呈现MapView
..将此代码添加到您的render
方法:
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={styles.container}>
<MapView
style={styles.map}
showUserLocation
followUserLocation
loadingEnabled
region={this.getMapRegion()}
>
<Marker.Animated
ref={marker => {
this.marker = marker;
}}
coordinate={this.state.coordinate}
/>
</MapView>
</View>
</SafeAreaView>
);
我们用Marker.Animated
,随着用户的移动和坐标的变化,它将以动画的方式移动。
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchID);
}
我们也会清除所有geolocation
观察法componentWillUnmount()
以避免任何内存泄漏。
让我们通过添加一些样式来完成Trackee应用程序:
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
justifyContent: "flex-end",
alignItems: "center"
},
map: {
...StyleSheet.absoluteFillObject
}
});
由于我们希望我们的地图覆盖整个屏幕,所以我们必须使用绝对定位,并将每一侧设置为零(position: 'absolute', left: 0, right: 0, top: 0, bottom: 0
).
StyleSheet
提供absoluteFill
这可以用来方便和减少重复这些重复的风格。
运行Trackee应用程序
在我们更进一步之前,测试我们的应用总是一个好主意。我们可以采取以下步骤来做到这一点。
在IOS上
如果你使用的是iOS模拟器,那你就走运了。与Android相比,在iOS中测试这一功能非常容易。
在IOS模拟器设置中,转到调试 > 位置 > 高速公路车道刷新你的应用程序(CMD + R)。你应该看到这样的东西:
在Android上
不幸的是,对于Android来说,没有简单的方法来测试这个特性。
您可以使用第三方应用程序来模仿gps定位应用程序。我发现GPS Joybar帮个大忙。
您也可以使用基因运动,它有一个用于模拟位置的实用程序。
PubNub的测试
要测试PubNub是否正在接收数据,您可以打开实时分析,这将显示您的应用程序正在接收或发送的消息数量。
在你的钥匙选项卡,转到底部并打开实时分析..然后转到实时分析,检查数据是否被接收.
视频播放器
00:00
00:09
这是所有的Trackee应用需要做的,所以让我们转到跟踪应用程序。
跟踪应用程序
遵循与Trackee应用程序相同的步骤,创建一个名为Reactinativeproject的新项目trackerApp
.
Tracker和Trackee应用程序共享它们的大部分代码。
唯一的区别是trackerApp
我们将从trackeeApp
通过PubNub。
添加pubnub-react
SDK,导入并初始化,就像我们在Trackee应用程序中所做的那样。
在……里面componentDidMount()
,增加以下内容:
// same imports as trackeeApp
componentDidMount() {
/* remove
watchLocation = () => {}
*/
// add:
this.subscribeToPubNub();
}
// add:
subscribeToPubNub = () => {
this.pubnub.subscribe({
channels: ['location'],
withPresence: true,
});
this.pubnub.getMessage('location', msg => {
const { coordinate } = this.state;
const { latitude, longitude } = msg.message;
const newCoordinate = { latitude, longitude };
if (Platform.OS === 'android') {
if (this.marker) {
this.marker._component.animateMarkerToCoordinate(newCoordinate, 500);
}
} else {
coordinate.timing(newCoordinate).start();
}
this.setState({
latitude,
longitude,
});
});
};
/* remove
watchLocation = () => {
}
*/
这是最新版本的偷偷摸摸的高峰。电码追踪器的应用程序。
在上面的代码中,我们使用PubNub的subscribe
方法订阅我们的location
一旦组件被挂载,就启动通道。
在那之后,我们用getMessage
才能接收到在那个频道上收到的消息。
我们将使用这些坐标更新跟踪程序的MapView。
因为这两个应用程序共享相同的坐标集,所以我们应该能够在Tracker应用程序中看到Trackee应用程序的坐标。
同时运行两个应用程序
我们终于走到最后一步了。在同一台开发模式下在同一台机器上测试这两个应用程序并非易事。
为了在iOS机器上测试这两个应用程序,我将遵循以下步骤:
-
我们将在iOS模拟器上运行Trackee应用程序,因为它有调试模式,我可以在那里模拟移动的车辆。我还将在发布模式下运行它,因为我们不能同时运行两个包:
$ react-native run-ios --configuration Release
现在,去调试 > 位置 > 高速公路车道.
-
我们将在Android模拟器上运行Tracker应用程序:
$ react-native run-android
跟踪程序现在应该能够查看Marker
就像Trackee应用程序一样移动。
您可以在GitHub上找到这两个应用程序的源代码。