Créez votre propre application Uber/Lyft avec suivi de géolocalisation
Published: 2024-02-22 07:51:25

**Dans cet article tiré de nos archives, nous expliquons comment créer votre propre clone d'Uber ou de Lyft, en utilisant PubNub pour suivre la position du véhicule. Bien que certains extraits de code fassent référence à d'anciennes versions de la bibliothèque, tout ce qui figure dans cet article est approprié pour le public d'aujourd'hui.**  
  

Le suivi de la position en temps réel d'un autre appareil est à la base de nombreuses applications mobiles populaires axées sur la localisation, en particulier lorsqu'il s'agit de construire des clones de Lyber ou de Lyft.

comme Lyft et Uber. Construire cette fonctionnalité est un défi et peut être fastidieux, mais nous allons le simplifier avec un modèle facile de publication/abonnement entre les conducteurs et les passagers, alimenté par PubNub.

Vue d'ensemble du tutoriel
--------------------------

**Le[code source complet](https://github.com/PubNubDevelopers/RealtimeTaxiAndroidDemo) de ce tutoriel est disponible ici.**

Dans ce tutoriel, nous allons vous montrer comment mettre en œuvre ce cas d'utilisation courant dans une application Android. L'exemple d'application que nous allons créer demande d'abord à l'utilisateur s'il est le conducteur ou le passager. Si l'utilisateur est le conducteur, sa position actuelle sera publiée sur un canal, mise à jour toutes les 5 secondes (dans cet exemple), ou le nombre de fois requis par votre application.

Si un utilisateur est un passager, il s'abonnera au même canal pour recevoir des mises à jour sur la position actuelle de son conducteur. Ce modèle de publication/abonnement est illustré dans le graphique ci-dessous.

[![Uber/Lyft App](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1j4o/69ed800cea3e73d95979e9cad4cbfb3b/Screen-Shot-2018-06-06-at-11.58.58-AM.png "Uber/Lyft App")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1j4o/69ed800cea3e73d95979e9cad4cbfb3b/Screen-Shot-2018-06-06-at-11.58.58-AM.png)

API Google Maps et configuration de PubNub
------------------------------------------

Nous devons d'abord écrire nos dépendances Gradle pour utiliser le [SDK Android PubNub](https://pubnub.com/docs/sdks/java/android/) et les services Google Play pour la fonctionnalité de carte. Nous allons également implémenter lesbibliothèques

```js
com.fasterxml.jackson
```

, afin de réaliser une analyse JSON de base des messages PubNub .

Dans le fichier build.gradle pour le module app sous dependencies, entrez le codeblock de la commande ci-dessous pour vous assurer que nous avons ce dont nous avons besoin. Assurez-vous que Google Play Services est installé à partir du gestionnaire SDK Android dans la partie outils du menu, afin que nous puissions implémenter les bibliothèques nécessaires.

```js
implementation group: 'com.pubnub', name: 'pubnub-gson', version: '4.12.0'
implementation 'com.google.android.gms:play-services-maps:15.0.1'
implementation "com.google.android.gms:play-services-location:15.0.1"
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.2'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.2'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.2'
```

Maintenant que nous avons les dépendances nécessaires, assurons-nous que nous avons les permissions nécessaires dans notre fichier Android Manifest. Avec la permission d'accéder à l'état du réseau et d'établir une connexion internet, l'utilisateur peut maintenant se connecter à l'API PubNub. Nous utiliserons la permission de localisation plus tard, lorsque nous demanderons la localisation du conducteur.

```js
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
```

Afin de configurer PubNub dans votre application Android, vous devez créer une application PubNub dans le [PubNub Admin Dashboard](https://dashboard.pubnub.com/signup/) **(c'est gratuit)**. Lors de la création de l'application, une clé de souscription et une clé de publication vous seront attribuées. Dans la partie suivante, nous utiliserons ces informations d'identification dans notre classe MainActivity pour établir la connexion.

Nous devons maintenant configurer notre clé API Google Maps, afin de pouvoir l'utiliser dans notre application. Pour ce faire, rendez-vous dans la [console Developer API de Google](https://console.cloud.google.com/projectselector2/apis/dashboard?supportedpurview=project). Nous y créerons un nouveau projet, puis nous générerons une clé API. Maintenant que nous avons notre clé API, nous pouvons écrire le code suivant pour mettre en place notre API Google Maps et la configurer avec notre clé API générée.

```js
<meta-data
   android:name="com.google.android.gms.version"
   android:value="@integer/google_play_services_version" />
<meta-data
   android:name="com.google.android.geo.API_KEY"
   android:value=”ENTER_KEY_HERE" />
```

Activité principale
-------------------

La classe MainActivity aura trois fonctionnalités importantes :

1.  Diriger l'utilisateur vers son interface respective, selon qu'il est conducteur ou passager.
2.  Établir une connexion à PubNub pour tous les utilisateurs de l'application.
3.  Vérifier les autorisations d'accès à la localisation

Tout d'abord, nous voulons séparer nos utilisateurs en conducteurs et passagers et leur fournir leur interface utilisateur respective. Pour ce faire, nous allons créer une classe DriverActivity et une classe PassengerActivity, dont nous parlerons en détail dans les parties 2 et 3.

Dans MainActivity, nous créerons une interface simple basée sur un bouton qui invitera l'utilisateur à indiquer à l'application son rôle en tant que conducteur ou passager. Grâce à la classe Intent d'Android, nous pouvons passer de la classe MainActivity à la classe DriverActivity ou de la classe MainActivity à la classe PassengerActivity, en fonction du bouton sur lequel l'utilisateur a appuyé.

L'interface se présentera comme suit :

[![screenshot](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1j4p/89ff1d0cceea0f257e1b66aacc1fa7a6/screenshot.png "screenshot")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1j4p/89ff1d0cceea0f257e1b66aacc1fa7a6/screenshot.png)

```js
driverButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       startActivity(new Intent(MainActivity.this, DriverActivity.class));
   }
});
passengerButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       startActivity(new Intent(MainActivity.this, PassengerActivity.class));
   }
});
```

Ensuite, en utilisant nos identifiants PubNub du [tableau de bord d'administration](https://dashboard.pubnub.com/signup), nous allons créer une instance

```js
PNConfiguration
```

, qui nous permet de créer une instance

```js
PubNub
```

connectant notre application et PubNub. Cette instance PubNub dans la classe MainActivity sera publique et statique afin d'être accessible à la fois depuis DriverActivity et PassengerActivity. Nous appellerons la méthode ci-dessous dans notre méthode

```js
onCreate()
```

de l'activité principale, afin que PubNub soit correctement initialisé pour tous les utilisateurs de notre application. Tout ceci est illustré dans le code suivant.

```js
private void initPubnub() {
        PNConfiguration pnConfiguration = new PNConfiguration();
        pnConfiguration.setSubscribeKey(Constants.PUBNUB_SUBSCRIBE_KEY);
        pnConfiguration.setPublishKey(Constants.PUBNUB_PUBLISH_KEY);
        pnConfiguration.setSecure(true);
        pubnub = new PubNub(pnConfiguration);
    }
```

Enfin, nous devons nous assurer que notre utilisateur a activé ses services de localisation pour notre application. Cela peut être fait avec le code suivant. Si l'utilisateur ne donne pas l'autorisation d'accéder à la localisation fine ou à la localisation grossière, notre application demandera cette autorisation.

```js
public void checkPermission() {
   if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
           ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
           ) {//Can add more as per requirement
       ActivityCompat.requestPermissions(this,
               new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION},
               123);
   }
}
```

Activité du conducteur
----------------------

La seule fonction de la classe DriverActivity est d'obtenir la position du conducteur et de publier ces données à un certain intervalle de temps sur le canal PubNub.

Tout d'abord, voyons comment effectuer une demande de localisation. Nous utiliserons laclasse

```js
FusedLocationProviderClient
```

de l'API de localisation de Google afin de demander au conducteur des mises à jour de sa position. Nous utiliserons également la classe

```js
LocationRequest
```

pour spécifier les paramètres importants de notre demande de localisation, tels que la priorité, le plus petit déplacement et l'intervalle de temps.

Pour notre exemple, nous utiliserons un intervalle de temps de 5000 millisecondes, de sorte que la localisation soit mise à jour toutes les 5 secondes, et un plus petit déplacement de 10 mètres pour s'assurer que la localisation n'est mise à jour que s'il y a un changement d'au moins 10 mètres. Enfin, nous voulons que la demande de localisation utilise le GPS de l'appareil mobile, pour un suivi de localisation de haute précision. Cette précision est importante pour permettre au passager de voir un affichage détaillé de son conducteur (représenté par l'icône de la voiture) se déplaçant sur la carte jusqu'à sa destination.

```js
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(5000);
locationRequest.setSmallestDisplacement(10);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
```

Maintenant que nous avons défini nos paramètres de demande de localisation, nous allons passer cet objet LocationRequest à notre objet FusedLocationProviderClient pour les mises à jour de localisation.

```js
mFusedLocationClient.requestLocationUpdates(locationRequest, new LocationCallback() {
   @Override
   public void onLocationResult(LocationResult locationResult) {
       Location location = locationResult.getLastLocation();
...
```

En utilisant l'emplacement que nous obtenons de notre demande, nous devons le convertir en un LinkedHashMap afin qu'il corresponde au format souhaité d'un message d'emplacement dans le canal PubNub. Le LinkedHashMap aura deux clés "lat" et "lng" et les valeurs correspondantes pour ces clés, toutes deux sous forme de chaînes.

Maintenant que notre message est au format LinkedHashMap, nous pouvons le publier sur le canal PubNub. C'est ce que montre le code suivant. Notez que nous devons utiliser

```js
MainActivity.pubnub
```

pour obtenir l'instance PubNub que nous avons précédemment dans la méthode onCreate de l'activité principale. Nous ne voulons pas établir plusieurs connexions en initialisant à nouveau PubNub. Au lieu de cela, nous utilisons simplement celle que nous avons déjà créée dans la classe MainActivity.

```js
MainActivity.pubnub.publish()
       .message(message)
       .channel(Constants.PUBNUB_CHANNEL_NAME)
       .async(new PNCallback<PNPublishResult>() {
           @Override
           public void onResponse(PNPublishResult result, PNStatus status) {
               // handle publish result, status always present, result if successful
               // status.isError() to see if error happened
               if (!status.isError()) {
                   System.out.println("pub timetoken: " + result.getTimetoken());
               }
               System.out.println("pub status code: " + status.getStatusCode());
           }
       });
```

Activité Passager
-----------------

Dans notre classe PassengerActivity, nous voulons créer une vue de carte pour montrer l'emplacement du conducteur mis à jour. Pour ajouter l'élément MapView à notre activité Passenger, nous devons inclure le code suivant dans le fichier layout.xml correspondant à cette activité.

```js
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/map"
   android:name="com.google.android.gms.maps.SupportMapFragment"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context="com.example.mapwithmarker.MapsMarkerActivity" />
```

Ensuite, instanciez l'objet

```js
MapFragment
```

en utilisant l'ID que nous avons défini dans le fichier de mise en page. Dans notre exemple de code, nous avons utilisé "map" comme ID. Nous allons également mettre en place notre méthode

```js
onMapReady
```

en demandant à PassengerActivity d'implémenter

```js
onMapReadyCallback
```

. Nous transmettrons ensuite

```js
PassengerActivity.this
```

en tant que paramètre à la méthode```js
getMapAsync
```

de notre objet MapFragment .Cela nous permet de configurer notre méthode de rappel onMapReady pour notre objet MapFragment.

```js
mMapFragment = (SupportMapFragment) getSupportFragmentManager()
       .findFragmentById(R.id.map);
mMapFragment.getMapAsync(PassengerActivity.this);
```

Nous voulons maintenant nous abonner au canal de localisation du conducteur afin de recevoir des mises à jour sur sa position actuelle. Cela doit être fait une fois que la carte est prête, nous inclurons donc ce code dans notre méthode de rappel. Deplus, nous devons ajouter un listener avec un

```js
SubscribeCallback
```

, afin que notre application sache comment agir lors de la réception d'un message .

Comme spécifié dans la documentation PubNub Android, nous devons effectuer ceci dans l'ordre où nous ajoutons d'abord le listener et ensuite souscrivons l'instance PubNub au canal. Une fois que nous avons reçu un message, nous voulons convertir la sortie JSON en un LinkedHashMap, que nous pouvons facilement analyser pour obtenir la longitude et la latitude. Pourconvertir la sortie JSON en LinkedHashMap, nous devons importer la classe

```js
JsonUtil
```

, qui contient la méthode

```js
fromJson()
```

qui nous permet de le faire.Cette classe est présentée dans le code source complet. Une fois que nous avons la position du conducteur, nous devons mettre à jour l'interface utilisateur en appelant notre méthode

```js
updateUI()
```

et en passant la nouvelle position en paramètre .

```js
MainActivity.pubnub.addListener(new SubscribeCallback() {
    @Override
    public void status(PubNub pub, PNStatus status) {
    }
    @Override
    public void message(PubNub pub, final PNMessageResult message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    Map<String, String> newLocation = JsonUtil.fromJson(message.getMessage().toString(), LinkedHashMap.class);
                    updateUI(newLocation);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    @Override
    public void presence(PubNub pub, PNPresenceEventResult presence) {
    }
});
MainActivity.pubnub.subscribe()
        .channels(Arrays.asList(Constants.PUBNUB_CHANNEL_NAME)) // subscribe to channels
        .execute();
```

Notre méthode updateUI rencontre deux cas de figure.

Dans lepremier cas, il n'existe pas encore de marqueur pour le conducteur. Dans ce cas, nous instancions l'objet

```js
Marker
```

et définissons sa position sur le premier emplacement suivi du conducteur. Nous devons également effectuer un zoom avant sur la carte afin de conserver une vue de la voiture du conducteur.

Dans le second cas, il existe déjà un marqueur pour le conducteur et, dans ce cas, il n'est pas nécessaire de réinstancier l'objet Marqueur. Nous déplaçons simplement l'emplacement du marqueur sur la carte vers son nouvel emplacement. Pour cefaire, nous appelons la méthode

```js
animateCar()
```

. Nous devons également nous assurer que nous déplaçons la caméra du MapView vers le nouvel emplacement, s'il est hors des limites de la caméra. Ainsi, le marqueur du conducteur sera toujours dans les limites du MapView. C'est ce que montre le code suivant.

```js
private void updateUI(Map<String, String> newLoc) {
        LatLng newLocation = new LatLng(Double.valueOf(newLoc.get("lat")), Double.valueOf(newLoc.get("lng")));
        if (driverMarker != null) {
            animateCar(newLocation);
            boolean contains = mGoogleMap.getProjection()
                    .getVisibleRegion()
                    .latLngBounds
                    .contains(newLocation);
            if (!contains) {
                mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(newLocation));
            }
        } else {
            mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
                    newLocation, 15.5f));
            driverMarker = mGoogleMap.addMarker(new MarkerOptions().position(newLocation).
                    icon(BitmapDescriptorFactory.fromResource(R.drawable.car)));
        }
    }
```

Dans notre méthode animateCar, nous devons déplacer notre marqueur de voiture vers son nouvel emplacement, d'une manière fluide et en forme de ligne. L'animation doit durer 5 secondes, car notre application reçoit des mises à jour de la position du conducteur toutes les 5 secondes. Ainsi, chaque fois que l'animation est terminée, la nouvelle position est mise à jour pour lancer l'animation suivante. De cette façon, nous minimisons le décalage dans l'animation de la voiture.

Nous utiliserons également l'interface

```js
LatLngInterpolator
```

ci-dessous. Celle-ci nous permet d'implémenter la méthode

```js
interpolate()
```

qui renvoie une nouvelle coordonnée LatLng correspondant à une fraction de la nouvelle position finale. Cette fraction est déterminée par la méthode

```js
getAnimatedFraction()
```

. Nous appellerons cette méthode à partir d'une instance

```js
ValueAnimator
```

que nous obtiendrons grâce à la méthode

```js
onAnimationUpdate()
```

méthode de rappel. Cette fraction augmentera à un rythme régulier de sorte qu'au bout de 5 secondes, elle sera de 1 (jusqu'au nouvel emplacement). Cette animation de la voiture est illustrée dans les extraits de code suivants.

```js
private void animateCar(final LatLng destination) {
        final LatLng startPosition = driverMarker.getPosition();
        final LatLng endPosition = new LatLng(destination.latitude, destination.longitude);
        final LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed();
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(5000); // duration 5 seconds
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                try {
                    float v = animation.getAnimatedFraction();
                    LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, endPosition);
                    driverMarker.setPosition(newPosition);
                } catch (Exception ex) {
                }
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }
        });
        valueAnimator.start();
    }
```

```js
private interface LatLngInterpolator {
       LatLng interpolate(float fraction, LatLng a, LatLng b);
       class LinearFixed implements LatLngInterpolator {
           @Override
           public LatLng interpolate(float fraction, LatLng a, LatLng b) {
               double lat = (b.latitude - a.latitude) * fraction + a.latitude;
               double lngDelta = b.longitude - a.longitude;
               if (Math.abs(lngDelta) > 180) {
                   lngDelta -= Math.signum(lngDelta) * 360;
               }
               double lng = lngDelta * fraction + a.longitude;
               return new LatLng(lat, lng);
           }
       }
   }
```

Améliorations supplémentaires
-----------------------------

Si vous souhaitez développer davantage cet exemple, vous pourriez ajouter une fonctionnalité qui consisterait à faire tourner le marqueur en même temps que la voiture. Pour ce faire, nous devrions ajouter une paire clé-valeur à la structure de notre message. Nous devrions inclure la clé "bearing" et la valeur. Il suffirait ensuite de faire pivoter le marqueur en fonction de l'orientation du conducteur.

Félicitations !
---------------

Maintenant que nous avons créé les activités MainActivity, DriverActivity et PassengerActivity, nous avons réussi à construire le modèle publish/subscribe nécessaire à la création d'une démo Android Lyft/Uber simple. Cliquez ici pour accéder au [code source complet](https://github.com/PubNubDevelopers/RealtimeTaxiAndroidDemo).

  
**Si le contenu intégré n'est pas disponible** sur cette page, il peut également être consulté à l'[adresse https://www.youtube.com/embed/kQ6EzqoQu5A](https://www.youtube.com/embed/kQ6EzqoQu5A).

Plus de ressources
------------------

-   [Devriez-vous ajouter une API de géolocalisation à votre application ?](https://www.pubnub.com/guides/should-you-add-a-geolocation-api-to-your-app/)
    
-   [Notre démo sur la géolocalisation](https://www.pubnub.com/demos/geolocation-demo/)
    
-   [Chemin des développeurs de la géolocalisation](https://www.pubnub.com/developers/geolocation-developer-path/)
    

Comment PubNub peut-il vous aider ?
===================================

Cet article a été publié à l'origine sur [PubNub.com](https://www.pubnub.com/blog/build-your-own-uber-lyft-app-geolocation-tracking-android/)

Notre plateforme aide les développeurs à construire, livrer et gérer l'interactivité en temps réel pour les applications web, les applications mobiles et les appareils IoT.

La base de notre plateforme est le réseau de messagerie en temps réel le plus grand et le plus évolutif de l'industrie. Avec plus de 15 points de présence dans le monde, 800 millions d'utilisateurs actifs mensuels et une fiabilité de 99,999 %, vous n'aurez jamais à vous soucier des pannes, des limites de concurrence ou des problèmes de latence causés par les pics de trafic.

Découvrez PubNub
----------------

Découvrez le [Live Tour](https://www.pubnub.com/tour/introduction/) pour comprendre les concepts essentiels de chaque application alimentée par PubNub en moins de 5 minutes.

S'installer
-----------

Créez un [compte PubNub](https://admin.pubnub.com/signup/) pour un accès immédiat et gratuit aux clés PubNub.

Commencer
---------

La [documentation PubNub](https://www.pubnub.com/docs) vous permettra de démarrer, quel que soit votre cas d'utilisation ou votre [SDK](https://www.pubnub.com/docs).