다음을 통해 공유


연습 - Xamarin.iOS의 배경 위치

이 예제에서는 위도, 경도 및 기타 매개 변수와 같은 현재 위치에 대한 정보를 화면에 출력하는 iOS 위치 애플리케이션을 빌드합니다. 이 애플리케이션은 애플리케이션이 활성 또는 백그라운드 상태인 동안 위치 업데이트를 올바르게 수행하는 방법을 보여 줍니다.

이 연습에서는 백그라운드에서 필요한 애플리케이션으로 앱을 등록하고, 앱이 백그라운드에 있을 때 UI 업데이트를 일시 중단하고, 및 WillEnterForeground AppDelegate 메서드를 WillEnterBackground 사용하는 등 몇 가지 주요 배경 개념을 설명합니다.

애플리케이션 설정

  1. 먼저 새 iOS > 앱 > 단일 보기 애플리케이션(C#)을 만듭니다. 위치를 호출하고 iPad와 iPhone이 모두 선택되었는지 확인합니다.

  2. 위치 애플리케이션은 iOS에서 백그라운드에서 필요한 애플리케이션으로 한정됩니다. 프로젝트의 Info.plist 파일을 편집하여 애플리케이션을 위치 애플리케이션으로 등록합니다.

    솔루션 탐색기 Info.plist 파일을 두 번 클릭하여 열고 목록 아래쪽으로 스크롤합니다. 백그라운드 모드 사용 및 위치 업데이트 확인란을 모두 확인합니다.

    Mac용 Visual Studio 다음과 같이 표시됩니다.

    백그라운드 모드 사용 및 위치 업데이트 확인란 둘 다에서 확인란을 배치합니다.

    Visual Studio 에서 다음 키/값 쌍을 추가하여 Info.plist 를 수동으로 업데이트해야 합니다.

    <key>UIBackgroundModes</key>
    <array>
      <string>location</string>
    </array>
    
  3. 이제 애플리케이션이 등록되었으므로 디바이스에서 위치 데이터를 가져올 수 있습니다. iOS CLLocationManager 에서 클래스는 위치 정보에 액세스하는 데 사용되며 위치 업데이트를 제공하는 이벤트를 발생시키는 데 사용됩니다.

  4. 코드에서 위치 업데이트를 구독하는 다양한 화면 및 코드에 대한 단일 위치를 제공하는 새 클래스를 LocationManager 만듭니다. 클래스에서 LocationManager 호출된 인스턴스를 CLLocationManager 만듭니다 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; }
        }
    }
    

    위의 코드는 CLLocationManager 클래스에 대한 여러 속성 및 권한을 설정합니다.

    • PausesLocationUpdatesAutomatically – 시스템이 위치 업데이트를 일시 중지할 수 있는지 여부에 따라 설정할 수 있는 부울입니다. 일부 디바이스에서는 기본값으로 true설정되며, 이로 인해 디바이스가 약 15분 후에 백그라운드 위치 업데이트 가져오기를 중지할 수 있습니다.
    • RequestAlwaysAuthorization - 앱 사용자에게 백그라운드에서 위치에 액세스할 수 있는 옵션을 제공하려면 이 메서드를 전달해야 합니다. RequestWhenInUseAuthorization 은 앱이 포그라운드에 있을 때만 위치에 액세스할 수 있는 옵션을 사용자에게 제공하려는 경우에도 전달될 수 있습니다.
    • AllowsBackgroundLocationUpdates – 일시 중단 시 앱이 위치 업데이트를 받을 수 있도록 설정할 수 있는 iOS 9에 도입된 부울 속성입니다.

    Important

    iOS 8 이상에서는 인증 요청의 일부로 사용자를 표시하기 위해 Info.plist 파일의 항목도 필요합니다.

  5. 위치 데이터 액세스를 요청하는 경고에서 사용자에게 표시될 문자열을 사용하여 앱에 필요한 NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescriptionNSLocationAlwaysAndWhenInUseUsageDescription 사용 권한 유형에 대한 Info.plist 키를 추가합니다.

  6. iOS 9를 사용하려면 Info.plist를 사용할 AllowsBackgroundLocationUpdates 때 값location이 포함된 키가 UIBackgroundModes 포함되어야 합니다. 이 연습의 2단계를 완료한 경우 Info.plist 파일에 이미 있어야 합니다.

  7. 클래스 내에서 LocationManager 다음 코드를 사용하여 호출 StartLocationUpdates 되는 메서드를 만듭니다. 이 코드는 다음에서 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();
    }
    

    이 메서드에는 몇 가지 중요한 일이 있습니다. 먼저 애플리케이션이 디바이스의 위치 데이터에 액세스할 수 있는지 확인하는 검사를 수행합니다. 를 호출 LocationServicesEnabled 하여 이를 확인합니다 CLLocationManager. 사용자가 위치 정보에 대한 애플리케이션 액세스를 거부한 경우 이 메서드는 false를 반환합니다.

  8. 다음으로 위치 관리자에게 업데이트 빈도를 알려 줍니다. CLLocationManager 에서는 업데이트 빈도를 포함하여 위치 데이터를 필터링하고 구성하는 다양한 옵션을 제공합니다. 이 예제에서는 위치가 DesiredAccuracy 미터별로 변경될 때마다 업데이트하도록 설정합니다. 위치 업데이트 빈도 및 기타 기본 설정을 구성하는 방법에 대한 자세한 내용은 Apple 설명서의 CLLocationManager 클래스 참조를 참조 하세요.

  9. 마지막으로 인스턴스를 호출 StartUpdatingLocation 합니다 CLLocationManager . 그러면 위치 관리자에게 현재 위치에 대한 초기 수정을 받고 업데이트 보내기를 시작하도록 지시합니다.

