DEV Community

Cover image for Erstellen Sie Ihre eigene Uber/Lyft App mit Geolocation Tracking
PubNub Developer Relations for PubNub [Deutsch]

Posted on

Erstellen Sie Ihre eigene Uber/Lyft App mit Geolocation Tracking

In diesem Beitrag aus unseren Archiven erklären wir, wie man einen eigenen Uber- oder Lyft-Klon erstellt und dabei PubNub zur Verfolgung der Fahrzeugposition verwendet. Auch wenn einige der Codeschnipsel auf ältere Bibliotheksversionen verweisen, ist alles in diesem Artikel für das heutige Publikum geeignet

Die Verfolgung des Echtzeit-Standortes eines anderen Geräts ist die Grundlage vieler beliebter mobiler, standortbezogener Apps, insbesondere wenn es um

wie Lyft und Uber. Der Aufbau dieser Funktionalität ist eine Herausforderung und kann mühsam sein, aber wir werden es mit einem einfachen Publish/Subscribe-Modell zwischen Fahrern und Fahrgästen vereinfachen, das von PubNub unterstützt wird.

Tutorial-Übersicht

Dervollständige Quellcode für dieses Tutorial ist hier verfügbar.

In diesem Tutorial zeigen wir Ihnen, wie Sie diesen häufigen Anwendungsfall in einer Android-Anwendung implementieren können. In der Beispielanwendung, die wir erstellen werden, wird der Benutzer zunächst gefragt, ob er der Fahrer oder der Beifahrer ist. Wenn ein Benutzer ein Fahrer ist, wird sein aktueller Standort in einem Kanal veröffentlicht und alle 5 Sekunden (in diesem Beispiel) oder so oft, wie es Ihre Anwendung erfordert, aktualisiert.

Ist ein Benutzer ein Beifahrer, abonniert er denselben Kanal, um Aktualisierungen des aktuellen Standorts seines Fahrers zu erhalten. Dieses Veröffentlichungs-/Abonnementmodell ist in der folgenden Abbildung dargestellt.

Uber/Lyft App

Google Maps API und PubNub-Einrichtung

Zunächst müssen wir unsere Gradle-Abhängigkeiten schreiben, um das PubNub Android SDK und die Google Play Services für die Kartenfunktionalität zu nutzen. Wir werden auch

com.fasterxml.jackson
Enter fullscreen mode Exit fullscreen mode

Bibliotheken implementieren, um einige grundlegende JSON-Parsing von PubNub-Nachrichten zu vervollständigen .

Geben Sie in der build.gradle-Datei für das App-Modul unter dependencies den Codeblock des folgenden Befehls ein, um sicherzustellen, dass wir alles haben, was wir brauchen. Stellen Sie sicher, dass Google Play Services über den Android SDK Manager im Tools-Teil des Menüs installiert ist, damit wir die erforderlichen Bibliotheken implementieren können.

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'
Enter fullscreen mode Exit fullscreen mode

Jetzt, da wir die notwendigen Abhängigkeiten haben, müssen wir sicherstellen, dass wir die notwendigen Berechtigungen in unserer Android Manifest-Datei haben. Mit der Erlaubnis, auf den Netzwerkstatus zuzugreifen und eine Internetverbindung herzustellen, kann der Benutzer nun die Verbindung zur PubNub-API herstellen. Wir werden die Standortberechtigung später verwenden, wenn wir den Standort des Fahrers abfragen.

<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"/>
Enter fullscreen mode Exit fullscreen mode

Um PubNub in Ihrer Android-App einzurichten, müssen Sie eine PubNub-App im PubNub Admin Dashboard erstellen (kostenlos). Nach der Erstellung der App werden Ihnen ein Abonnement- und ein Veröffentlichungsschlüssel zugewiesen. Im folgenden Teil werden wir diese Anmeldeinformationen in unserer MainActivity-Klasse verwenden, um die Verbindung herzustellen.

Nun müssen wir unseren Google Maps API-Schlüssel einrichten, damit wir ihn in unserer Anwendung verwenden können. Rufen Sie dazu die Google Developer API-Konsole auf. Hier erstellen wir ein neues Projekt und generieren dann einen API-Schlüssel. Jetzt, da wir unseren API-Schlüssel haben, können wir den folgenden Code schreiben, um unsere Google Maps-API einzurichten und sie mit unserem generierten API-Schlüssel zu konfigurieren.

<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" />
Enter fullscreen mode Exit fullscreen mode

Hauptaktivität

Die Klasse MainActivity wird drei wichtige Funktionen haben:

  1. Sie leitet den Benutzer zu seiner jeweiligen Schnittstelle, je nachdem, ob er Fahrer oder Beifahrer ist.
  2. Herstellen einer Verbindung zu PubNub für alle Benutzer der App
  3. Überprüfung der Zugriffsrechte für den Standort

