Procedura dettagliata - Percorso in background in Xamarin.iOS
In questo esempio si creerà un'applicazione location iOS che stampa informazioni sulla posizione corrente: latitudine, longitudine e altri parametri sullo schermo. Questa applicazione dimostrerà come eseguire correttamente gli aggiornamenti della posizione mentre l'applicazione è attiva o in background.
Questa procedura dettagliata illustra alcuni concetti di base chiave, tra cui la registrazione di un'app come applicazione in background, la sospensione degli aggiornamenti dell'interfaccia utente quando l'app è in background e l'uso dei WillEnterBackground
metodi e WillEnterForeground
AppDelegate
.
Configurazione dell'applicazione
Creare prima di tutto una nuova applicazione di visualizzazione singola per app iOS > > (C#). Chiama Location e assicurati che sia iPad che iPhone siano stati selezionati.
Un'applicazione location si qualifica come applicazione in background in iOS. Registrare l'applicazione come applicazione Location modificando il file Info.plist per il progetto.
In Esplora soluzioni fare doppio clic sul file Info.plist per aprirlo e scorrere fino alla fine dell'elenco. Selezionare entrambe le caselle di controllo Abilita modalità in background e Aggiornamenti percorso.
In Visual Studio per Mac avrà un aspetto simile al seguente:
In Visual Studio, Info.plist deve essere aggiornato manualmente aggiungendo la coppia chiave/valore seguente:
<key>UIBackgroundModes</key> <array> <string>location</string> </array>
Ora che l'applicazione è registrata, può ottenere i dati sulla posizione dal dispositivo. In iOS, la
CLLocationManager
classe viene usata per accedere alle informazioni sulla posizione e può generare eventi che forniscono aggiornamenti della posizione.Nel codice creare una nuova classe denominata
LocationManager
che fornisce un'unica posizione per varie schermate e codice per sottoscrivere gli aggiornamenti della posizione.LocationManager
Nella classe creare un'istanza diCLLocationManager
denominataLocMgr
: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; } } }
Il codice precedente imposta una serie di proprietà e autorizzazioni per la classe CLLocationManager :
PausesLocationUpdatesAutomatically
: valore booleano che può essere impostato a seconda che il sistema possa sospendere gli aggiornamenti della posizione. In un dispositivo per impostazione predefinita ètrue
, che può causare l'arresto dell'aggiornamento della posizione in background del dispositivo dopo circa 15 minuti.RequestAlwaysAuthorization
- Devi passare questo metodo per consentire all'utente dell'app di consentire l'accesso alla posizione in background.RequestWhenInUseAuthorization
può essere passato anche se vuoi dare all'utente la possibilità di consentire l'accesso alla posizione solo quando l'app è in primo piano.AllowsBackgroundLocationUpdates
: si tratta di una proprietà booleana, introdotta in iOS 9 che può essere impostata per consentire a un'app di ricevere gli aggiornamenti della posizione quando viene sospesa.
Importante
Anche iOS 8 (e versioni successive) richiede una voce nel file Info.plist per mostrare l'utente come parte della richiesta di autorizzazione.
Aggiungere chiavi Info.plist per i tipi di autorizzazione richiesti dall'app,
NSLocationAlwaysUsageDescription
,NSLocationWhenInUseUsageDescription
e/oNSLocationAlwaysAndWhenInUseUsageDescription
, con una stringa che verrà visualizzata all'utente nell'avviso che richiede l'accesso ai dati sulla posizione.iOS 9 richiede che quando si usa
AllowsBackgroundLocationUpdates
Info.plist includa la chiaveUIBackgroundModes
con il valorelocation
. Se hai completato il passaggio 2 di questa procedura dettagliata, questo dovrebbe essere già presente nel file Info.plist.All'interno della
LocationManager
classe creare un metodo denominatoStartLocationUpdates
con il codice seguente. Questo codice illustra come iniziare a ricevere gli aggiornamenti della posizione daCLLocationManager
: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 questo metodo sono presenti diversi aspetti importanti. Prima di tutto, viene eseguito un controllo per verificare se l'applicazione ha accesso ai dati sulla posizione nel dispositivo. Per verificare questa situazione, chiamare
LocationServicesEnabled
suCLLocationManager
. Questo metodo restituirà false se l'utente ha negato l'accesso dell'applicazione alle informazioni sulla posizione.In seguito, indicare al gestore della posizione la frequenza con cui eseguire l'aggiornamento.
CLLocationManager
offre molte opzioni per filtrare e configurare i dati sulla posizione, inclusa la frequenza degli aggiornamenti. In questo esempio impostare l'oggettoDesiredAccuracy
da aggiornare ogni volta che la posizione cambia di un contatore. Per altre informazioni sulla configurazione della frequenza di aggiornamento della posizione e altre preferenze, vedere le informazioni di riferimento sulla classe CLLocationManager nella documentazione di Apple.Infine, chiamare
StartUpdatingLocation
sull'istanzaCLLocationManager
di . Questo indica al gestore della posizione di ottenere una correzione iniziale nel percorso corrente e di iniziare a inviare gli aggiornamenti
Finora, il gestore della posizione è stato creato, configurato con i tipi di dati che si desidera ricevere e ha determinato la posizione iniziale. A questo punto, il codice deve eseguire il rendering dei dati della posizione nell'interfaccia utente. È possibile eseguire questa operazione con un evento personalizzato che accetta come CLLocation
argomento:
// event for the location changing
public event EventHandler<LocationUpdatedEventArgs>LocationUpdated = delegate { };
Il passaggio successivo consiste nel sottoscrivere gli aggiornamenti della posizione da CLLocationManager
e generare l'evento personalizzato LocationUpdated
quando i nuovi dati di posizione diventano disponibili, passando il percorso come argomento. A tale scopo, creare una nuova classe LocationUpdateEventArgs.cs. Questo codice è accessibile all'interno dell'applicazione principale e restituisce la posizione del dispositivo quando viene generato l'evento:
public class LocationUpdatedEventArgs : EventArgs
{
CLLocation location;
public LocationUpdatedEventArgs(CLLocation location)
{
this.location = location;
}
public CLLocation Location
{
get { return location; }
}
}
Interfaccia utente
Usare Xcode Interface Builder per compilare la schermata che visualizzerà le informazioni sulla posizione. Fare doppio clic sul file Main.storyboard per iniziare.
Nello storyboard trascinare diverse etichette sullo schermo per fungere da segnaposto per le informazioni sulla posizione. In questo esempio sono disponibili etichette per latitudine, longitudine, altitudine, corso e velocità.
Per altre informazioni, vedere Progettazione di interfacce utente con Xcode.
Nel riquadro della soluzione fare doppio clic sul
ViewController.cs
file e modificarlo per creare una nuova istanza di LocationManager e chiamarlaStartLocationUpdates
. Modificare il codice in modo che sia simile al seguente:#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
Verrà avviato l'aggiornamento del percorso all'avvio dell'applicazione, anche se non verranno visualizzati dati.
Ora che gli aggiornamenti della posizione vengono ricevuti, aggiornare la schermata con le informazioni sulla posizione. Il metodo seguente ottiene la posizione dall'evento
LocationUpdated
e lo mostra nell'interfaccia utente:#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
È comunque necessario sottoscrivere l'evento LocationUpdated
in AppDelegate e chiamare il nuovo metodo per aggiornare l'interfaccia utente. Aggiungere il codice seguente subito ViewDidLoad,
dopo la StartLocationUpdates
chiamata:
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;
}
A questo punto, quando l'applicazione viene eseguita, dovrebbe essere simile alla seguente:
Gestione degli stati attivi e in background
L'applicazione restituisce gli aggiornamenti del percorso mentre è in primo piano e attivo. Per illustrare cosa accade quando l'app entra in background, eseguire l'override dei metodi che tengono traccia delle
AppDelegate
modifiche dello stato dell'applicazione in modo che l'applicazione scriva nella console quando passa tra il primo piano e lo sfondo:public override void DidEnterBackground (UIApplication application) { Console.WriteLine ("App entering background state."); } public override void WillEnterForeground (UIApplication application) { Console.WriteLine ("App will enter foreground"); }
Aggiungere il codice seguente in
LocationManager
per stampare continuamente i dati di posizione aggiornati nell'output dell'applicazione per verificare che le informazioni sulla posizione siano ancora disponibili in background: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); } }
C'è un problema rimanente con il codice: il tentativo di aggiornare l'interfaccia utente quando l'app è in background causerà l'interruzione di iOS. Quando l'app entra in background, il codice deve annullare la sottoscrizione agli aggiornamenti della posizione e interrompere l'aggiornamento dell'interfaccia utente.
iOS fornisce notifiche quando l'app sta per passare a un diverso stato dell'applicazione. In questo caso, è possibile sottoscrivere la
ObserveDidEnterBackground
notifica.Il frammento di codice seguente mostra come usare una notifica per informare la visualizzazione quando interrompere gli aggiornamenti dell'interfaccia utente. Questa operazione verrà visualizzata in
ViewDidLoad
:UIApplication.Notifications.ObserveDidEnterBackground ((sender, args) => { Manager.LocationUpdated -= HandleLocationChanged; });
Quando l'app è in esecuzione, l'output sarà simile al seguente:
L'applicazione stampa gli aggiornamenti della posizione sullo schermo quando si opera in primo piano e continua a stampare i dati nella finestra di output dell'applicazione mentre opera in background.
Rimane un solo problema in sospeso: la schermata avvia gli aggiornamenti dell'interfaccia utente al primo caricamento dell'app, ma non ha modo di sapere quando l'app è nuovamente in primo piano. Se l'applicazione in background viene ripristinata in primo piano, gli aggiornamenti dell'interfaccia utente non riprenderanno.
Per risolvere questo problema, annidare una chiamata per avviare gli aggiornamenti dell'interfaccia utente all'interno di un'altra notifica, che verrà attivata quando l'applicazione entra nello stato Attivo:
UIApplication.Notifications.ObserveDidBecomeActive ((sender, args) => {
Manager.LocationUpdated += HandleLocationChanged;
});
Ora l'interfaccia utente inizierà ad aggiornare al primo avvio dell'applicazione e riprenderà l'aggiornamento in qualsiasi momento in cui l'app torna in primo piano.
In questa procedura dettagliata è stata creata un'applicazione iOS con riconoscimento dello sfondo ben comportamento che stampa i dati sulla posizione sia sullo schermo che sulla finestra di output dell'applicazione.