지금까지 위치 관리자를 만들고, 수신하려는 데이터의 종류로 구성하고, 초기 위치를 결정했습니다. 이제 코드는 사용자 인터페이스에 위치 데이터를 렌더링해야 합니다. 인수로 사용하는 CLLocation 사용자 지정 이벤트를 사용하여 이 작업을 수행할 수 있습니다.

// event for the location changing
public event EventHandler<LocationUpdatedEventArgs>LocationUpdated = delegate { };

다음 단계는 위치 업데이트를 CLLocationManager구독하고 새 위치 데이터를 사용할 수 있게 되면 사용자 지정 LocationUpdated 이벤트를 발생시키고 위치를 인수로 전달하는 것입니다. 이렇게 하려면 새 클래스 LocationUpdateEventArgs.cs 만듭니다. 이 코드는 기본 애플리케이션 내에서 액세스할 수 있으며 이벤트가 발생하면 디바이스 위치를 반환합니다.

public class LocationUpdatedEventArgs : EventArgs
{
    CLLocation location;

    public LocationUpdatedEventArgs(CLLocation location)
    {
       this.location = location;
    }

    public CLLocation Location
    {
       get { return location; }
    }
}

사용자 인터페이스

  1. Xcode 인터페이스 작성기를 사용하여 위치 정보를 표시하는 화면을 빌드합니다. Main.storyboard 파일을 두 번 클릭하여 시작합니다.

    스토리보드에서 여러 레이블을 화면으로 끌어 위치 정보의 자리 표시자 역할을 합니다. 이 예제에는 위도, 경도, 고도, 코스 및 속도에 대한 레이블이 있습니다.

    자세한 내용은 Xcode를 사용하여 사용자 인터페이스 디자인을 참조하세요.

  2. Solution Pad에서 파일을 두 번 클릭하고 ViewController.cs 편집하여 LocationManager의 새 인스턴스를 만들고 호출 StartLocationUpdates합니다. 코드를 다음과 같이 변경합니다.

    #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
    

    그러면 데이터가 표시되지 않지만 애플리케이션 시작 시 위치 업데이트가 시작됩니다.

  3. 이제 위치 업데이트가 수신되었으므로 위치 정보로 화면을 업데이트합니다. 다음 메서드는 이벤트에서 위치를 LocationUpdated 가져오고 UI에 표시합니다.

    #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
    

