Статьи

Как разработать приложение на основе местоположения с использованием React Native

Откуда Убер всегда знает место выдачи? Или как Tinder может найти даты в радиусе двух миль от вас? Все просто — вы позволили им узнать ваше местоположение.

Основанные на местоположении приложения используют местоположения клиентов, чтобы функционировать и управлять различными функциями. От доставки пиццы и такси до Find My iPhone и отображения расписания автобусов, приложения, основанные на местоположении, помогали нам в выполнении наших повседневных задач.

Местоположение может быть либо основной функцией, как в Uber, либо вспомогательной, как в Facebook — она ​​всегда сообщает вам, когда рядом с вами приближается предстоящее событие. Является ли это основной функцией или нет, местоположение помогает улучшить взаимодействие с пользователем.

Разработать приложение на основе местоположения

В этой статье мы расскажем вам об основных компонентах приложений, основанных на местоположении, и о том, как их разработать с использованием инфраструктуры React Native. Сначала мы изучим, что такое React Native, и сравним его с разработкой собственных приложений. Затем мы поделимся подходами к сбору и отображению местоположения в приложении. И, наконец, мы рассмотрим проблемы проектирования и пути их решения.

Инструменты для разработки сервисов на основе местоположения: Native vs. React Native

React Native — это JavaScript-инфраструктура с открытым исходным кодом, созданная Facebook, которая позволяет разработчикам создавать кроссплатформенные приложения с их собственным поведением.

Что мы подразумеваем под поведением? Позволь мне объяснить. iOS и Android разные — они выглядят по-разному, их кнопки разные, общие жесты разные. Разработка приложения для iOS и Android потребует создания двух отдельных приложений. Раньше это занимало много времени, но теперь мы можем написать единую базу кода, и она будет хорошо работать на обеих платформах.

Это помогает компаниям предлагать свои приложения пользователям iOS и Android, что увеличивает потенциальную клиентскую базу. React Native — популярный выбор для новых компаний, которые не могут позволить себе создавать два отдельных приложения или не уверены, использует ли их аудитория iOS или Android. Принимая во внимание, что  кроссплатформенный рынок, вероятно, вырастет до 80 миллиардов долларов к 2020 году , для многих компаний имеет смысл выбрать React Native.

Теперь мы переходим к плюсам и минусам React Native. Это не всемогущий и всемогущий фреймворк, но есть определенные случаи, когда вы должны его использовать.

Реагируйте Родные Плюсы

  • Кросс-платформенный.  Вместо написания отдельной базы кода для каждой платформы вы можете использовать один и тот же код для iOS и Android. Это также означает, что вам не нужно проектировать различные пользовательские интерфейсы и пользовательские интерфейсы.
  • Высокая производительность.  React Native использует собственные элементы управления и модули. Он взаимодействует с нативными компонентами iOS и Android и выводит код на нативный API. Основным здесь является собственный API — использование отдельного потока от пользовательского интерфейса повышает производительность приложения.
  • Открытый источник.  Сообщество React Native быстро растет, как и количество доступных компонентов. Это позволяет разработчикам делиться своим опытом, улучшать среду, находить решения для существующих ошибок и, следовательно, ускорять процесс разработки.
  • Это экономит деньги.  В результате трех предыдущих пунктов использование React Native экономит ваши деньги. Это быстрее, чем создание двух отдельных приложений, и на тестирование и выпуск MVP уходит меньше времени.

Однако есть несколько причин, по которым вы можете не использовать React Native. Они включают:

  • Вам не нужно кроссплатформенное приложение.  Если вы знаете, какую ОС использует ваша аудитория, я предлагаю вам использовать нативную разработку. Во-первых, приложение будет адаптировано под специфику выбранной ОС, а во-вторых, вы сможете использовать функции, специфичные для платформы.
  • Вам нужен доступ к большему количеству API, чем может предложить React Native.  Фреймворк не поддерживает все API нативной платформы. Одной из основных причин, по которой многие предпочитают нативный код, является независимость от сторонних сервисов, потому что все можно получить с помощью нативных сред.

говоря о реакции родного

Как собрать и отобразить местоположение пользователя

В этой части мы расскажем вам о способах сбора и отображения данных о местоположении. Выбор обычно зависит от особенностей разрабатываемого приложения.

Сбор данных о местоположении

Мы укажем три способа собрать местоположение пользователя. Это общий обзор для вас, чтобы понять, когда выбрать для каждого и различия между ними.

Используйте React Native API

Существует  собственный API-интерфейс JavaScript  для определения геолокации устройства. Он прост в установке и использовании, но есть некоторые недостатки — он работает только во время работы приложения и не дает информацию о провайдере местоположения (3G, Wi-Fi, GPS).

реагируют-родной-фон-геолокации