Zunächst wollen wir unsere Nutzer in Fahrer und Beifahrer unterteilen und ihnen ihre jeweilige Benutzeroberfläche zur Verfügung stellen. Dazu erstellen wir eine Klasse DriverActivity und eine Klasse PassengerActivity, die wir in Teil 2 und Teil 3 ausführlich besprechen werden.

In MainActivity werden wir eine einfache, auf Schaltflächen basierende Schnittstelle erstellen, die den Benutzer auffordert, der App seine Rolle als Fahrer oder Beifahrer mitzuteilen. Mithilfe der Intent-Klasse von Android können wir von der MainActivity-Klasse in die DriverActivity-Klasse oder von der MainActivity-Klasse in die PassengerActivity-Klasse übergehen, je nachdem, welche Schaltfläche gedrückt wird.

Die Schnittstelle wird wie folgt aussehen:

screenshot

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));
   }
});
Enter fullscreen mode Exit fullscreen mode

Als Nächstes erstellen wir mit unseren PubNub-Anmeldeinformationen aus dem Admin Dashboard eine

PNConfiguration
Enter fullscreen mode Exit fullscreen mode

-Instanz, mit der wir eine

PubNub
Enter fullscreen mode Exit fullscreen mode

-Instanz erstellen können ,die unsere App und PubNub verbindet. Diese PubNub-Instanz in der Klasse MainActivity wird öffentlich und statisch sein, damit sie sowohl von der DriverActivity als auch von der PassengerActivity aus zugänglich ist. Wir werden die untenstehende Methode in unserer

onCreate()
Enter fullscreen mode Exit fullscreen mode

Methode der MainActivityaufrufen , damit PubNub für alle Benutzer unserer App richtig initialisiert wird. Dies alles ist im folgenden Code dargestellt.

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);
    }
Enter fullscreen mode Exit fullscreen mode

Zum Schluss müssen wir sicherstellen, dass unser Benutzer seine Standortdienste für unsere App aktiviert hat. Dies kann mit folgendem Code geschehen. Wenn unser Benutzer keine Erlaubnis für den Zugriff auf den Fein- oder Grobstandort erteilt, wird unsere App diese Erlaubnis anfordern.

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);
   }
}
Enter fullscreen mode Exit fullscreen mode

Fahrer-Aktivität

Die einzige Aufgabe der Klasse DriverActivity besteht darin, den Standort des Fahrers zu ermitteln und diese Daten in einem bestimmten Zeitintervall im PubNub-Kanal zu veröffentlichen.

Schauen wir uns zunächst an, wie man eine Standortabfrage durchführt. Wir werden die Klasse

FusedLocationProviderClient
Enter fullscreen mode Exit fullscreen mode

aus der Google Location API verwenden , umStandortaktualisierungen vom Fahrer anzufordern. Außerdem verwenden wir die Klasse

LocationRequest
Enter fullscreen mode Exit fullscreen mode

, umwichtige Parameter unserer Standortanforderung festzulegen, z. B. die Priorität, den kleinsten Abstand und das Zeitintervall .

Für unser Beispiel verwenden wir ein Zeitintervall von 5000 Millisekunden, so dass der Standort alle 5 Sekunden aktualisiert wird, und eine kleinste Verschiebung von 10 Metern, um sicherzustellen, dass der Standort nur dann aktualisiert wird, wenn eine Änderung von mindestens 10 Metern vorliegt. Schließlich soll die Standortabfrage das GPS des Mobilgeräts verwenden, um eine hochgenaue Standortbestimmung zu ermöglichen. Diese hohe Genauigkeit ist wichtig, damit der Fahrgast eine detaillierte Anzeige seines Fahrers (dargestellt als Fahrzeugsymbol) sehen kann, der sich über die Karte zum Zielort bewegt.

LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(5000);
locationRequest.setSmallestDisplacement(10);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
Enter fullscreen mode Exit fullscreen mode

Nachdem wir nun unsere Parameter für die Standortanforderung definiert haben, werden wir dieses LocationRequest-Objekt an die Anforderung unseres FusedLocationProviderClient-Objekts für Standortaktualisierungen weitergeben.

