지오펜스 설정

참고 항목

MapControl 및 지도 서비스를 사용하려면 MapServiceToken이라는 지도 인증 키가 필요합니다. 맵 인증 키 가져오기 및 설정에 대한 자세한 내용은 맵 인증 키 요청을 참조하세요.

앱에서 지오펜스를 설정한 후, 포그라운드 및 백그라운드에서 알림을 처리하는 방법을 알아보세요.

앱에서 위치에 액세스하는 방법에 대해 자세히 알아보려면 GitHub의 Windows-universal-samples 리포지토리에서 다음 샘플을 다운로드하세요.

위치 기능 활성화하기

  1. 솔루션 탐색기에서 package.appxmanifest를 두 번 클릭하고 기능 탭을 선택하세요.
  2. 기능 목록에서 위치에 체크 표시하세요. 이렇게 하면 패키지 매니페스트 파일에 Location 디바이스 기능이 추가됩니다.
  <Capabilities>
    <!-- DeviceCapability elements must follow Capability elements (if present) -->
    <DeviceCapability Name="location"/>
  </Capabilities>

지오펜스 설정

1단계: 사용자의 위치에 대한 액세스 권한 요청하기

중요 사용자의 위치에 대한 액세스를 시도하기 전에 RequestAccessAsync 메서드를 사용해서 사용자의 위치에 대한 액세스 권한을 요청해야 합니다. 사용자는 UI 스레드로부터 RequestAccessAsync 메서드를 호출해야 하며, 이때는 앱이 포그라운드에 있어야 합니다. 사용자가 앱에 권한을 부여할 때까지는 앱으로 사용자의 위치 정보에 액세스할 수 없습니다.

using Windows.Devices.Geolocation;
...
var accessStatus = await Geolocator.RequestAccessAsync();

RequestAccessAsync 메서드를 사용하면 해당 위치에 액세스할 수 있는 권한이 있는지 묻는 메시지가 사용자에게 표시됩니다. 사용자는 앱당 한 번만 메시지를 받습니다. 최초로 권한을 부여하거나 거부하고 나면 이 메서드가 더 이상 사용자에게 권한 유무를 묻지 않습니다. 사용자가 메시지를 받은 후 위치 권한을 변경할 수 있도록, 이 토픽의 뒷부분에 설명된 대로 위치 설정의 링크를 제공하는 것이 좋습니다.

2단계: 지오펜스 상태 및 위치 권한의 변경 사항 등록하기

이 예제에서 switch 구문은 사용자의 위치에 대한 액세스가 허용된 경우에만 작동하도록 accessStatus(이전 예제에 수록됨)와 함께 사용됩니다. 사용자의 위치에 대한 액세스가 허용되는 경우 이 코드는 현재의 지오펜스에 액세스하고, 지오펜스 상태 변경을 등록하며, 위치 권한의 변경 사항을 등록합니다.

지오펜스를 사용할 경우, Geolocator 클래스의 StatusChanged 이벤트 대신 GeofenceMonitor 클래스의 StatusChanged 이벤트를 사용해서 위치 권한의 변경 사항을 모니터링하세요. Disabled(비활성화됨)GeofenceMonitorStatus는 비활성화된 PositionStatus와 동일합니다. 둘 다 앱에 사용자의 위치에 액세스할 권한이 없음을 나타냅니다.

switch (accessStatus)
{
    case GeolocationAccessStatus.Allowed:
        geofences = GeofenceMonitor.Current.Geofences;

        FillRegisteredGeofenceListBoxWithExistingGeofences();
        FillEventListBoxWithExistingEvents();

        // Register for state change events.
        GeofenceMonitor.Current.GeofenceStateChanged += OnGeofenceStateChanged;
        GeofenceMonitor.Current.StatusChanged += OnGeofenceStatusChanged;
        break;


    case GeolocationAccessStatus.Denied:
        _rootPage.NotifyUser("Access denied.", NotifyType.ErrorMessage);
        break;

    case GeolocationAccessStatus.Unspecified:
        _rootPage.NotifyUser("Unspecified error.", NotifyType.ErrorMessage);
        break;
}

그런 다음, 포그라운드 앱에서 다른 곳으로 이동하면 이벤트 수신기의 등록을 취소하세요.

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
    GeofenceMonitor.Current.GeofenceStateChanged -= OnGeofenceStateChanged;
    GeofenceMonitor.Current.StatusChanged -= OnGeofenceStatusChanged;

    base.OnNavigatingFrom(e);
}

