29 07 2015
Geolocalização em Windows Apps
O mundo super conectado de hoje em dia faz com que seja cada vez mais importante sabermos a localização (coordenadas) onde o dispositivo do usuário se encontra. Por sorte, ao desenvolvermos Windows Apps (aplicativos para a interface moderna do Windows 8/10, ou “Metro Apps“), temos à nossa disposição uma classe que facilita a questão de geolocalização. Essa classe é a Geolocator, e é ela que iremos estudar no artigo de hoje.
A necessidade mais simples que podemos ter quanto à geolocalização ao desenvolvermos aplicativos é sabermos qual coordenada o dispositivo se encontra no momento. Essa é uma tarefa extremamente simples quando utilizamos as APIs do WinRT.
Para demonstrar essa funcionalidade, vamos criar um novo projeto do tipo Windows Apps / Blank App. No Grid da MainPage, vamos adicionar um StackPanel com três TextBoxes e um Button:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Width="200"
Margin="50"
HorizontalAlignment="Left">
<TextBox x:Name="LatitudeTextBox"
Header="Latitude"
IsEnabled="False"/>
<TextBox x:Name="LongitudeTextBox"
Header="Longitude"
IsEnabled="False" />
<TextBox x:Name="FonteTextBox"
Header="Fonte"
IsEnabled="False" />
<Button x:Name="PosicaoButton"
Content="Posição"
HorizontalAlignment="Stretch"
Click="PosicaoButton_Click" />
</StackPanel>
</Grid>
Feito isso, vamos até o code-behind da nossa Window, onde devemos criar uma instância da classe Geolocator e, no clique do botão, vamos chamar o método GetPositionAsync para lermos a posição atual do dispositivo (note que o event handler “PosicaoButton_Click” deve ser assíncrono pois o método GetPositionAsync é assíncrono):
private Windows.Devices.Geolocation.Geolocator _geoLocator = new Windows.Devices.Geolocation.Geolocator();
private async void PosicaoButton_Click(object sender, RoutedEventArgs e)
{
var position = await _geoLocator.GetGeopositionAsync();
ReadPosition(position);
}
private void ReadPosition(Windows.Devices.Geolocation.Geoposition position)
{
LatitudeTextBox.Text = position.Coordinate.Point.Position.Latitude.ToString();
LongitudeTextBox.Text = position.Coordinate.Point.Position.Longitude.ToString();
FonteTextBox.Text = position.Coordinate.PositionSource.ToString();
}
Simples, não? Pois execute a aplicação, clique no botão e veja o resultado:
WinRT information: The required device capability has not been declared in the manifest.
Como a mensagem de erro claramente indica, temos que declarar a capability de “Location” no manifesto da nossa aplicação, caso contrário não teremos permissão para executar uma leitura das coordenadas.
Adicionando a capability de “Location”
Adicionar a capability de “Location” no manifesto da aplicação é muito simples. Basta abrirmos o manifesto da aplicação (duplo clique em cima do arquivo Package.appxmanifest no Solution Explorer), irmos até a aba “Capabilities” e marcarmos a opção “Location“:
Feito isso, ao executarmos novamente a aplicação e clicarmos no botão “Posição“, o Windows perguntará se a aplicação pode utilizar a sua localização. Caso o usuário permita, os TextBoxes receberão as coordenadas que o Geolocator retornar:
Fontes de geolocalização no Windows 8
Como você pode perceber, o Windows 8 consegue ler as coordenadas de diferentes fontes. No exemplo acima, a coordenada utilizada foi a retornada pelo roteador WiFi. As fontes de dados disponíveis para geolocalização no Windows 8.1 são:
Cellular: posição obtida através de triangulação de antenas
Satellite: posição obtida através do GPS
WiFi: posição obtida através do roteador WiFi
IPAddress: posição obtida através do endereço IP
Por padrão, o Windows tentará obter as coordenadas utilizando a fonte que estiver disponível e que gaste a menor quantidade de energia possível dada a precisão estabelecida. Não conseguimos especificar que queremos explicitamente saber as coordenadas utilizando o GPS. O máximo que podemos fazer é configurar uma precisão alta (utilizando as propriedades DesiredAccuracy ou DesiredAccuracyInMeters).
Tracking da posição atual
Até agora vimos o quão simples é ler a posição atual através do clique de um botão. Mas, e se quisermos fazer um “tracking” da posição do dispositivo, atualizando as coordenadas sempre que o usuário alterar a sua posição? Isso é muito fácil também, uma vez que a classe Geolocator possui o evento PositionChanged, que é disparado justamente quando o dispositivo é movido.
Para demonstrar esse efeito, vamos adicionar mais um TextBox e um Button dentro do nosso StackPanel:
<StackPanel Width="200"
Margin="50"
HorizontalAlignment="Left">
<TextBox x:Name="LatitudeTextBox"
Header="Latitude"
IsEnabled="False"/>
<TextBox x:Name="LongitudeTextBox"
Header="Longitude"
IsEnabled="False" />
<TextBox x:Name="FonteTextBox"
Header="Fonte"
IsEnabled="False" />
<TextBox x:Name="TrackingStatusTextBox"
Header="Tracking Status"
IsEnabled="False" />
<Button x:Name="PosicaoButton"
Content="Posição"
HorizontalAlignment="Stretch"
Click="PosicaoButton_Click" />
<Button x:Name="TrackingButton"
Content="Começar Tracking"
HorizontalAlignment="Stretch"
Click="TrackingButton_Click" />
</StackPanel>
Após isso, vamos até o code-behind da janela para implementarmos o tratamento do clique desse novo botão:
private void TrackingButton_Click(object sender, RoutedEventArgs e)
{
_geoLocator.PositionChanged += _geoLocator_PositionChanged;
_geoLocator.StatusChanged += _geoLocator_StatusChanged;
TrackingButton.IsEnabled = false;
}
private void _geoLocator_PositionChanged(Windows.Devices.Geolocation.Geolocator sender, Windows.Devices.Geolocation.PositionChangedEventArgs args)
{
ReadPosition(args.Position);
}
private void _geoLocator_StatusChanged(Windows.Devices.Geolocation.Geolocator sender, Windows.Devices.Geolocation.StatusChangedEventArgs args)
{
TrackingStatusTextBox.Text = args.Status.ToString();
}
Execute o aplicativo, clique no botão de “Tracking” e aprecie o novo erro que recebemos:
The application called an interface that was marshalled for a different thread.
Isso acontece porque o evento PositionChanged e StatusChanged do Geolocator acontecem em outra thread, e não na thread de UI. Dessa forma, se tentarmos atualizar qualquer coisa relacionada à interface, receberemos esse erro. Para resolvermos essa situação, temos que utilizar o Dispatcher para atualizarmos a UI. Veja como fica o código utilizando o Dispatcher:
private async void _geoLocator_PositionChanged(Windows.Devices.Geolocation.Geolocator sender, Windows.Devices.Geolocation.PositionChangedEventArgs args)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => ReadPosition(args.Position));
}
private async void _geoLocator_StatusChanged(Windows.Devices.Geolocation.Geolocator sender, Windows.Devices.Geolocation.StatusChangedEventArgs args)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => TrackingStatusTextBox.Text = args.Status.ToString());
}
Com essa alteração, ao executarmos a aplicação novamente e clicarmos no botão de “Tracking“, o Geolocator nos informará sempre que o dispositivo mudar de posição:
Caso você fique curioso, na documentação do MSDN você encontra os possíveis valores e descrições para o enumerador PositionStatus.
Concluindo
Neste artigo você viu como é fácil requisitar a posição atual do dispositivo ao desenvolvermos Windows Apps. Você viu também que não temos que nos preocupar em lidar com o GPS, pois o Windows automaticamente retornará a posição utilizando fontes alternativas dependendo da precisão configurada no Geolocator. Por fim, você viu também a facilidade em se implementar o “tracking” da posição atual do dispositivo utilizando o evento PositionChanged.
Agora, você está esperando o que? Em 15 minutos você consegue implementar suporte a geolocalização nos seus Windows Apps. Não perca mais tempo e utilize o que você aprendeu nesse artigo nas suas próprias aplicações!
Antes de me despedir, convido você a assinar a minha newsletter. Ao fazer isso, você receberá toda semana o meu comentário sobre o artigo publicado, ficará sabendo em primeira mão sobre o tema do artigo da próxima semana e, o mais legal de tudo, você receberá dicas extras que eu só compartilho por e-mail. Assine agora mesmo utilizando este link ou o formulário logo abaixo.
Até a próxima!
André Lima
Photo by Walt Stoneburner used under Creative Commons
https://www.flickr.com/photos/waltstoneburner/6170496511
Mudando o ícone do aplicativo em tempo de execução O que são grupos de mastermind (mastermind groups)?