mFusedLocationClient.requestLocationUpdates(locationRequest, new LocationCallback() {
   @Override
   public void onLocationResult(LocationResult locationResult) {
       Location location = locationResult.getLastLocation();
...
Enter fullscreen mode Exit fullscreen mode

Mit dem Standort, den wir von unserer Anfrage erhalten, müssen wir ihn in eine LinkedHashMap umwandeln, damit er in das gewünschte Format einer Standortnachricht im PubNub-Kanal passt. Die LinkedHashMap hat zwei Schlüssel "lat" und "lng" und die entsprechenden Werte für diese Schlüssel, beide als Strings.

Jetzt, da unsere Nachricht im Format einer LinkedHashMap vorliegt, können wir sie im PubNub-Kanal veröffentlichen. Dies wird im folgenden Code gezeigt. Beachten Sie, dass wir

MainActivity.pubnub
Enter fullscreen mode Exit fullscreen mode

verwenden müssen, um die PubNub-Instanz zu erhalten, die wir zuvor in der onCreate-Methode der Main Activity erstellt haben. Wir wollen nicht mehrere Verbindungen aufbauen, indem wir PubNub erneut initialisieren. Stattdessen verwenden wir einfach die Verbindung, die wir bereits in der Klasse MainActivity erstellt haben.

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());
           }
       });
Enter fullscreen mode Exit fullscreen mode

Passenger-Aktivität

In unserer Klasse PassengerActivity wollen wir eine MapView erstellen, um den Standort des Fahrers anzuzeigen, der gerade aktualisiert wird. Um das MapView-UI-Element zu unserer PassengerActivity hinzuzufügen, müssen wir den folgenden Code in die entsprechende layout.xml-Datei für diese Activity aufnehmen.

<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" />
Enter fullscreen mode Exit fullscreen mode

Anschließend instanziieren Sie das Objekt

MapFragment
Enter fullscreen mode Exit fullscreen mode

unter Verwendung der in der Layout-Datei definierten ID. In unserem Beispielcode haben wir "map" als ID verwendet. Wir werden auch unsere Methode

onMapReady
Enter fullscreen mode Exit fullscreen mode

ein richten, indem wir PassengerActivity

onMapReadyCallback
Enter fullscreen mode Exit fullscreen mode

implementieren lassen. Dann übergeben wir

PassengerActivity.this
Enter fullscreen mode Exit fullscreen mode

als Parameter an die Methode

getMapAsync
Enter fullscreen mode Exit fullscreen mode

unseres MapFragment-Objekts . Dies ermöglicht uns die Einrichtung unserer onMapReady-Callback-Methode für unser MapFragment-Objekt.

mMapFragment = (SupportMapFragment) getSupportFragmentManager()
       .findFragmentById(R.id.map);
mMapFragment.getMapAsync(PassengerActivity.this);
Enter fullscreen mode Exit fullscreen mode

Nun wollen wir den Standortkanal des Fahrers abonnieren, damit wir Aktualisierungen des aktuellen Standorts des Fahrers erhalten. Dies muss geschehen, sobald die Karte bereit ist, also werden wir diesen Code in unsere Callback-Methode aufnehmen. Außerdem müssen wir einen Listener mit einem

SubscribeCallback
Enter fullscreen mode Exit fullscreen mode

hinzufügen, damit unsere Anwendung weiß, wie sie beim Empfang einer Nachricht reagieren soll.

Wie in den PubNub-Android-Dokumenten beschrieben, müssen wir dies in der Reihenfolge tun, in der wir zuerst den Listener hinzufügen und dann die PubNub-Instanz für den Kanal abonnieren. Sobald wir eine Nachricht erhalten, wollen wir die JSON-Ausgabe in eine LinkedHashMap konvertieren, die wir leicht parsen können, um den Längen- und Breitengrad zu erhalten. Um die JSON-Ausgabe in eine LinkedHashMap zu konvertieren, müssen wir die Klasse

JsonUtil
Enter fullscreen mode Exit fullscreen mode

importieren , die die Methode

fromJson()
Enter fullscreen mode Exit fullscreen mode

enthält , die uns dies ermöglicht. Diese Klasse ist im vollständigen Quellcode dargestellt. Sobald wir den Standort des Fahrers haben, müssen wir die Benutzeroberfläche aktualisieren, indem wir unsere Methode

updateUI()
Enter fullscreen mode Exit fullscreen mode

aufrufen und den neuen Standort als Parameter übergeben .

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();
Enter fullscreen mode Exit fullscreen mode

Unsere updateUI-Methode hat zwei Fälle, auf die sie treffen wird.

Der erste Fall ist, dass es noch keine Markierung für den Fahrer gibt. In diesem Fall instanziieren wir das Objekt

Marker
Enter fullscreen mode Exit fullscreen mode

und setzen seine Position auf den ersten getrackten Standort des Fahrers. Außerdem müssen wir die Karte vergrößern, um eine Straßenansicht des Fahrzeugs des Fahrers zu erhalten.

