Автор оригинала: Wern Ancheta.
В этом руководстве мы создадим приложение для бронирования езды с реактивным нативным и толкателем. Приложение, которое мы создадим, будет похоже на популярные приложения для бронирования езды, такие как Uber, Lyft или Grab. React Nature будет использоваться для создания приложения для Android для драйвера, так и для пассажира. Толкатель будет использоваться для связи в реальном времени между двумя.
Что вы будете создавать
Как и любое другое приложение для бронирования поездки там, будет приложение драйвера и пассажирское приложение. Пассажирское приложение будет использоваться для бронирования езды, а приложение водителя просто получает любой запрос, который поступает из пассажирского приложения. Для целей консистенции мы просто ссылаемся на приложение как «GRABCLONE».
Поток приложения
Клон, который мы собираемся создать, в значительной степени, в значительной степени одинаковый поток, что и любое приложение для бронирования поездки: пассажирские книги Ride → приложение ищет драйвер → драйвер принимает запрос → водитель подбирает пассажиров → драйверы до назначения → Пассажир платит водителю.
Здесь я просто хочу показать вам, как этот процесс будет выглядеть внутри приложения. Таким образом, у вас будет четкая картина того, что вы собираетесь создавать.
Приложение определяет местоположение пользователя и показывает его на карте (Примечание: на данный момент необходимо включить GPS).
От пассажирского приложения пользователь нажимает на «Бронировать поездку».
Модаль откроется, что позволит пассажиру выбрать место, где они хотят пойти.
Приложение просит пассажира подтвердить свой пункт назначения.
После подтверждения приложение отправляет запрос на приложение драйвера, чтобы забрать пассажир. Анимация загрузки отображается, пока приложение ждет драйвера, чтобы принять запрос.
Приложение водителя получает запрос. Отсюда водитель может принимать или отклонить запрос.
Как только драйвер принимает запрос, данные драйвера отображаются в пассажирском приложении.
Пассажирское приложение показывает текущее местоположение драйвера на карте.
После того, как водитель находится в 50 метрах от местоположения пассажира, они увидят предупреждение о том, что водитель рядом.
После того, как водитель находится в пределах 20 метров от местоположения пассажира, приложение водителя отправляет сообщение в приложение пассажира, что водитель практически там.
После подъема пассажира водитель приводит к месту назначения.
После того, как водитель находится в пределах 20 метров от своего назначения, приложение драйвера отправляет сообщение пассажирству, которое они очень близко к месту назначения.
На данный момент езды заканчиваются, и пассажир может забронировать другую поездку. Водитель также может принимать любую входящую проездную поездку.
Предпосылки
Учетная учетная запись – Регистрация для учетной записи Pusher или Войти с вашим существующим Отказ После того, как вы создали учетную запись, создайте новое приложение → Выбрать «Реагирование» для интерфейсных технологий → Выберите «Node.js» для задней технологии.
Затем нажмите на вкладку «Настройки приложения» и проверьте «Включить клиентские события». Это позволяет нам иметь приложение водителя и пассажира напрямую общаться друг с другом.
Последнее, нажмите на «клавиши приложений» и скопируйте учетные данные. Если вы беспокоитесь о ценах, Pusher Plan Sandbox довольно щедрый Таким образом, вы можете использовать его бесплатно при тестировании приложения.
Установите Android Studio – Вам не нужна Android-студия, но она поставляется с Android SDK, который нам нужен. Google также больше не предлагает отдельная загрузка для него.
Установить React Native – Метод, который я рекомендую для этого, является строительным проектам народный путь. Когда вы находитесь на севере RACT NONED, нажмите «Строительные проекты с нативным кодом» вкладки и следуйте инструкциям там. Экспо Клиент отлично подходит для быстрого прототипов приложений, но он на самом деле не предлагает быстрый способ для того, чтобы мы проверили функции геолокации, которые нам нужны для этого приложения.
Genymotion – Для тестирования приложения водителя. Мы используем это вместо эмулятора Android по умолчанию, потому что он поставляется с инструментом моделирования GPS, который позволяет нам искать определенное местоположение и использовать его в качестве расположения эмулируемого устройства. Он использует Google Maps в качестве интерфейса, и вы также можете перемещать маркер. Это позволяет имитировать движущийся транспортный автомобиль. Как только Genymotion установлен, вам необходимо войти в свою учетную запись, чтобы добавить устройство. Для меня я установил Google Nexus 5X для тестирования.
Android-устройство – Это будет использоваться для тестирования пассажирского приложения. Обязательно проверьте версию вашего телефона Android. Если это что-то более низкое, чем 4,2, то вам нужно установить дополнительные пакеты через Android SDK Manager. Это связано с тем, что по умолчанию реагируйте нативные цели API версии 23 или выше. Это означает, что Android-версия вашего телефона должна быть версии 6.0, по крайней мере, или приложение не будет работать. Если вы установили Android Studio, вы можете получить доступ к менеджеру SDK, открывая Android Studio → Нажмите «Настроить» → Выбрать «SDK Manager». Затем под «платформами SDK» проверьте версии Android, которые вы хотите поддержать.
Пока вы там, нажмите на «SDK Tools» и убедитесь, что у вас также есть те же инструменты, установленные как мой:
- Дополнительный компьютер – Это необязательно. Я только что включал его здесь, потому что arent React может запустить приложение на одном устройстве или эмуляторе одновременно. Таким образом, вам необходимо сделать дополнительную работу, чтобы запускать два приложения, как вы увидите позже.
Создание сервера auth
Теперь пришло время загрязнеть наши руки. Во-первых, давайте будем работать на сервере auth. Это требуется, потому что мы будем отправлять События клиента Из приложения, клиентские события требуют, чтобы канал толкателя быть частным, а частные каналы имеют ограниченный доступ. Вот где находится сервер auth. Он служит способом для того, чтобы позвонить, чтобы знать, если пользователь, который пытается подключиться, действительно является зарегистрированным пользователем приложения.
Начните с установки зависимостей:
npm install --save express body-parser pusher
Далее создайте server.js
Файл и добавьте следующий код:
var express = require('express'); var bodyParser = require('body-parser'); var Pusher = require('pusher'); var app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); var pusher = new Pusher({ // connect to pusher appId: process.env.APP_ID, key: process.env.APP_KEY, secret: process.env.APP_SECRET, cluster: process.env.APP_CLUSTER, }); app.get('/', function(req, res){ // for testing if the server is running res.send('all is well...'); }); // for authenticating users app.get("/pusher/auth", function(req, res) { var query = req.query; var socketId = query.socket_id; var channel = query.channel_name; var callback = query.callback; var auth = JSON.stringify(pusher.authenticate(socketId, channel)); var cb = callback.replace(/\"/g,"") + "(" + auth + ");"; res.set({ "Content-Type": "application/javascript" }); res.send(cb); }); app.post('/pusher/auth', function(req, res) { var socketId = req.body.socket_id; var channel = req.body.channel_name; var auth = pusher.authenticate(socketId, channel); res.send(auth); }); var port = process.env.PORT || 5000; app.listen(port);
Я больше не собираюсь вносить в подробности, какой код выше, поскольку он уже объясняется в документах для Аутентификация пользователей Отказ Чтобы сохранить все возможное, я на самом деле не добавил код, чтобы проверить, существует ли пользователь в базе данных. Вы можете сделать это в /pusher/auth
Конечная точка, проверяя, существует ли имя пользователя. Вот пример:
var users = ['luz', 'vi', 'minda']; var username = req.body.username; if(users.indexOf(username) !== -1){ var socketId = req.body.socket_id; var channel = req.body.channel_name; var auth = pusher.authenticate(socketId, channel); res.send(auth); } // otherwise: return error
Не забудьте пройти в Имя пользователя
При подключении к тошеру на стороне клиента позже.
Попробуйте запустить сервер, когда это сделано:
node server.js
Доступ http://localhost: 5000
В вашем браузере, чтобы увидеть, работает ли это.
Развертывание сервера auth
Поскольку pusher придется подключаться к серверу auth, он должен быть доступен из Интернета. Вы можете использовать сейчас .sh Развернуть сервер auth. Вы можете установить его со следующей командой:
npm install now
После установки вы можете теперь перейти к папке, где у вас есть server.js
Файл и выполнить сейчас
Отказ Вас попросят ввести свою электронную почту и подтвердить свою учетную запись.
Как только ваш аккаунт проверен, выполните следующее, чтобы добавить настройки приложения PUSHER в качестве переменных среды на свою учетную запись New.sh, чтобы вы могли использовать его изнутри сервера:
now secret add pusher_app_id YOUR_PUSHER_APP_ID now secret add pusher_app_key YOUR_PUSHER_APP_KEY now secret add pusher_app_secret YOUR_PUSHER_APP_SECRET now secret add pusher_app_cluster YOUR_PUSHER_APP_CLUSTER
Далее разверните сервер при поставке секретных значений, которые вы добавили:
now -e APP_ID=@pusher_app_id -e APP_KEY=@pusher_app_key -e APP_SECRET=@pusher_app_secret APP_CLUSTER=@pusher_app_cluster
Это позволяет вам получить доступ к настройкам приложения Pusher изнутри сервера, как так:
process.env.APP_ID
URL-адрес развертывания, который Now.sh возвращает URL, который вы будете использовать позже, чтобы подключить приложение к серверу auth.
Создание приложения водителя
Теперь вы готовы начать создавать приложение водителя.
Во-первых, создайте новое реагирование нативное приложение:
react-native init grabDriver
Установка зависимостей
Как только это сделано, навигация внутри Грабдривер
Справочник и установите библиотеки, которые нам понадобятся. Это включает в себя PUSHER-JS Для работы с толкателем Реагировать нативные карты Для отображения карты и Реагировать родной геокодирование Для координат обратного геокодирования к фактическому названию места:
npm install --save pusher-js react-native-maps react-native-geocoding
Как только все библиотеки установлены, реагируйте нативные карты, нуждаются в некоторых дополнительных шагах для его работы. Сначала связывает проектные ресурсы:
react-native link react-native-maps
Далее необходимо создать проект Google, получить ключ API из Консоль разработчика Google и включить Google Maps Android API и Google Maps Geocoding API Отказ После этого открыть Android \ app \ src \ main \ androidmanifest.xml
Файл в вашем каталоге проекта. Под <Приложение>
Теги, добавьте
содержащий ключ API сервера.
Пока вы там, добавьте следующее ниже разрешений по умолчанию. Это позволяет проверить состояние сети и запрос данных геолокации с устройства.
Также убедитесь, что его нацеливание на ту же версию API, что и устройство, которое вы установили с помощью Genymotion. Как я уже говорил ранее, если его версия 23 или выше, вам действительно не нужно ничего делать, но если его ниже, то, он должен быть точно для работы приложения.
Наконец, поскольку мы будем в первую очередь использовать Genymotion для тестирования приложения водителя, вам нужно следовать за Инструкции здесь Отказ В случае, если ссылка становится сломанной, вот что вам нужно сделать:
- Посетить OpenGapps.org Отказ
- Выберите X86 в качестве платформы.
- Выберите версию Android, соответствующую вашему виртуальному устройству.
- Выберите Nano как вариант.
- Загрузите ZIP-файл.
- Перетащите установщик ZIP в новом виртуальном устройстве Genymotion (только 2.7.2 и выше).
- Следуйте за всплывающим инструкциям.
Нам нужно сделать это, потому что библиотека активных карт RACT Noated Maps в основном использует карты Google. Нам нужно добавить сервисы Google Play для этого для работы. В отличие от большинства телефонов Android, которые уже поставляются с этим, Genymotion не имеет его по умолчанию из-за причин интеллектуальной собственности. Таким образом, нам нужно вручную установить его.
Если вы читаете это некоторое время после того, как он был опубликован, обязательно проверьте Монтажные документы чтобы убедиться, что вы не пропустите ничего.
Кодирование приложения водителя
Теперь вы готовы начать кодировать приложение. Начните с открытия index.android.js
Файл и замените код по умолчанию следующим образом:
import { AppRegistry } from 'react-native'; import App from './App'; AppRegistry.registerComponent('grabDriver', () => App);
Что это делает, импортирует Приложение
Компонент, который является основным компонентом для приложения. Затем он зарегистрирован как компонент по умолчанию, поэтому он будет отображен на экране.
Далее создайте App.js
Файл и импортировать вещи, которые нам нужны от нативного пакета raction:
import React, { Component } from 'react'; import { StyleSheet, Text, View, Alert } from 'react-native';
Также импортируйте сторонние библиотеки, которые мы установили ранее:
import Pusher from 'pusher-js/react-native'; import MapView from 'react-native-maps'; import Geocoder from 'react-native-geocoding'; Geocoder.setApiKey('YOUR GOOGLE SERVER API KEY');
Наконец, импортировать помощники
файл:
import { regionFrom, getLatLonDiffInMeters } from './helpers';
помощники.js
Файл содержит следующее:
export function regionFrom(lat, lon, accuracy) { const oneDegreeOfLongitudeInMeters = 111.32 * 1000; const circumference = (40075 / 360) * 1000; const latDelta = accuracy * (1 / (Math.cos(lat) * circumference)); const lonDelta = (accuracy / oneDegreeOfLongitudeInMeters); return { latitude: lat, longitude: lon, latitudeDelta: Math.max(0, latDelta), longitudeDelta: Math.max(0, lonDelta) }; } export function getLatLonDiffInMeters(lat1, lon1, lat2, lon2) { var R = 6371; // Radius of the earth in km var dLat = deg2rad(lat2-lat1); // deg2rad below var dLon = deg2rad(lon2-lon1); var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon/2) * Math.sin(dLon/2) ; var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c; // Distance in km return d * 1000; } function deg2rad(deg) { return deg * (Math.PI/180) }
Эти функции используются для получения ценностей дельта-дельты широты и долготы, необходимые библиотекой NACT NOADY MAPS для отображения карты. Другая функция ( getLatlondiffinmers
) используется для определения расстояния в метрах между двумя координатами. Позже это позволит нам сообщить, что они уже рядом друг с другом или когда они возле своего назначения.
Далее создайте основной компонент приложений и заявляете, что заявляют о штатах по умолчанию:
export default class grabDriver extends Component { state = { passenger: null, // for storing the passenger info region: null, // for storing the current location of the driver accuracy: null, // for storing the accuracy of the location nearby_alert: false, // whether the nearby alert has already been issued has_passenger: false, // whether the driver has a passenger (once they agree to a request, this becomes true) has_ridden: false // whether the passenger has already ridden the vehicle } } // next: add constructor code
Внутри конструктора инициализируйте переменные, которые будут использоваться во всем приложении:
constructor() { super(); this.available_drivers_channel = null; // this is where passengers will send a request to any available driver this.ride_channel = null; // the channel used for communicating the current location // for a specific ride. Channel name is the username of the passenger this.pusher = null; // the pusher client } // next: add code for connecting to pusher
Перед установленным компонентом подключитесь к серверу auth, который вы создали ранее. Обязательно замените значения для клавиши толкателя, AuthencePoint
и кластер
Отказ
componentWillMount() { this.pusher = new Pusher('YOUR PUSHER KEY', { authEndpoint: 'YOUR PUSHER AUTH SERVER ENDPOINT', cluster: 'YOUR PUSHER CLUSTER', encrypted: true }); // next: add code for listening to passenger requests }
Теперь, когда вы подключили к серверу auth, теперь вы можете начать слушать запросы, исходящие из пассажирского приложения. Первый шаг – подписаться на Частный канал Отказ Этот канал находится в том, что все пассажиры и водители подписываются на. В этом случае его используются водителями для прослушивания запросов на поездки. Это должно быть частным каналом, потому что События клиента Может быть вызван только на частных каналах и присутствиях из-за соображений безопасности. Вы знаете, что это частный канал из-за частные-
приставка.
this.available_drivers_channel = this.pusher.subscribe('private-available-drivers'); // subscribe to "available-drivers" channel
Далее, слушай Клиент-водитель-запрос
мероприятие. Вы знаете, что это клиентское событие из-за клиент-
приставка. События клиента не требуют вмешательства сервера для работы, сообщения отправляются непосредственно от клиента клиенту. Вот почему нам нужен сервер auth, чтобы убедиться, что все пользователи, которые пытаются подключить, являются реальными пользователями приложения.
Возвращаясь к коду, мы слушаем клиентские события, позвонив привязывать
Метод на канале, который мы подписались и передаваем имя события в качестве первого аргумента. Второй аргумент – это функция, которую вы хотите выполнить, как только это событие срабатывает с другого клиента (от кого-либо используя пассажирское приложение, чтобы запросить поездку). В приведенном ниже коде мы показываем сообщение о предупреждении, спрашиваемое водителю, если они хотят принять пассажир. Обратите внимание, что приложение предполагает, что может быть только один пассажир в любое время.
// listen to the "driver-request" event this.available_drivers_channel.bind('client-driver-request', (passenger_data) => { if(!this.state.has_passenger){ // if the driver has currently no passenger // alert the driver that they have a request Alert.alert( "You got a passenger!", // alert title "Pickup: " + passenger_data.pickup.name + "\nDrop off: " + passenger_data.dropoff.name, // alert body [ { text: "Later bro", // text for rejecting the request onPress: () => { console.log('Cancel Pressed'); }, style: 'cancel' }, { text: 'Gotcha!', // text for accepting the request onPress: () => { // next: add code for when driver accepts the request } }, ], { cancelable: false } // no cancel button ); } });
Как только водитель соглашается забрать пассажир, мы подписываемся на свой частный канал. Этот канал зарезервирован только для связи между водителем и пассажиром, поэтому мы используем уникальное имя пользователя пассажира как часть имени канала.
this.ride_channel = this.pusher.subscribe('private-ride-' + passenger_data.username);
Не в отличие от Доступные водители
Канал, нам нужно будет слушать, когда подписка фактически удалась ( Pusher: подписку_suceeded
) Прежде чем мы сделаем все остальное. Это потому, что мы собираемся немедленно вызвать событие клиента, которое будет отправлено пассажиру. Это событие ( клиент-драйвер-ответ
) – это событие рукопожатия, чтобы пассажир знал, что водитель, которого они отправили их запрос, все еще доступно. Если пассажир по-прежнему не ездил в то время, пассажирское приложение вызывает то же событие, чтобы водитель знал, что они все еще доступны для подбора. На данный момент мы обновляем состояние так, чтобы пользовательские пользователи менялись соответственно.
this.ride_channel.bind('pusher:subscription_succeeded', () => { // send a handshake event to the passenger this.ride_channel.trigger('client-driver-response', { response: 'yes' // yes, I'm available }); // listen for the acknowledgement from the passenger this.ride_channel.bind('client-driver-response', (driver_response) => { if(driver_response.response == 'yes'){ // passenger says yes //passenger has no ride yet this.setState({ has_passenger: true, passenger: { username: passenger_data.username, pickup: passenger_data.pickup, dropoff: passenger_data.dropoff } }); // next: reverse-geocode the driver location to the actual name of the place }else{ // alert that passenger already has a ride Alert.alert( "Too late bro!", "Another driver beat you to it.", [ { text: 'Ok' }, ], { cancelable: false } ); } }); });
Далее мы используем библиотеку геокодирования, чтобы определить имя места, где водитель в настоящее время находится. За кулисами это использует API Google GeoCoding, и он обычно возвращает имя улицы. Как только мы получим ответ на ответ, мы вызываем найденный водитель
Событие, чтобы сообщить пассажиру, что приложение нашло для них драйвер. Это содержит информацию драйвера, такую как имя и текущее местоположение.
Geocoder.getFromLatLng(this.state.region.latitude, this.state.region.longitude).then( (json) => { var address_component = json.results[0].address_components[0]; // inform passenger that it has found a driver this.ride_channel.trigger('client-found-driver', { driver: { name: 'John Smith' }, location: { name: address_component.long_name, latitude: this.state.region.latitude, longitude: this.state.region.longitude, accuracy: this.state.accuracy } }); }, (error) => { console.log('err geocoding: ', error); } ); // next: add componentDidMount code
Как только компонент установлен, мы используем РЕАКТИРОВАТЬ НАРОДНОГО Геолокации API смотреть за обновления местоположения. Функция, которую вы переходите к Вид на видимость
Функция выполняется каждый раз, когда изменения местоположения.
componentDidMount() { this.watchId = navigator.geolocation.watchPosition( (position) => { var region = regionFrom( position.coords.latitude, position.coords.longitude, position.coords.accuracy ); // update the UI this.setState({ region: region, accuracy: position.coords.accuracy }); if(this.state.has_passenger && this.state.passenger){ // next: add code for sending driver's current location to passenger } }, (error) => this.setState({ error: error.message }), { enableHighAccuracy: true, // allows you to get the most accurate location timeout: 20000, // (milliseconds) in which the app has to wait for location before it throws an error maximumAge: 1000, // (milliseconds) if a previous location exists in the cache, how old for it to be considered acceptable distanceFilter: 10 // (meters) how many meters the user has to move before a location update is triggered }, ); }
Далее отправьте текущее местоположение водителя в пассажир. Это обновит UI в приложении пассажира, чтобы показать текущее местоположение драйвера. Вы увидите, как приложение пассажира связывается с этим событием позже, когда мы перейдем к кодированию пассажирского приложения.
this.ride_channel.trigger('client-driver-location', { latitude: position.coords.latitude, longitude: position.coords.longitude, accuracy: position.coords.accuracy });
Далее мы хотим сообщить как пассажир, так и водитель, что они уже рядом друг с другом. Для этого мы используем getlatlondiffinmers
Функция из помощники.js
файл для определения количества метров между пассажиром и водителем. Поскольку водитель уже получил местоположение пассажира, когда они приняли запрос, это только вопрос получения текущего местоположения водителя и передает его на Гетланондифторметры
Функция, чтобы получить разницу в метрах. Оттуда мы просто информируем водитель или пассажир на основе количества метров. Позже вы увидите, как эти события принимаются в пассажирском приложении.
var diff_in_meter_pickup = getLatLonDiffInMeters( position.coords.latitude, position.coords.longitude, this.state.passenger.pickup.latitude, this.state.passenger.pickup.longitude); if(diff_in_meter_pickup <= 20){ if(!this.state.has_ridden){ // inform the passenger that the driver is very near this.ride_channel.trigger('client-driver-message', { type: 'near_pickup', title: 'Just a heads up', msg: 'Your driver is near, let your presence be known!' }); /* we're going to go ahead and assume that the passenger has rode the vehicle at this point */ this.setState({ has_ridden: true }); } }else if(diff_in_meter_pickup <= 50){ if(!this.state.nearby_alert){ this.setState({ nearby_alert: true }); /* since the location updates every 10 meters, this alert will be triggered at least five times unless we do this */ Alert.alert( "Slow down", "Your passenger is just around the corner", [ { text: 'Gotcha!' }, ], { cancelable: false } ); } } // next: add code for sending messages when near the destination
На данный момент мы предполагаем, что водитель поднял пассажир и что теперь они направляются в пункт назначения. Так что на этот раз мы получаем расстояние между текущим местоположением и точкой выпадания. После того, как они 20 метров до точки высадки, приложение водителя отправляет сообщение пассажиру, что они очень близки к месту назначения. Как только это сделано, мы предполагаем, что пассажир сойдет через несколько секунд. Поэтому мы развиваем события, которые мы слушаем и отписываемся от частного канала пассажира. Это эффективно режет соединение между приложением водителя и пассажира. Единственное соединение, которое остается открытым, это Доступные водители
канал.
var diff_in_meter_dropoff = getLatLonDiffInMeters( position.coords.latitude, position.coords.longitude, this.state.passenger.dropoff.latitude, this.state.passenger.dropoff.longitude); if(diff_in_meter_dropoff <= 20){ this.ride_channel.trigger('client-driver-message', { type: 'near_dropoff', title: "Brace yourself", msg: "You're very close to your destination. Please prepare your payment." }); // unbind from passenger event this.ride_channel.unbind('client-driver-response'); // unsubscribe from passenger channel this.pusher.unsubscribe('private-ride-' + this.state.passenger.username); this.setState({ passenger: null, has_passenger: false, has_ridden: false }); } // next: add code for rendering the UI
UI для приложения водителя отображается только карта и маркеры для водителя и пассажира.
render() { return ({ this.state.region && ); } // next: add code when component unmounts} { this.state.passenger && !this.state.has_ridden && }
Перед компонентами размонтирует, мы остановим наблюдателя местоположения, позвонив на ClearWatch
Метод:
componentWillUnmount() { navigator.geolocation.clearWatch(this.watchId); }
Наконец, добавьте стили:
const styles = StyleSheet.create({ container: { ...StyleSheet.absoluteFillObject, justifyContent: 'flex-end', alignItems: 'center', }, map: { ...StyleSheet.absoluteFillObject, }, });
Создание пассажирского приложения
Приложение пассажирского пассажира будет довольно похоже на приложение водителя, поэтому я больше не буду учитывать детали на деталях, которые похожи. Продолжай и создайте новое приложение:
react-native init grabClone
Установка зависимостей
Тебе также нужно будет установить те же библиотеки плюс еще пару:
npm install --save pusher-js react-native-geocoding github:geordasche/react-native-google-place-picker react-native-loading-spinner-overlay react-native-maps
Два других библиотеки Google Place Picker и Загрузка прядильника наложения Отказ Хотя мы использовали Вилка Из сборщика Google Place из-за проблемы совместимости с реактивными нативными картами, которые еще не были зафиксированы в оригинальном репо.
Поскольку мы установили те же библиотеки, вы можете вернуться в раздел, где мы выполнили дополнительную конфигурацию для работы библиотеки. Вернитесь здесь, как только вы сделаете это.
Затем сборщик Google Place также нужна дополнительная конфигурация для нее для работы. Во-первых, откройте Android/app/src/main/java/com/grabclone/mainapplication.java
Файл и добавьте следующее ниже последнего импорта:
import com.reactlibrary.RNGooglePlacePickerPackage;
Добавьте библиотеку, которую вы просто импортировали под GetPackages ()
функция. Пока вы там, также убедитесь, что Mappackage ()
перечислены также.
protected ListgetPackages() { return Arrays. asList( new MainReactPackage(), new MapsPackage(), new RNGooglePlacePickerPackage() // <- add this ); }
Далее откройте Android/Settings.gradle
Файл и добавьте это прямо над включить ': приложение'
Директива:
include ':react-native-google-place-picker' project(':react-native-google-place-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-google-place-picker/android')
Пока вы там, также убедитесь, что ресурсы для реагирования нативных отображений также добавлены:
include ':react-native-maps' project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/lib/android')
Далее откройте Android/App/build.gradle
Файл и добавьте следующее под зависимости
:
dependencies { compile project(':react-native-google-place-picker') // <- add this }
Наконец, убедитесь, что реагирование нативные карты также скомпилированы:
compile project(':react-native-maps')
Кодирование пассажирского приложения
Открыть index.android.js
Файл и добавьте следующее:
import { AppRegistry } from 'react-native'; import App from './App'; AppRegistry.registerComponent('grabClone', () => App);
Так же, как приложение водителя, он также использует App.js
как основной компонент. Продолжай и импортируйте библиотеки. Это также использует то же самое помощники.js
Файл, чтобы вы могли скопировать его из приложения водителя.
import React, { Component } from 'react'; import { StyleSheet, Text, View, Button, Alert } from 'react-native'; import Pusher from 'pusher-js/react-native'; import RNGooglePlacePicker from 'react-native-google-place-picker'; import Geocoder from 'react-native-geocoding'; import MapView from 'react-native-maps'; import Spinner from 'react-native-loading-spinner-overlay'; import { regionFrom, getLatLonDiffInMeters } from './helpers'; Geocoder.setApiKey('YOUR GOOGLE SERVER API KEY');
Создайте компонент и заявляйте состояния по умолчанию:
export default class App extends Component { state = { location: null, // current location of the passenger error: null, // for storing errors has_ride: false, // whether the passenger already has a driver which accepted their request destination: null, // for storing the destination / dropoff info driver: null, // the driver info origin: null, // for storing the location where the passenger booked a ride is_searching: false, // if the app is currently searching for a driver has_ridden: false // if the passenger has already been picked up by the driver }; // next: add constructor code }
Чтобы сохранить вещи простыми, мы объявляем имя пользователя пассажира в конструкторе. Мы также инициализируем каналы толкателя:
constructor() { super(); this.username = 'wernancheta'; // the unique username of the passenger this.available_drivers_channel = null; // the pusher channel where all drivers and passengers are subscribed to this.user_ride_channel = null; // the pusher channel exclusive to the passenger and driver in a given ride this.bookRide = this.bookRide.bind(this); // bind the function for booking a ride } // next: add bookRide() function
Bookride ()
Функция выполняется, когда пользовательские краны на кнопке «Поездка книги». Это открывает сортирую место, которое позволяет пользователю выбирать пункт назначения. Как только местоположение будет выбрано, приложение отправляет запрос на проезд во всех драйверов. Как вы видели в приложении водителя ранее, это вызывает оповещение, чтобы показать в приложении водителя, который спрашивает, хочет ли водитель принять запрос или нет. В этот момент загрузчик будет продолжать вращаться до тех пор, пока водитель не примет запрос.
bookRide() { RNGooglePlacePicker.show((response) => { if(response.didCancel){ console.log('User cancelled GooglePlacePicker'); }else if(response.error){ console.log('GooglePlacePicker Error: ', response.error); }else{ this.setState({ is_searching: true, // show the loader destination: response // update the destination, this is used in the UI to display the name of the place }); // the pickup location / origin let pickup_data = { name: this.state.origin.name, latitude: this.state.location.latitude, longitude: this.state.location.longitude }; // the dropoff / destination let dropoff_data = { name: response.name, latitude: response.latitude, longitude: response.longitude }; // send a ride request to all drivers this.available_drivers_channel.trigger('client-driver-request', { username: this.username, pickup: pickup_data, dropoff: dropoff_data }); } }); } // next: add _setCurrentLocation() function
_SetcurrentLocation ()
Функция получает текущее местоположение пассажира. Обратите внимание, что здесь мы используем GetCurrentPosition ()
в отличие от Видимость ()
который мы использовали в приложении водителя ранее. Единственная разница между ними в том, что GetCurrentPosition ()
Только получают место один раз.
_setCurrentLocation() { navigator.geolocation.getCurrentPosition( (position) => { var region = regionFrom( position.coords.latitude, position.coords.longitude, position.coords.accuracy ); // get the name of the place by supplying the coordinates Geocoder.getFromLatLng(position.coords.latitude, position.coords.longitude).then( (json) => { var address_component = json.results[0].address_components[0]; this.setState({ origin: { // the passenger's current location name: address_component.long_name, // the name of the place latitude: position.coords.latitude, longitude: position.coords.longitude }, location: region, // location to be used for the Map destination: null, has_ride: false, has_ridden: false, driver: null }); }, (error) => { console.log('err geocoding: ', error); } ); }, (error) => this.setState({ error: error.message }), { enableHighAccuracy: false, timeout: 10000, maximumAge: 3000 }, ); } // next: add componentDidMount() function
Когда компонент монтируется, мы хотим установить текущее местоположение пассажира, подключиться к серверу AUTH AUTH и подписывайтесь на два канала: доступные драйверы и личный канал пассажира для связи только с водителем, в котором был отправлен запрос на поездки.
componentDidMount() { this._setCurrentLocation(); // set current location of the passenger // connect to the auth server var pusher = new Pusher('YOUR PUSHER API KEY', { authEndpoint: 'YOUR AUTH SERVER ENDPOINT', cluster: 'YOUR PUSHER CLUSTER', encrypted: true }); // subscribe to the available drivers channel this.available_drivers_channel = pusher.subscribe('private-available-drivers'); // subscribe to the passenger's private channel this.user_ride_channel = pusher.subscribe('private-ride-' + this.username); // next: add code for listening to handshake responses }
Далее добавьте код для прослушивания ответа рукопожатия водителем. Это отправляется из приложения водителя, когда водитель принимает запрос на поездку. Это позволяет нам убедиться, что пассажир все еще ищет поездку. Если пассажир отвечает «да», то это единственное время, когда водитель отправляет свою информацию.
this.user_ride_channel.bind('client-driver-response', (data) => { let passenger_response = 'no'; if(!this.state.has_ride){ // passenger is still looking for a ride passenger_response = 'yes'; } // passenger responds to driver's response this.user_ride_channel.trigger('client-driver-response', { response: passenger_response }); }); // next: add listener for when a driver is found
Драйвер отправляет свою информацию, вызвав Найденный клиент-драйвер
мероприятие. Как вы видели в приложении водителя ранее, это содержит имя драйвера, а также их текущее местоположение.
this.user_ride_channel.bind('client-found-driver', (data) => { // the driver's location info let region = regionFrom( data.location.latitude, data.location.longitude, data.location.accuracy ); this.setState({ has_ride: true, // passenger has already a ride is_searching: false, // stop the loading UI from spinning location: region, // display the driver's location in the map driver: { // the driver location details latitude: data.location.latitude, longitude: data.location.longitude, accuracy: data.location.accuracy } }); // alert the passenger that a driver was found Alert.alert( "Orayt!", "We found you a driver. \nName: " + data.driver.name + "\nCurrent location: " + data.location.name, [ { text: 'Sweet!' }, ], { cancelable: false } ); }); // next: add code for listening to driver's current location
На данный момент пассажир теперь может слушать изменения местоположения от водителя. Мы просто обновляем UI каждый раз, когда это событие срабатывает:
this.user_ride_channel.bind('client-driver-location', (data) => { let region = regionFrom( data.latitude, data.longitude, data.accuracy ); // update the Map to display the current location of the driver this.setState({ location: region, // the driver's location driver: { latitude: data.latitude, longitude: data.longitude } }); });
Далее – это событие, которое запускается на конкретные экземпляры. Это главная цель – отправить обновления пассажиру в отношении расположения водителя ( refer_pickup
), а также, когда они уже рядом с местоположением выпадают ( refer_dropoff
).
this.user_ride_channel.bind('client-driver-message', (data) => { if(data.type == 'near_pickup'){ // the driver is very near the pickup location // remove passenger marker since we assume that the passenger has rode the vehicle at this point this.setState({ has_ridden: true }); } if(data.type == 'near_dropoff'){ // they're near the dropoff location this._setCurrentLocation(); // assume that the ride is over, so reset the UI to the current location of the passenger } // display the message sent from the driver app Alert.alert( data.title, data.msg, [ { text: 'Aye sir!' }, ], { cancelable: false } ); }); // next: render the UI
Уэй, состоящий из загрузки спина (видимый только тогда, когда приложение ищет драйвер), заголовок, кнопка для бронирования поездки, местоположение пассажира ( происхождение
) и их назначение, а также карта, которая изначально отображается Текущее местоположение пользователя, а затем отображает текущее местоположение драйвера после того, как поездка была забронирована.
render() { return (); } { !this.state.has_ride && GrabClone } { this.state.origin && this.state.destination && } { this.state.location && Origin: {this.state.origin.name} Destination: {this.state.destination.name} { this.state.origin && !this.state.has_ridden && }} { this.state.driver && }
Наконец, добавьте стили:
const styles = StyleSheet.create({ container: { ...StyleSheet.absoluteFillObject, justifyContent: 'flex-end' }, form_container: { flex: 1, justifyContent: 'center', padding: 20 }, header: { padding: 20, backgroundColor: '#333', }, header_text: { color: '#FFF', fontSize: 20, fontWeight: 'bold' }, origin_destination: { alignItems: 'center', padding: 10 }, label: { fontSize: 18 }, text: { fontSize: 18, fontWeight: 'bold', }, map_container: { flex: 9 }, map: { flex: 1 }, });
Запуск приложения
Теперь вы готовы запустить приложение. Как я уже упоминал в Предпосылки Раздел ранее, вы собираетесь необязательно нужны две машины, один для запуска каждого из приложений. Это позволит вам включить ведение журнала ( Console.log
) для обоих. Но если у вас есть только одна машина, то вам нужно запустить их в определенном порядке: Passenger App сначала и затем приложение водителя.
Продолжайте и подключите устройство Android к компьютеру и запустите следующую команду:
react-native run-android
Это будет компилировать, установить и запустить приложение на вашем устройстве. Как только его запустите, завершите наблюдение и отсоедините свое устройство с компьютера.
Далее открывайте Genymotion и запустите устройство, которое вы установили ранее. На этот раз запустите приложение водителя. Как только приложение запускается, вы увидите пустой экран. Это нормально, потому что приложение нужно место для того, чтобы что-то сделать. Вы можете сделать это, нажав на «GPS», расположенный на верхней правой части эмулятора UI, затем включите GPS.
Вы также можете нажать на кнопку карты и выберите определенное местоположение, если хотите:
Как только вы выбрали местоположение, карта UI в приложении должна показать то же место, которое вы выбрали.
Далее вы можете теперь выполнить шаги на Поток приложения раздел ранее. Обратите внимание, что вы можете эмулировать движущееся транспортное средство, щелкнув вокруг интернет-интерфейса MENYMOTION. Если пассажир уже забронировал поездку, и водитель принял запрос, он должен начать обновлять как пассажирское приложение, так и приложение драйвера текущего местоположения драйвера.
Если вы используете две машины, то вы можете просто запустить React - родной Run-Android
на обоих. Один должен быть подключен к вашему устройству, а другой должен открывать эмулятор геньмоции.
Заключение
Это оно! В этом руководстве вы узнали, как использовать Pusher, чтобы создать приложение для бронирования езды. Как вы видели, приложение, которое вы построили, довольно голые кости. Мы придерживаемся только для создания самых важных частей приложения для бронирования езды. Если вы хотите, вы можете добавить больше функций в приложение и, возможно, использовать его в своих собственных проектах. Вы можете найти исходный код, используемый в этом приложении на его Github Repo Отказ
Первоначально опубликовано на Pusher Blog Отказ