AppDelegate에서 이벤트를 구독 LocationUpdated 하고 새 메서드를 호출하여 UI를 업데이트해야 합니다. 호출 직후에 ViewDidLoad, 다음 코드를 추가합니다 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;

}

이제 애플리케이션이 실행되면 다음과 같이 표시됩니다.

앱 실행 예제

활성 및 백그라운드 상태 처리

  1. 애플리케이션이 포그라운드 및 활성 상태인 동안 위치 업데이트를 출력합니다. 앱이 백그라운드에 들어갈 때 발생하는 작업을 보여 주려면 애플리케이션이 포그라운드와 백그라운드 간에 전환할 때 콘솔에 쓰도록 애플리케이션 상태 변경을 추적하는 메서드를 재정 AppDelegate 의합니다.

    public override void DidEnterBackground (UIApplication application)
    {
        Console.WriteLine ("App entering background state.");
    }
    
    public override void WillEnterForeground (UIApplication application)
    {
        Console.WriteLine ("App will enter foreground");
    }
    

    업데이트된 위치 데이터를 애플리케이션 출력에 지속적으로 인쇄하려면 다음 코드를 추가하여 백그라운드에서 LocationManager 위치 정보를 계속 사용할 수 있는지 확인합니다.

    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. 코드에 남아 있는 한 가지 문제가 있습니다. 앱이 백그라운드에 있을 때 UI를 업데이트하려고 하면 iOS가 종료됩니다. 앱이 백그라운드로 전환되면 코드는 위치 업데이트에서 구독을 취소하고 UI 업데이트를 중지해야 합니다.

    iOS는 앱이 다른 애플리케이션 상태로 전환하려고 할 때 알림을 제공합니다. 이 경우 알림을 구독할 ObserveDidEnterBackground 수 있습니다.

    다음 코드 조각에서는 알림을 사용하여 UI 업데이트를 중지해야 하는 시기를 보기에 알리는 방법을 보여 줍니다. 그러면 다음이 수행됩니다.ViewDidLoad

    UIApplication.Notifications.ObserveDidEnterBackground ((sender, args) => {
        Manager.LocationUpdated -= HandleLocationChanged;
    });
    

    앱이 실행되면 출력은 다음과 같이 표시됩니다.

    콘솔의 위치 출력 예제

  3. 애플리케이션은 포그라운드에서 작동할 때 화면에 위치 업데이트를 인쇄하고 백그라운드에서 작동하는 동안 애플리케이션 출력 창에 데이터를 계속 인쇄합니다.

앱이 처음 로드될 때 화면이 UI 업데이트를 시작하지만 앱이 포그라운드에 다시 입력된 시기를 알 수 있는 방법은 없습니다. 백그라운드 애플리케이션을 포그라운드로 다시 가져오는 경우 UI 업데이트가 다시 시작되지 않습니다.

이 문제를 해결하려면 호출을 중첩하여 애플리케이션이 활성 상태가 되면 발생하는 다른 알림 내에 UI 업데이트를 시작합니다.

UIApplication.Notifications.ObserveDidBecomeActive ((sender, args) => {
  Manager.LocationUpdated += HandleLocationChanged;
});

이제 애플리케이션이 처음 시작될 때 UI가 업데이트되기 시작하고 앱이 포그라운드로 돌아올 때마다 업데이트를 다시 시작합니다.

이 연습에서는 위치 데이터를 화면과 애플리케이션 출력 창 모두에 출력하는 잘 작동하는 배경 인식 iOS 애플리케이션을 빌드했습니다.