André Alves de Lima

Talking about Software Development and more…

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 handlerPosicaoButton_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

Newsletter do André Lima

* indicates required



Powered by MailChimp

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *