Udostępnij za pośrednictwem


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

  1. 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.

  2. 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:

    Zaznacz pole wyboru Włącz tryby tła i Aktualizacje lokalizacji

    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>
    
  3. 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.

  4. 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ąpienie CLLocationManager o nazwie LocMgr:

    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ądzeniach truewartość 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.

  5. Dodaj klucze Info.plist dla typów uprawnień, których aplikacja wymaga — NSLocationAlwaysUsageDescription, NSLocationWhenInUseUsageDescriptioni/lub NSLocationAlwaysAndWhenInUseUsageDescription — z ciągiem, który będzie wyświetlany użytkownikowi w alercie, który żąda dostępu do danych lokalizacji.

  6. System iOS 9 wymaga, aby w przypadku korzystania z AllowsBackgroundLocationUpdates pliku Info.plist zawierał klucz UIBackgroundModes z wartością location. Jeśli krok 2 tego przewodnika został ukończony, powinno to już znajdować się w pliku Info.plist.

  7. LocationManager Wewnątrz klasy utwórz metodę o nazwie StartLocationUpdates przy użyciu następującego kodu. Ten kod pokazuje, jak rozpocząć odbieranie aktualizacji lokalizacji z pliku CLLocationManager:

    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 metody CLLocationManager. Ta metoda zwróci wartość false , jeśli użytkownik odmówił dostępu aplikacji do informacji o lokalizacji.

  8. 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ładzie DesiredAccuracy 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.

  9. 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 CLLocationManagerelementu 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

  1. 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.

  2. W okienku rozwiązania kliknij ViewController.cs dwukrotnie plik i edytuj go, aby utworzyć nowe wystąpienie menedżera lokalizacji i wywołać StartLocationUpdatesgo. 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.

  3. 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:

Uruchamianie przykładowej aplikacji

Obsługa stanów aktywnych i w tle

  1. 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);
        }
    }
    
  2. 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:

    Przykładowe dane wyjściowe lokalizacji w konsoli

  3. 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.