3단계: 지오펜스 생성하기

이제 Geofence 개체를 정의하고 설정할 준비가 되었습니다. 생성자 오버로드는 필요에 따라 여러 가지를 선택할 수 있습니다. 아래 내용대로 가장 기본적인 지오펜스 생성자에서 IdGeoshape만 지정하세요.

// Set the fence ID.
string fenceId = "fence1";

// Define the fence location and radius.
BasicGeoposition position;
position.Latitude = 47.6510;
position.Longitude = -122.3473;
position.Altitude = 0.0;
double radius = 10; // in meters

// Set a circular region for the geofence.
Geocircle geocircle = new Geocircle(position, radius);

// Create the geofence.
Geofence geofence = new Geofence(fenceId, geocircle);

다른 생성자 중 하나를 사용하면 지오펜스를 미세 조정할 수 있습니다. 다음 예제에서 지오펜스 생성자는 다음의 추가 매개변수를 지정합니다.

  • MonitoredStates - 정의된 지역으로 들어가거나, 정의된 지역을 떠나거나, 지오펜스를 제거는 경우 알림을 받을 지오펜스 이벤트를 나타냅니다.
  • SingleUse - 지오펜스를 모니터링하는 모든 상태가 충족되었을 때 지오펜스를 제거합니다.
  • DwellTime - enter/exit 이벤트가 트리거되기까지 사용자가 정의된 영역에 있거나 이 영역에서 벗어나 있어야 하는 시간을 나타냅니다.
  • StartTime - 지오펜스 모니터링을 시작해야 할 시기를 나타냅니다.
  • Duration - 지오펜스를 모니터링할 기간을 나타냅니다.
// Set the fence ID.
string fenceId = "fence2";

// Define the fence location and radius.
BasicGeoposition position;
position.Latitude = 47.6510;
position.Longitude = -122.3473;
position.Altitude = 0.0;
double radius = 10; // in meters

// Set the circular region for geofence.
Geocircle geocircle = new Geocircle(position, radius);

// Remove the geofence after the first trigger.
bool singleUse = true;

// Set the monitored states.
MonitoredGeofenceStates monitoredStates =
                MonitoredGeofenceStates.Entered |
                MonitoredGeofenceStates.Exited |
                MonitoredGeofenceStates.Removed;

// Set how long you need to be in geofence for the enter event to fire.
TimeSpan dwellTime = TimeSpan.FromMinutes(5);

// Set how long the geofence should be active.
TimeSpan duration = TimeSpan.FromDays(1);

// Set up the start time of the geofence.
DateTimeOffset startTime = DateTime.Now;

// Create the geofence.
Geofence geofence = new Geofence(fenceId, geocircle, monitoredStates, singleUse, dwellTime, startTime, duration);

지오펜스를 만든 후에 새 지오펜스를 모니터에 등록해야 합니다.

// Register the geofence
try {
   GeofenceMonitor.Current.Geofences.Add(geofence);
} catch {
   // Handle failure to add geofence
}

4단계: 위치 권한의 변경 사항 처리하기

GeofenceMonitor 개체는 사용자의 위치 설정이 변경되었다는 것이 표시되도록 StatusChanged 이벤트를 트리거합니다. 이 이벤트는 인수의 sender.Status 속성(GeofenceMonitorStatus 형식에 속함)을 통해 해당 상태를 전달합니다. 이 메서드는 UI 스레드로부터 호출되지 않으며, 발송자 개체가 UI 변경 사항을 호출합니다.

