Przewodnik — lokalizacja w tle na platformie Xamarin.iOS
W tym przykładzie utworzymy aplikację lokalizacji systemu iOS, która wyświetla informacje o naszej bieżącej lokalizacji: szerokość geograficzna, długość geograficzna i inne parametry na ekranie. Ta aplikacja pokaże, jak prawidłowo wykonywać aktualizacje lokalizacji, gdy aplikacja jest aktywna lub w tle.
W tym przewodniku wyjaśniono niektóre kluczowe pojęcia dotyczące tworzenia tła, w tym rejestrowanie aplikacji jako aplikacji niezbędnej w tle, zawieszanie aktualizacji interfejsu użytkownika, gdy aplikacja jest w tle, oraz praca z metodami WillEnterBackground
i WillEnterForeground
AppDelegate
.
Konfiguracja aplikacji
Najpierw utwórz nową aplikację z pojedynczym widokiem aplikacji > systemu iOS > (C#). Wywołaj lokalizację i upewnij się, że wybrano zarówno urządzenie iPad, jak i iPhone.
Aplikacja lokalizacji kwalifikuje się jako aplikacja niezbędna w tle w systemie iOS. Zarejestruj aplikację jako aplikację Lokalizacja, edytując plik Info.plist dla projektu.
W Eksplorator rozwiązań kliknij dwukrotnie plik Info.plist, aby go otworzyć, i przewiń do dołu listy. Zaznacz pole wyboru Włącz tryby tła i Aktualizacje lokalizacji.
W Visual Studio dla komputerów Mac będzie wyglądać następująco:
W programie Visual Studio należy ręcznie zaktualizować plik Info.plist , dodając następującą parę klucz/wartość:
<key>UIBackgroundModes</key> <array> <string>location</string> </array>
Teraz, gdy aplikacja jest zarejestrowana, może pobierać dane lokalizacji z urządzenia. W systemie iOS klasa jest używana do uzyskiwania
CLLocationManager
dostępu do informacji o lokalizacji i może zgłaszać zdarzenia, które udostępniają aktualizacje lokalizacji.W kodzie utwórz nową klasę o nazwie
LocationManager
, która udostępnia jedno miejsce dla różnych ekranów i kodu w celu subskrybowania aktualizacji lokalizacji.LocationManager
W klasie utwórz wystąpienieCLLocationManager
o nazwieLocMgr
: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; } } }
Powyższy kod ustawia szereg właściwości i uprawnień w klasie CLLocationManager :
PausesLocationUpdatesAutomatically
— Jest to wartość logiczna, którą można ustawić w zależności od tego, czy system może wstrzymać aktualizacje lokalizacji. Na niektórych urządzeniachtrue
wartość domyślna to , co może spowodować, że urządzenie przestanie uzyskiwać aktualizacje lokalizacji w tle po około 15 minutach.RequestAlwaysAuthorization
— Należy przekazać tę metodę, aby nadać użytkownikowi aplikacji opcję zezwalania na dostęp do lokalizacji w tle.RequestWhenInUseAuthorization
można również przekazać, jeśli chcesz przyznać użytkownikowi opcję zezwalania na dostęp do lokalizacji tylko wtedy, gdy aplikacja znajduje się na pierwszym planie.AllowsBackgroundLocationUpdates
— Jest to właściwość logiczna wprowadzona w systemie iOS 9, która umożliwia aplikacji odbieranie aktualizacji lokalizacji po zawieszeniu.
Ważne
System iOS 8 (i nowsze) wymaga również wpisu w pliku Info.plist , aby pokazać użytkownika w ramach żądania autoryzacji.
Dodaj klucze Info.plist dla typów uprawnień, których aplikacja wymaga —
NSLocationAlwaysUsageDescription
,NSLocationWhenInUseUsageDescription
i/lubNSLocationAlwaysAndWhenInUseUsageDescription
— z ciągiem, który będzie wyświetlany użytkownikowi w alercie, który żąda dostępu do danych lokalizacji.System iOS 9 wymaga, aby w przypadku korzystania z
AllowsBackgroundLocationUpdates
pliku Info.plist zawierał kluczUIBackgroundModes
z wartościąlocation
. Jeśli krok 2 tego przewodnika został ukończony, powinno to już znajdować się w pliku Info.plist.LocationManager
Wewnątrz klasy utwórz metodę o nazwieStartLocationUpdates
przy użyciu następującego kodu. Ten kod pokazuje, jak rozpocząć odbieranie aktualizacji lokalizacji z plikuCLLocationManager
: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(); }
W tej metodzie dzieje się kilka ważnych rzeczy. Najpierw przeprowadzamy sprawdzanie, czy aplikacja ma dostęp do danych lokalizacji na urządzeniu. Zweryfikujemy to przez wywołanie
LocationServicesEnabled
metodyCLLocationManager
. Ta metoda zwróci wartość false , jeśli użytkownik odmówił dostępu aplikacji do informacji o lokalizacji.Następnie poinformuj menedżera lokalizacji, jak często należy je aktualizować.
CLLocationManager
Udostępnia wiele opcji filtrowania i konfigurowania danych lokalizacji, w tym częstotliwość aktualizacji. W tym przykładzieDesiredAccuracy
ustaw parametr , aby aktualizować za każdym razem, gdy lokalizacja zmienia się według miernika. Aby uzyskać więcej informacji na temat konfigurowania częstotliwości aktualizacji lokalizacji i innych preferencji, zapoznaj się z dokumentacją klasy CLLocationManager w dokumentacji firmy Apple.Na koniec wywołaj
StartUpdatingLocation
CLLocationManager
wystąpienie. Informuje menedżera lokalizacji, aby uzyskać początkową poprawkę w bieżącej lokalizacji i rozpocząć wysyłanie aktualizacji
Do tej pory menedżer lokalizacji został utworzony, skonfigurowany z rodzajami danych, które chcemy odbierać, i określił początkową lokalizację. Teraz kod musi renderować dane lokalizacji w interfejsie użytkownika. Możemy to zrobić za pomocą zdarzenia niestandardowego, które przyjmuje CLLocation
jako argument:
// event for the location changing
public event EventHandler<LocationUpdatedEventArgs>LocationUpdated = delegate { };
Następnym krokiem jest subskrybowanie aktualizacji lokalizacji z CLLocationManager
elementu i wywoływanie zdarzenia niestandardowego LocationUpdated
, gdy nowe dane lokalizacji staną się dostępne, przekazując lokalizację jako argument. W tym celu utwórz nową klasę LocationUpdateEventArgs.cs. Ten kod jest dostępny w głównej aplikacji i zwraca lokalizację urządzenia po wystąpieniu zdarzenia:
public class LocationUpdatedEventArgs : EventArgs
{
CLLocation location;
public LocationUpdatedEventArgs(CLLocation location)
{
this.location = location;
}
public CLLocation Location
{
get { return location; }
}
}
Interfejs użytkownika
Użyj narzędzia Xcode Interface Builder, aby skompilować ekran, na który będą wyświetlane informacje o lokalizacji. Kliknij dwukrotnie plik Main.storyboard, aby rozpocząć.
Na scenorysie przeciągnij kilka etykiet na ekran, aby pełnić rolę symboli zastępczych informacji o lokalizacji. W tym przykładzie istnieją etykiety szerokości geograficznej, długości geograficznej, wysokości, kursu i szybkości.
Aby uzyskać więcej informacji, zobacz Projektowanie interfejsów użytkownika za pomocą programu Xcode.
W okienku rozwiązania kliknij
ViewController.cs
dwukrotnie plik i edytuj go, aby utworzyć nowe wystąpienie menedżera lokalizacji i wywołaćStartLocationUpdates
go. Zmień kod tak, aby wyglądał następująco:#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
Spowoduje to uruchomienie aktualizacji lokalizacji podczas uruchamiania aplikacji, chociaż żadne dane nie będą wyświetlane.
Po odebraniu aktualizacji lokalizacji zaktualizuj ekran przy użyciu informacji o lokalizacji. Poniższa metoda pobiera lokalizację z naszego
LocationUpdated
zdarzenia i wyświetla ją w interfejsie użytkownika:#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
Nadal musimy zasubskrybować LocationUpdated
zdarzenie w naszej aplikacji AppDelegate i wywołać nową metodę w celu zaktualizowania interfejsu użytkownika. Dodaj następujący kod bezpośrednio ViewDidLoad,
po wywołaniu StartLocationUpdates
:
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;
}
Teraz po uruchomieniu aplikacji powinna ona wyglądać mniej więcej tak:
Obsługa stanów aktywnych i w tle
Aplikacja generuje aktualizacje lokalizacji, gdy znajduje się na pierwszym planie i jest aktywna. Aby zademonstrować, co się stanie po wejściu aplikacji w tle, przesłoń
AppDelegate
metody, które śledzą zmiany stanu aplikacji, tak aby aplikacja zapisywała w konsoli podczas przechodzenia między pierwszym planem a tłem:public override void DidEnterBackground (UIApplication application) { Console.WriteLine ("App entering background state."); } public override void WillEnterForeground (UIApplication application) { Console.WriteLine ("App will enter foreground"); }
Dodaj następujący kod w pliku ,
LocationManager
aby stale drukować zaktualizowane dane lokalizacji do danych wyjściowych aplikacji, aby sprawdzić, czy informacje o lokalizacji są nadal dostępne w tle: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); } }
Istnieje jeden z pozostałych problemów z kodem: próba zaktualizowania interfejsu użytkownika, gdy aplikacja jest w tle, spowoduje zakończenie działania systemu iOS. Gdy aplikacja przechodzi w tle, kod musi anulować subskrypcję aktualizacji lokalizacji i przestać aktualizować interfejs użytkownika.
System iOS udostępnia nam powiadomienia, gdy aplikacja ma przejść do innych stanów aplikacji. W takim przypadku możemy zasubskrybować powiadomienie
ObserveDidEnterBackground
.Poniższy fragment kodu pokazuje, jak za pomocą powiadomienia poinformować widok, kiedy zatrzymać aktualizacje interfejsu użytkownika. Spowoduje to przejście do elementu :
ViewDidLoad
UIApplication.Notifications.ObserveDidEnterBackground ((sender, args) => { Manager.LocationUpdated -= HandleLocationChanged; });
Gdy aplikacja jest uruchomiona, dane wyjściowe będą wyglądać mniej więcej tak:
Aplikacja drukuje aktualizacje lokalizacji na ekranie podczas działania na pierwszym planie i nadal drukuje dane w oknie danych wyjściowych aplikacji podczas działania w tle.
Pozostaje tylko jeden nierozwiązany problem: ekran uruchamia aktualizacje interfejsu użytkownika po pierwszym załadowaniu aplikacji, ale nie ma możliwości znajomości ponownego wprowadzenia aplikacji na pierwszym planie. Jeśli aplikacja w tle zostanie przywrócona na pierwszym planie, aktualizacje interfejsu użytkownika nie zostaną wznowione.
Aby rozwiązać ten problem, zagnieżdżanie wywołania w celu uruchomienia aktualizacji interfejsu użytkownika wewnątrz innego powiadomienia, które zostanie wyzwolony, gdy aplikacja przejdzie w stan Aktywny:
UIApplication.Notifications.ObserveDidBecomeActive ((sender, args) => {
Manager.LocationUpdated += HandleLocationChanged;
});
Teraz interfejs użytkownika rozpocznie aktualizowanie po pierwszym uruchomieniu aplikacji i wznowi aktualizowanie za każdym razem, gdy aplikacja wróci na pierwszy plan.
W tym przewodniku utworzyliśmy dobrze zachowywaną aplikację systemu iOS z obsługą tła, która drukuje dane lokalizacji zarówno na ekranie, jak i w oknie danych wyjściowych aplikacji.