使用Reaction本地和PubNub的实时位置跟踪

随着移动应用的使用不断增加,地理定位和跟踪功能可以在大多数应用程序中找到。实时地理位置跟踪在许多按需服务中起着重要作用,例如:

  • 出租车服务,如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之外,我们还导入了MarkerAnimatedRegion从…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接受两个参数-optionscallback.

作为选择,我们会enableHighAccuracytrue为了高精度,和distanceInterval10只有当位置变化至少10米时,才能接收更新。如果您希望获得最大的精度,请使用0,但请注意,它将使用更多的带宽和数据。

callback,我们得到位置坐标,并调用这些坐标来设置本地状态变量。

const { latitude, longitude } = position.coords;

this.setState({
  latitude,
  longitude
});

现在我们有了用户坐标,我们将使用它们在地图上添加一个标记,然后随着用户坐标随其位置的变化而不断更新该标记。

为此,我们将使用animateMarkerToCoordinate()Androidcoordinate.timing()为IOS。我们将传递一个对象newCoordinate带着latitudelongitude作为这些方法的参数:

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-reactSDK,导入并初始化,就像我们在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机器上测试这两个应用程序,我将遵循以下步骤:

  1. 我们将在iOS模拟器上运行Trackee应用程序,因为它有调试模式,我可以在那里模拟移动的车辆。我还将在发布模式下运行它,因为我们不能同时运行两个包:

     $ react-native run-ios --configuration Release
    

    现在,去调试 > 位置 > 高速公路车道.

  2. 我们将在Android模拟器上运行Tracker应用程序:

     $ react-native run-android
    

跟踪程序现在应该能够查看Marker就像Trackee应用程序一样移动。

您可以在GitHub上找到这两个应用程序的源代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值