using Windows.UI.Core;
...
public async void OnGeofenceStatusChanged(GeofenceMonitor sender, object e)
{
   await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
   {
    // Show the location setting message only if the status is disabled.
    LocationDisabledMessage.Visibility = Visibility.Collapsed;

    switch (sender.Status)
    {
     case GeofenceMonitorStatus.Ready:
      _rootPage.NotifyUser("The monitor is ready and active.", NotifyType.StatusMessage);
      break;

     case GeofenceMonitorStatus.Initializing:
      _rootPage.NotifyUser("The monitor is in the process of initializing.", NotifyType.StatusMessage);
      break;

     case GeofenceMonitorStatus.NoData:
      _rootPage.NotifyUser("There is no data on the status of the monitor.", NotifyType.ErrorMessage);
      break;

     case GeofenceMonitorStatus.Disabled:
      _rootPage.NotifyUser("Access to location is denied.", NotifyType.ErrorMessage);

      // Show the message to the user to go to the location settings.
      LocationDisabledMessage.Visibility = Visibility.Visible;
      break;

     case GeofenceMonitorStatus.NotInitialized:
      _rootPage.NotifyUser("The geofence monitor has not been initialized.", NotifyType.StatusMessage);
      break;

     case GeofenceMonitorStatus.NotAvailable:
      _rootPage.NotifyUser("The geofence monitor is not available.", NotifyType.ErrorMessage);
      break;

     default:
      ScenarioOutput_Status.Text = "Unknown";
      _rootPage.NotifyUser(string.Empty, NotifyType.StatusMessage);
      break;
    }
   });
}

포그라운드 알림 설정하기

지오펜스를 생성한 후에는 지오펜스 이벤트 발생 시 진행되는 작업을 처리할 논리를 추가해야 합니다. 설정된 MonitoredStates에 따라 다음과 같은 경우에 이벤트를 수신할 수 있습니다.

  • 사용자가 관심 있는 지역에 들어갑니다.
  • 사용자가 관심 있는 지역을 떠납니다.
  • 지오펜스가 만료되었거나 제거되었습니다. 백그라운드 앱은 제거 이벤트에 대해 활성화되지 않는다는 점에 유의하세요.

실행 중일 때 앱에서 직접 이벤트 수신을 대기할 수도 있고, 이벤트 발생 시 백그라운드 알림을 받도록 백그라운드 작업을 등록할 수도 있습니다.

1단계: 지오펜스 상태 변경 이벤트 등록하기

앱으로 지오펜스 상태 변경에 대한 포그라운드 알림을 받으려면 이벤트 처리기를 등록해야 합니다. 이 항목은 일반적으로 지오펜스를 생성할 때 설정됩니다.

private void Initialize()
{
    // Other initialization logic

    GeofenceMonitor.Current.GeofenceStateChanged += OnGeofenceStateChanged;
}

2단계: 지오펜스 이벤트 처리기 구현하기

다음 단계는 이벤트 처리기를 구현하는 것입니다. 여기서 수행될 작업은 앱이 지오펜스를 사용하려는 대상에 따라 달라집니다.

public async void OnGeofenceStateChanged(GeofenceMonitor sender, object e)
{
    var reports = sender.ReadReports();

    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        foreach (GeofenceStateChangeReport report in reports)
        {
            GeofenceState state = report.NewState;

            Geofence geofence = report.Geofence;

            if (state == GeofenceState.Removed)
            {
                // Remove the geofence from the geofences collection.
                GeofenceMonitor.Current.Geofences.Remove(geofence);
            }
            else if (state == GeofenceState.Entered)
            {
                // Your app takes action based on the entered event.

                // NOTE: You might want to write your app to take a particular
                // action based on whether the app has internet connectivity.

            }
            else if (state == GeofenceState.Exited)
            {
                // Your app takes action based on the exited event.

                // NOTE: You might want to write your app to take a particular
                // action based on whether the app has internet connectivity.

            }
        }
    });
}



백그라운드 알림 설정하기

지오펜스를 생성한 후에는 지오펜스 이벤트 발생 시 진행되는 작업을 처리할 논리를 추가해야 합니다. 설정된 MonitoredStates에 따라 다음과 같은 경우에 이벤트를 수신할 수 있습니다.

  • 사용자가 관심 있는 지역에 들어갑니다.
  • 사용자가 관심 있는 지역을 떠납니다.
  • 지오펜스가 만료되었거나 제거되었습니다. 백그라운드 앱은 제거 이벤트에 대해 활성화되지 않는다는 점에 유의하세요.

백그라운드에서 지오펜스 이벤트 수신을 대기하려면

  • 앱의 매니페스트에서 백그라운드 작업을 선언하세요.
  • 앱에서 백그라운드 작업을 등록하세요. 클라우드 서비스에 액세스하기 위해 앱을 통한 인터넷 접속이 필요한 경우, 이벤트가 트리거되었을 때 이를 위한 플래그를 설정할 수 있습니다. 플래그를 설정하면 사용자가 알림을 받을 수 있도록 이벤트가 트리거되었을 때 사용자가 있는지 확인할 수도 있습니다.
  • 앱이 포그라운드에서 실행되는 동안 앱 위치 권한을 부여하라는 메시지가 사용자에게 표시됩니다.

