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)?