Это пакет, который может указывать местоположение устройства от 0 до 1000 метров (0,6 мили). Такая точность требует большего расхода батареи, но, с другой стороны, вы можете настроить частоту отслеживания местоположения. Этот пакет позволяет вам интегрироваться с SQLite, чтобы вы могли сохранять записанные данные о местоположении на мобильном устройстве и затем синхронизировать их с вашей базой данных через HTTP.

import { NativeModules, DeviceEventEmitter, PermissionsAndroid } from 'react-native'  
import Config from 'react-native-config'  
import get from 'lodash/get'  
const { GeoLocation } = NativeModules

class BackgroundGeoLocation {  
  constructor(token, user_id) {
    this.state = null
  }
  start(dispatch, nextState) {
    this.dispatch = dispatch
    const token = get(nextState, 'session.data.token')
    const user_id = get(nextState, 'user.data.user_id')
    const id = get(nextState, 'user.data.id')
    this.state = {
      user_id,
      token,
    }

    return PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION)
      .then(is_granted => is_granted === PermissionsAndroid.RESULTS.GRANTED
        ? is_granted
        : PermissionsAndroid.requestMultiple([
          PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
          PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,
        ])
      )
      .then(_ => PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION))
      .then(is_granted => is_granted === PermissionsAndroid.RESULTS.GRANTED ? true : new Error())
      .then(_ => setTimeout(() => GeoLocation.startService(token, user_id, id, `${Config.API_URL}/live/car-tracking/gps-pos/`), 300))
      .catch(e => console.log(e))
  }
  stop() {
    return GeoLocation.stopService()
      .then(_ => console.log(_))
  }

  handleLocationChange(geo) {
    console.log(geo)
  }
}

export default BackgroundGeoLocation

Поскольку это пакет, его необходимо регулярно поддерживать и обновлять. К счастью, его создатель предлагает поддержку через GitHub. Этот пакет бесплатный для iOS, но стоит $ 300 для Android за одно приложение.

Соединить собственный код с JavaScript API

Чтобы решить проблему с фоновым отслеживанием при использовании собственного API-интерфейса JavaScript, вы можете написать собственный код, который будет запускать службу переднего плана в отдельном потоке. Это именно то, что мы сделали, когда  разрабатывали продукт для доставки еды, Азян . Частично, мы выбрали этот путь, потому что React Native позволил легко связать нативный код с компонентами React Native.

package com.djangostars.azyan;

import android.app.Notification;  
import android.app.NotificationChannel;  
import android.app.NotificationManager;  
import android.content.Context;  
import android.content.Intent;  
import android.content.pm.PackageManager;  
import android.location.Criteria;  
import android.location.Location;  
import android.location.LocationManager;  
import android.os.Build;  
import android.support.v4.content.ContextCompat;

import com.facebook.react.bridge.Arguments;  
import com.facebook.react.bridge.Promise;  
import com.facebook.react.bridge.ReactApplicationContext;  
import com.facebook.react.bridge.ReactContextBaseJavaModule;  
import com.facebook.react.bridge.ReactMethod;  
import com.facebook.react.bridge.WritableMap;  
import com.facebook.react.bridge.WritableNativeMap;


/**
 * Created by AGulchenko on 5/7/18.
 */

public class GeoLocationModule extends ReactContextBaseJavaModule {  
    public static final String CHANNEL_ID = "ExampleService_Channel";
    public GeoLocationModule(ReactApplicationContext reactContext) {
        super(reactContext);
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,"testName", NotificationManager.IMPORTANCE_DEFAULT);
            NotificationManager manager = reactContext.getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }

    @Override
    public String getName() {
        return "GeoLocation";
    }

    @ReactMethod
    public void startService(String token, String user_id, String id, String url_string, Promise promise) {
        WritableMap result = Arguments.createMap();
        result.putString("ststus", "success");
        try {
            Intent serviceIntent = new Intent(getReactApplicationContext(), GeoLocationService.class);
            serviceIntent.putExtra("token", token);
            serviceIntent.putExtra("user_id", user_id);
            serviceIntent.putExtra("id", id);
            serviceIntent.putExtra("url_string", url_string);
            getReactApplicationContext().startService(serviceIntent);
            promise.resolve(result);
        } catch (Exception e) {
            e.printStackTrace();
            promise.reject("rrrrr",e);
            return;
        }

    }

    @ReactMethod
    public void stopService(Promise promise) {
        String result = "Success";
        try {
            Intent serviceIntent = new Intent(getReactApplicationContext(), GeoLocationService.class);
            getReactApplicationContext().stopService(serviceIntent);
        } catch (Exception e) {
            promise.reject(e);
            return;
        }
        promise.resolve(result);
    }

    @ReactMethod
    public void getLocation( Promise promise) {
        WritableMap res = Arguments.createMap();
        try {
            LocationManager locationManager = null;

            locationManager = (LocationManager) this.getReactApplicationContext().getSystemService(Context.LOCATION_SERVICE);
            int permissionCheck = ContextCompat.checkSelfPermission(this.getReactApplicationContext(),
                    android.Manifest.permission.ACCESS_FINE_LOCATION);
            if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                Criteria criteria = new Criteria();
                String bestProvider = locationManager.getBestProvider(criteria, false);
                Location location = locationManager.getLastKnownLocation(bestProvider);
                if(location != null) {
                    res.putDouble("latitude", location.getLatitude());
                    res.putDouble("longitude", location.getLongitude());
                    promise.resolve(res);
                }

            }
        } catch (Exception e) {
            promise.reject(e);
            return;
        }
    }
}