Der zweite Fall ist, dass es bereits eine Markierung für den Fahrer gibt. In diesem Fall müssen wir das Markierungsobjekt nicht erneut instanziieren. In diesem Fall müssen wir das Marker-Objekt nicht neu instanziieren, sondern wir verschieben einfach die Position des Markers auf der Karte an seine neue Position. Dies geschieht durch den Aufruf der Methode

animateCar()
Enter fullscreen mode Exit fullscreen mode

. Wir müssen auch sicherstellen, dass wir die Kamera der MapView an die neue Position verschieben, wenn sie sich außerhalb der Grenzen der Kamera befindet. Auf diese Weise befindet sich der Marker des Fahrers immer innerhalb der Grenzen der MapView. Dies wird im folgenden Code gezeigt.

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)));
        }
    }
Enter fullscreen mode Exit fullscreen mode

In unserer animateCar-Methode müssen wir unseren Auto-Marker in einer sanften, linienförmigen Weise an seine neue Position bewegen. Die Animation muss 5 Sekunden dauern, da unsere App alle 5 Sekunden eine Aktualisierung der Position des Fahrers erhält. Auf diese Weise wird jedes Mal, wenn die Animation vorbei ist, die neue Position aktualisiert, um die nächste Animation zu starten. Auf diese Weise minimieren wir die Verzögerung bei der Animation des Autos.

Wir werden auch die

LatLngInterpolator
Enter fullscreen mode Exit fullscreen mode

Schnittstelle unten. Dies ermöglicht uns die Implementierung der Methode

interpolate()
Enter fullscreen mode Exit fullscreen mode

implementieren, die eine neue LatLng-Koordinate zurückgibt, die einen Bruchteil des Weges zur endgültigen newLocation darstellt. Dieser Bruchteil wird mit der Methode

getAnimatedFraction()
Enter fullscreen mode Exit fullscreen mode

. Wir rufen diese Methode von einer

ValueAnimator
Enter fullscreen mode Exit fullscreen mode

Instanz auf, die wir von der

onAnimationUpdate()
Enter fullscreen mode Exit fullscreen mode

Callback-Methode erhalten. Dieser Anteil steigt stetig an, so dass er nach 5 Sekunden 1 ist (bis zum neuen Standort). Diese Animation des Autos wird in den folgenden Codeschnipseln gezeigt.

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();
    }
Enter fullscreen mode Exit fullscreen mode
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);
           }
       }
   }
Enter fullscreen mode Exit fullscreen mode

Weitere Verbesserungen

Wenn Sie dieses Beispiel weiterentwickeln möchten, könnten Sie z. B. eine Funktion hinzufügen, bei der sich der Marker dreht, wenn sich das Auto dreht. Diese Funktion würde erfordern, dass wir ein Schlüssel-Wert-Paar zu unserer Nachrichtenstruktur hinzufügen. Wir müssten den Schlüssel "Peilung" und den Wert einfügen. Dann würden wir einfach die Markierung in Abhängigkeit von der Peilung des Fahrers drehen.

Herzlichen Glückwunsch!

Nun, da wir die MainActivity, DriverActivity und PassengerActivity erstellt haben, haben wir erfolgreich das Publish/Subscribe-Modell erstellt, das notwendig ist, um eine einfache Lyft/Uber Android-Demo zu erstellen. Klicken Sie hier für den vollständigen Quellcode.

Wenn der eingebettete Inhalt auf dieser Seite nicht verfügbar ist, kann er auch unter https://www.youtube.com/embed/kQ6EzqoQu5A angesehen werden.

Weitere Ressourcen

Wie kann PubNub Ihnen helfen?

Dieser Artikel wurde ursprünglich auf PubNub.com veröffentlicht.

Unsere Plattform unterstützt Entwickler bei der Erstellung, Bereitstellung und Verwaltung von Echtzeit-Interaktivität für Webanwendungen, mobile Anwendungen und IoT-Geräte.

Die Grundlage unserer Plattform ist das größte und am besten skalierbare Echtzeit-Edge-Messaging-Netzwerk der Branche. Mit über 15 Points-of-Presence weltweit, die 800 Millionen monatlich aktive Nutzer unterstützen, und einer Zuverlässigkeit von 99,999 % müssen Sie sich keine Sorgen über Ausfälle, Gleichzeitigkeitsgrenzen oder Latenzprobleme aufgrund von Verkehrsspitzen machen.

PubNub erleben

Sehen Sie sich die Live Tour an, um in weniger als 5 Minuten die grundlegenden Konzepte hinter jeder PubNub-gestützten App zu verstehen

Einrichten

Melden Sie sich für einen PubNub-Account an und erhalten Sie sofort kostenlosen Zugang zu den PubNub-Schlüsseln

Beginnen Sie

Mit den PubNub-Dokumenten können Sie sofort loslegen, unabhängig von Ihrem Anwendungsfall oder SDK

Top comments (0)