Exemplarische Vorgehensweise – Hintergrundspeicherort in Xamarin.iOS
In diesem Beispiel erstellen wir eine iOS-Standortanwendung, die Informationen zu unserem aktuellen Standort druckt: Breitengrad, Längengrad und andere Parameter auf dem Bildschirm. Diese Anwendung veranschaulicht, wie Positionsaktualisierungen ordnungsgemäß ausgeführt werden, während die Anwendung entweder aktiv oder hintergrundiert ist.
In dieser exemplarischen Vorgehensweise werden einige wichtige Hintergrundkonzepte erläutert, z. B. das Registrieren einer App als Hintergrundanwendung, das Anhalten von UI-Updates beim Hintergrund und das Arbeiten mit den WillEnterBackground
Methoden WillEnterForeground
AppDelegate
.
Anwendungssetup
Erstellen Sie zunächst eine neue Einzelansichtsanwendung für iOS-Apps > > (C#). Rufen Sie den Standort an, und stellen Sie sicher, dass sowohl iPad als auch iPhone ausgewählt wurden.
Eine Standortanwendung qualifiziert sich als Hintergrundanwendung in iOS. Registrieren Sie die Anwendung als Speicherortanwendung, indem Sie die Info.plist-Datei für das Projekt bearbeiten.
Doppelklicken Sie unter Projektmappen-Explorer auf die Datei "Info.plist", um sie zu öffnen, und scrollen Sie zum Ende der Liste. Aktivieren Sie sowohl die Kontrollkästchen "Hintergrundmodi aktivieren" als auch die Kontrollkästchen "Positionsaktualisierungen" .
In Visual Studio für Mac sieht es wie folgt aus:
In Visual Studio muss Info.plist manuell aktualisiert werden, indem das folgende Schlüssel-Wert-Paar hinzugefügt wird:
<key>UIBackgroundModes</key> <array> <string>location</string> </array>
Nachdem die Anwendung registriert wurde, kann sie Standortdaten vom Gerät abrufen. In iOS wird die
CLLocationManager
Klasse für den Zugriff auf Standortinformationen verwendet und kann Ereignisse auslösen, die Standortupdates bereitstellen.Erstellen Sie im Code eine neue Klasse, die einen
LocationManager
zentralen Ort für verschiedene Bildschirme und Code zum Abonnieren von Positionsupdates bereitstellt. Erstellen Sie in derLocationManager
Klasse eine Instanz desCLLocationManager
aufgerufenenLocMgr
Elements:public class LocationManager { protected CLLocationManager locMgr; public LocationManager () { this.locMgr = new CLLocationManager(); this.locMgr.PausesLocationUpdatesAutomatically = false; // iOS 8 has additional permissions requirements if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) { locMgr.RequestAlwaysAuthorization (); // works in background //locMgr.RequestWhenInUseAuthorization (); // only in foreground } if (UIDevice.CurrentDevice.CheckSystemVersion (9, 0)) { locMgr.AllowsBackgroundLocationUpdates = true; } } public CLLocationManager LocMgr { get { return this.locMgr; } } }
Der obige Code legt eine Reihe von Eigenschaften und Berechtigungen für die CLLocationManager-Klasse fest:
PausesLocationUpdatesAutomatically
– Dies ist ein boolescher Wert, der abhängig davon festgelegt werden kann, ob das System Positionsupdates anhalten darf. Auf einigen Geräten wirdtrue
standardmäßig festgelegt, was dazu führen kann, dass das Gerät nach ca. 15 Minuten keine Aktualisierung der Hintergrundspeicherorte mehr erhält.RequestAlwaysAuthorization
– Sie sollten diese Methode übergeben, um dem App-Benutzer die Möglichkeit zu geben, den Zugriff auf den Speicherort im Hintergrund zu ermöglichen.RequestWhenInUseAuthorization
kann auch übergeben werden, wenn Sie dem Benutzer die Möglichkeit geben möchten, den Zugriff auf den Standort nur zuzulassen, wenn sich die App im Vordergrund befindet.AllowsBackgroundLocationUpdates
– Dies ist eine boolesche Eigenschaft, die in iOS 9 eingeführt wurde und so festgelegt werden kann, dass eine App Positionsupdates empfangen kann, wenn sie angehalten wird.
Wichtig
iOS 8 (und höher) erfordert auch einen Eintrag in der Datei Info.plist , um den Benutzer als Teil der Autorisierungsanforderung anzuzeigen.
Fügen Sie Info.plist-Schlüssel für die Berechtigungstypen hinzu,
NSLocationWhenInUseUsageDescription
die die App erfordert –NSLocationAlwaysUsageDescription
, und/oderNSLocationAlwaysAndWhenInUseUsageDescription
– mit einer Zeichenfolge, die dem Benutzer in der Warnung angezeigt wird, die den Zugriff auf Standortdaten anfordert.iOS 9 erfordert, dass bei Verwendung
AllowsBackgroundLocationUpdates
der Info.plist den SchlüsselUIBackgroundModes
mit dem Wertlocation
enthält. Wenn Sie Schritt 2 dieser exemplarischen Vorgehensweise abgeschlossen haben, sollte dies bereits in Der Datei "Info.plist" enthalten sein.Erstellen Sie innerhalb der
LocationManager
Klasse eine Methode, die mit dem folgenden Code aufgerufen wirdStartLocationUpdates
. Dieser Code zeigt, wie Sie mit dem Empfangen von Positionsupdates aus demCLLocationManager
:if (CLLocationManager.LocationServicesEnabled) { //set the desired accuracy, in meters LocMgr.DesiredAccuracy = 1; LocMgr.LocationsUpdated += (object sender, CLLocationsUpdatedEventArgs e) => { // fire our custom Location Updated event LocationUpdated (this, new LocationUpdatedEventArgs (e.Locations [e.Locations.Length - 1])); }; LocMgr.StartUpdatingLocation(); }
In dieser Methode gibt es mehrere wichtige Dinge. Zunächst führen wir eine Überprüfung durch, um festzustellen, ob die Anwendung Zugriff auf Standortdaten auf dem Gerät hat. Wir überprüfen dies durch Aufrufen
LocationServicesEnabled
derCLLocationManager
. Diese Methode gibt "false" zurück, wenn der Benutzer die Anwendung den Zugriff auf Standortinformationen verweigert hat.Informieren Sie als Nächstes den Standort-Manager, wie oft aktualisiert werden soll.
CLLocationManager
bietet viele Optionen zum Filtern und Konfigurieren von Standortdaten, einschließlich der Häufigkeit von Updates. Legen Sie in diesem Beispiel dieDesiredAccuracy
Aktualisierung fest, wenn sich die Position um einen Meter ändert. Weitere Informationen zum Konfigurieren der Standortaktualisierungshäufigkeit und anderer Einstellungen finden Sie in der Apple-Dokumentation in der CLLocationManager-Klassenreferenz .Rufen Sie schließlich die
CLLocationManager
Instanz aufStartUpdatingLocation
. Dadurch wird der Standortmanager aufgefordert, einen anfänglichen Fix für den aktuellen Speicherort zu erhalten und mit dem Senden von Updates zu beginnen.
Bisher wurde der Standort-Manager erstellt, mit den Arten von Daten konfiguriert, die wir empfangen möchten, und hat den ursprünglichen Standort bestimmt. Jetzt muss der Code die Standortdaten auf der Benutzeroberfläche rendern. Wir können dies mit einem benutzerdefinierten Ereignis tun, das ein CLLocation
Argument akzeptiert:
// event for the location changing
public event EventHandler<LocationUpdatedEventArgs>LocationUpdated = delegate { };
Der nächste Schritt besteht darin, Standortaktualisierungen von dem CLLocationManager
Ereignis zu abonnieren und das benutzerdefinierte LocationUpdated
Ereignis auszuheben, wenn neue Standortdaten verfügbar werden, wobei der Speicherort als Argument übergeben wird. Erstellen Sie dazu eine neue Klasse LocationUpdateEventArgs.cs. Auf diesen Code kann innerhalb der Hauptanwendung zugegriffen werden und gibt den Gerätespeicherort zurück, wenn das Ereignis ausgelöst wird:
public class LocationUpdatedEventArgs : EventArgs
{
CLLocation location;
public LocationUpdatedEventArgs(CLLocation location)
{
this.location = location;
}
public CLLocation Location
{
get { return location; }
}
}
Benutzeroberfläche
Verwenden Sie den Xcode-Schnittstellen-Generator, um den Bildschirm zu erstellen, auf dem Standortinformationen angezeigt werden. Doppelklicken Sie auf die Datei "Main.storyboard ", um zu beginnen.
Ziehen Sie auf dem Storyboard mehrere Beschriftungen auf den Bildschirm, um als Platzhalter für die Positionsinformationen zu fungieren. In diesem Beispiel gibt es Bezeichnungen für Breitengrad, Längengrad, Höhe, Kurs und Geschwindigkeit.
Weitere Informationen finden Sie unter Entwerfen von Benutzeroberflächen mit Xcode.
Doppelklicken Sie auf dem Lösungspad auf die
ViewController.cs
Datei, und bearbeiten Sie sie, um eine neue Instanz des LocationManager zu erstellen und darauf aufzurufenStartLocationUpdates
. Ändern Sie den Code so, dass er wie folgt aussieht:#region Computed Properties public static bool UserInterfaceIdiomIsPhone { get { return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone; } } public static LocationManager Manager { get; set;} #endregion #region Constructors public ViewController (IntPtr handle) : base (handle) { // As soon as the app is done launching, begin generating location updates in the location manager Manager = new LocationManager(); Manager.StartLocationUpdates(); } #endregion
Dadurch werden die Positionsupdates beim Starten der Anwendung gestartet, obwohl keine Daten angezeigt werden.
Nachdem die Positionsupdates empfangen wurden, aktualisieren Sie den Bildschirm mit den Standortinformationen. Die folgende Methode ruft den Ort aus unserem
LocationUpdated
Ereignis ab und zeigt ihn in der Benutzeroberfläche an:#region Public Methods public void HandleLocationChanged (object sender, LocationUpdatedEventArgs e) { // Handle foreground updates CLLocation location = e.Location; LblAltitude.Text = location.Altitude + " meters"; LblLongitude.Text = location.Coordinate.Longitude.ToString (); LblLatitude.Text = location.Coordinate.Latitude.ToString (); LblCourse.Text = location.Course.ToString (); LblSpeed.Text = location.Speed.ToString (); Console.WriteLine ("foreground updated"); } #endregion
Wir müssen das LocationUpdated
Ereignis weiterhin in unserem AppDelegate abonnieren und die neue Methode aufrufen, um die Benutzeroberfläche zu aktualisieren. Fügen Sie den folgenden Code ViewDidLoad,
direkt hinter dem StartLocationUpdates
Aufruf hinzu:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// It is better to handle this with notifications, so that the UI updates
// resume when the application re-enters the foreground!
Manager.LocationUpdated += HandleLocationChanged;
}
Wenn die Anwendung ausgeführt wird, sollte sie nun etwa wie folgt aussehen:
Behandeln von Aktiven und Hintergrundzuständen
Die Anwendung gibt Positionsaktualisierungen aus, während sie sich im Vordergrund und aktiv befindet. Um zu veranschaulichen, was passiert, wenn die App in den Hintergrund wechselt, überschreiben Sie die
AppDelegate
Methoden, mit denen anwendungszustandsänderungen nachverfolgt werden, damit die Anwendung in die Konsole schreibt, wenn sie zwischen Vordergrund und Hintergrund wechselt:public override void DidEnterBackground (UIApplication application) { Console.WriteLine ("App entering background state."); } public override void WillEnterForeground (UIApplication application) { Console.WriteLine ("App will enter foreground"); }
Fügen Sie den
LocationManager
folgenden Code zum fortlaufenden Drucken aktualisierter Positionsdaten zur Anwendungsausgabe hinzu, um sicherzustellen, dass die Standortinformationen weiterhin im Hintergrund verfügbar sind:public class LocationManager { public LocationManager () { ... LocationUpdated += PrintLocation; } ... //This will keep going in the background and the foreground public void PrintLocation (object sender, LocationUpdatedEventArgs e) { CLLocation location = e.Location; Console.WriteLine ("Altitude: " + location.Altitude + " meters"); Console.WriteLine ("Longitude: " + location.Coordinate.Longitude); Console.WriteLine ("Latitude: " + location.Coordinate.Latitude); Console.WriteLine ("Course: " + location.Course); Console.WriteLine ("Speed: " + location.Speed); } }
Es gibt ein weiteres Problem mit dem Code: Wenn Sie versuchen, die Benutzeroberfläche zu aktualisieren, wenn die App hintergrund ist, wird sie von iOS beendet. Wenn die App in den Hintergrund wechselt, muss der Code das Abonnement von Positionsupdates kündigen und die Aktualisierung der Benutzeroberfläche beenden.
iOS stellt uns Benachrichtigungen bereit, wenn die App zu einem anderen Anwendungsstatus wechselt. In diesem Fall können wir die
ObserveDidEnterBackground
Benachrichtigung abonnieren.Der folgende Codeausschnitt zeigt, wie Sie eine Benachrichtigung verwenden, um die Ansicht darüber zu informieren, wann Ui-Updates angehalten werden sollen. Dies wird in
ViewDidLoad
:UIApplication.Notifications.ObserveDidEnterBackground ((sender, args) => { Manager.LocationUpdated -= HandleLocationChanged; });
Wenn die App ausgeführt wird, sieht die Ausgabe ungefähr wie folgt aus:
Die Anwendung druckt Positionsaktualisierungen auf dem Bildschirm, wenn sie im Vordergrund ausgeführt werden, und druckt weiterhin Daten in das Anwendungsausgabefenster, während sie im Hintergrund ausgeführt werden.
Nur ein noch ausstehendes Problem bleibt bestehen: Der Bildschirm startet UI-Updates, wenn die App zum ersten Mal geladen wird, hat aber keine Möglichkeit zu wissen, wann die App erneut in den Vordergrund gelangt ist. Wenn die hintergrundgeschaltete Anwendung wieder in den Vordergrund gebracht wird, werden UI-Updates nicht fortgesetzt.
Um dies zu beheben, schachteln Sie einen Aufruf, um UI-Updates in einer anderen Benachrichtigung zu starten, was ausgelöst wird, wenn die Anwendung in den aktiven Zustand wechselt:
UIApplication.Notifications.ObserveDidBecomeActive ((sender, args) => {
Manager.LocationUpdated += HandleLocationChanged;
});
Jetzt beginnt die Benutzeroberfläche, wenn die Anwendung zum ersten Mal gestartet wird, zu aktualisieren und die Aktualisierung fortzusetzen, wenn die App wieder im Vordergrund angezeigt wird.
In dieser exemplarischen Vorgehensweise haben wir eine gut verhaltene, hintergrundfähige iOS-Anwendung erstellt, die Standortdaten sowohl auf dem Bildschirm als auch im Anwendungsausgabefenster druckt.