Разрешение на доступ к данным о местоположении

Несмотря на необходимость обновления React Native с помощью собственного кода, мы решили продолжать использовать React Native для облегчения получения разрешения на использование информации о местоположении. Вот почему это может вызвать проблемы.

Разные платформы могут требовать разрешения для доступа к данным о местоположении на разных этапах: в iOS разрешение запрашивается при первом запуске приложения; на Android запрашивается при загрузке приложения. Если вы используете нативный код, мы должны принять это во внимание. Но React Native упрощает этот процесс, используя проверку доступа к модулю данных о местоположении. Он проверяет доступ к данным о местоположении, не вызывая предупреждение о разрешении.

Отображение местоположения

Если не подходить осторожно, данные о местоположении могут отображаться неточно. Устройство собирает данные о своем текущем местоположении из трех источников: GPS, Wi-Fi и сотовой сети (3G, 4G). Поскольку данные Wi-Fi и сотовой связи точнее, чем GPS (сигнал от устройства к спутнику может быть искажен), устройство постоянно проверяет, есть ли подключение к Интернету. Если это так, данные о местоположении поступают из него. Если нет, он использует GPS. При получении неточных данных мы можем наблюдать зигзаги на карте, а не прямые линии. Это выглядит примерно так:

Неточная геолокация

Чтобы решить эту проблему, мы предлагаем вам использовать Fused Location Client от Google. Позволяет установить время и расстояние, на котором обновляются данные о местоположении; например, обновлять данные каждые 100 метров, каждые 5 секунд. Вы избавитесь от зашумленных данных, так как этот API сопоставляет все местоположения устройств с дорогами и тротуарами. Однако, если устройство находится где-то в Тихом океане или в Альпах, оно может быть не таким эффективным.

Неточная геолокация

Клиент Fused Location Client позволяет не отображать определенные местоположения, в которых точность ниже установленного порога. Такая настройка приводит к снижению шума и более точному отображению местоположений.

Несколько слов о дизайне

В этом кратком разделе мы рассмотрим препятствия, которые обычно возникают при разработке приложения на основе определения местоположения, и способы преодоления этих препятствий React Native.

React Native предоставляет простые подходы к отображению карт. Компоненты React Native UI для Material Design позволяют разработчикам работать быстрее и с меньшими усилиями. Мы использовали Material Design для создания оболочки Google Maps, а затем React Native адаптировал их к специфике каждой платформы.

Бесконечный список — это функция React Native, которая создает бесконечный список результатов поиска. В Uber бесконечный список появляется, когда вы начинаете вводить точку назначения. Если вы начнете печатать 3 Ave, он покажет все третьи авеню вокруг вас. Список на самом деле не бесконечен; просто он загружает больше результатов поиска, когда пользователи прокручивают страницу вниз.

<FlatList  
        data={get(props, 'order.data.items', [])}
        renderItem={listItem}
        keyExtractor={({ id }) => id}
        style={style.list}
      />

function listItem({ item: { quantity, name } }) {  
  return (
    <View style={style.main}>
      <Text style={[style.count, style.listItemText]}>{quantity}</Text>
      <Text style={[style.listItemText, style.name]}>{name}</Text>
    </View>
  )
}

В React Native есть готовый компонент интерфейса, Flat List, который имеет фиксированный заголовок, нижний колонтитул и разделители. Создание таких списков с нуля занимает много времени, поэтому React Native является правильным выбором для этой функции.

Нижняя граница

Мы изучили, почему React Native может быть правильным выбором, если вы собираетесь создавать приложение на основе определения местоположения. Мы также определили основные методы сбора и отображения местоположения на устройстве.

Мы перечислили основные преимущества разработки приложения с использованием React Native. Если большинство из них верны для вас, мы предлагаем вам глубже исследовать технологию и ее возможности.

Теперь мы рекомендуем вам уделять больше внимания приложениям, которые используют местоположение устройства. Вы можете быть удивлены тем, что большинство известных вам приложений просят предоставить им доступ к вашему местоположению. Для многих предприятий очень важно знать ваше местоположение, чтобы предоставить лучший сервис. Google, Facebook, Airbnb, Amazon — все они используют местоположение в качестве основы для некоторых своих функций: где искать, где остановиться, куда отправлять. При правильном использовании данные о местоположении позволяют сделать сервис более ориентированным на пользователя и эффективным.