1단계: 지오펜스 상태 변경 이벤트 등록하기

앱 매니페스트의 선언 탭에서 위치 백그라운드 작업에 대한 선언을 추가하세요. 방법:

  • 백그라운드 작업 형식의 선언을 추가하세요.
  • 위치의 속성 작업 유형을 설정하세요.
  • 이벤트가 트리거되었을 때 호출할 앱으로의 진입점을 설정하세요.

2단계: 백그라운드 작업 등록하기

이 단계의 코드는 지오펜싱 백그라운드 작업을 등록합니다. 지오펜스가 생성되면 위치 사용 권한을 확인한다는 점을 기억하세요.

async private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
{
    // Get permission for a background task from the user. If the user has already answered once,
    // this does nothing and the user must manually update their preference via PC Settings.
    BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();

    // Regardless of the answer, register the background task. Note that the user can use
    // the Settings app to prevent your app from running background tasks.
    // Create a new background task builder.
    BackgroundTaskBuilder geofenceTaskBuilder = new BackgroundTaskBuilder();

    geofenceTaskBuilder.Name = SampleBackgroundTaskName;
    geofenceTaskBuilder.TaskEntryPoint = SampleBackgroundTaskEntryPoint;

    // Create a new location trigger.
    var trigger = new LocationTrigger(LocationTriggerType.Geofence);

    // Associate the location trigger with the background task builder.
    geofenceTaskBuilder.SetTrigger(trigger);

    // If it is important that there is user presence and/or
    // internet connection when OnCompleted is called
    // the following could be called before calling Register().
    // SystemCondition condition = new SystemCondition(SystemConditionType.UserPresent | SystemConditionType.InternetAvailable);
    // geofenceTaskBuilder.AddCondition(condition);

    // Register the background task.
    geofenceTask = geofenceTaskBuilder.Register();

    // Associate an event handler with the new background task.
    geofenceTask.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);

    BackgroundTaskState.RegisterBackgroundTask(BackgroundTaskState.LocationTriggerBackgroundTaskName);

    switch (backgroundAccessStatus)
    {
    case BackgroundAccessStatus.Unspecified:
    case BackgroundAccessStatus.Denied:
        rootPage.NotifyUser("This app is not allowed to run in the background.", NotifyType.ErrorMessage);
        break;

    }
}


3단계: 백그라운드 알림 처리하기

사용자에게 알리기 위해 취해야 하는 조치는 앱이 수행하는 작업에 따라 달라집니다. 다만 알림 메시지를 표시하거나, 오디오 사운드를 재생하거나, 라이브 타일을 업데이트할 수는 있습니다. 이 단계의 코드는 알림을 처리합니다.

async private void OnCompleted(IBackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs e)
{
    if (sender != null)
    {
        // Update the UI with progress reported by the background task.
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            try
            {
                // If the background task threw an exception, display the exception in
                // the error text box.
                e.CheckResult();

                // Update the UI with the completion status of the background task.
                // The Run method of the background task sets the LocalSettings.
                var settings = ApplicationData.Current.LocalSettings;

                // Get the status.
                if (settings.Values.ContainsKey("Status"))
                {
                    rootPage.NotifyUser(settings.Values["Status"].ToString(), NotifyType.StatusMessage);
                }

                // Do your app work here.

            }
            catch (Exception ex)
            {
                // The background task had an error.
                rootPage.NotifyUser(ex.ToString(), NotifyType.ErrorMessage);
            }
        });
    }
}


개인 정보 보호 설정 변경하기

위치 개인 정보 보호 설정에서 앱으로 사용자의 위치에 액세스하도록 허용하지 않는 경우, 설정 앱의 위치 개인 정보 보호 설정으로 연결되는 간편 링크를 제공하는 것이 좋습니다. 이 예제에서는 하이퍼링크 컨트롤을 사용하여 ms-settings:privacy-location URI로 이동합니다.

<!--Set Visibility to Visible when access to the user's location is denied. -->  
<TextBlock x:Name="LocationDisabledMessage" FontStyle="Italic"
                 Visibility="Collapsed" Margin="0,15,0,0" TextWrapping="Wrap" >
          <Run Text="This app is not able to access Location. Go to " />
              <Hyperlink NavigateUri="ms-settings:privacy-location">
                  <Run Text="Settings" />
              </Hyperlink>
          <Run Text=" to check the location privacy settings."/>
</TextBlock>

아니면 앱으로 LaunchUriAsync 메서드를 호출하여 코드에서 설정 앱을 시작해도 됩니다. 자세한 내용은 Windows 설정 앱 시작하기를 참조하세요.

using Windows.System;
...
bool result = await Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-location"));

앱 테스트/디버깅하기

지오펜싱 앱을 테스트하고 디버깅하는 것은 디바이스의 위치에 따라 앱이 달라지기 때문에 어려울 수 있습니다. 여기서는 포그라운드 및 백그라운드 지오펜스를 모두 테스트하기 위한 몇 가지 메서드를 간략하게 설명해 드리겠습니다.

지오펜싱 앱을 디버그하려면

  1. 디바이스를 새 위치로 물리적으로 이동시키세요.
  2. 현재의 물리적 위치를 포함하는 지오펜스 지역을 생성해서 지오펜스 입력을 테스트하세요. 그 결과 사용자는 이미 지오펜스 내부에 있고, "지오펜스 입력됨" 이벤트가 즉시 트리거됩니다.
  3. Microsoft Visual Studio 에뮬레이터를 사용하여 디바이스의 위치를 시뮬레이션하세요.

포그라운드에서 실행 중인 지오펜싱 앱 테스트/디버깅하기

포그라운드에서 실행되는 지오펜싱 앱을 테스트하려면

  1. Visual Studio에서 앱을 빌드하세요.
  2. Visual Studio 에뮬레이터에서 앱을 시작하세요.
  3. 이 도구들을 사용하여 지오펜스 지역 내부 및 외부의 다양한 위치를 시뮬레이션하세요. DwellTime속성에 지정된 시간이 지나서 이벤트가 트리거될 때까지 충분히 오래 기다려야 합니다. 앱에 대한 위치 권한을 활성화하려면 메시지를 허용해야 합니다. 위치 시뮬레이션 방법에 대한 자세한 내용은 디바이스의 시뮬레이션 대상 Geolocation 설정하기를 참조하세요.
  4. 에뮬레이터를 사용하면 펜스의 크기 및 다른 속도로 감지하는 데 필요한 지속 시간의 근사치를 예측할 수도 있습니다.

백그라운드에서 실행 중인 지오펜싱 앱 테스트/디버깅하기

백그라운드에서 실행되는 지오펜싱 앱을 테스트하려면

  1. Visual Studio에서 앱을 빌드하세요. 앱은 위치 백그라운드 작업 유형을 설정해야 합니다.
  2. 먼저 앱을 로컬로 배포하세요.
  3. 로컬로 실행 중인 앱을 닫으세요.
  4. Visual Studio 에뮬레이터에서 앱을 시작하세요. 백그라운드 지오펜싱 시뮬레이션은 에뮬레이터 내에서 한 번에 한 개의 앱에서만 지원됩니다. 에뮬레이터 내에서 여러 지오펜싱 앱을 시작하지 마세요.
  5. 에뮬레이터에서 지오펜스 지역 내부 및 외부의 다양한 위치를 시뮬레이션하세요. DwellTime이 지나 이벤트가 트리거될 때까지 충분히 오래 기다려야 합니다. 앱에 대한 위치 권한을 활성화하려면 메시지를 허용해야 합니다.
  6. Visual Studio를 사용하여 위치 백그라운드 작업을 트리거하세요. Visual Studio에서 백그라운드 작업을 트리거하는 방법에 대한 자세한 내용은 백그라운드 작업 트리거 방법을 참조하세요.

앱 문제 해결

앱으로 위치에 액세스하려면 먼저 디바이스에서 위치를 활성화해야 합니다. 설정 앱에서 다음 위치 개인 정보 보호 설정이 켜져 있는지 확인하세요.

  • 이 디바이스의 위치켜져 있습니다(Windows 10 Mobile에는 적용되지 않음).
  • 위치 서비스 설정인 위치켜져 있습니다.
  • 사용자의 위치를 사용할 수 있는 앱 선택 하위에서 앱이 켜짐으로 설정됩니다.