quarta-feira, 20 de novembro de 2013

Mapas, V2

Olá à todos.

Até dezembro de 2012, Mapas em Android eram mostrados de maneira bem básica, inflados em 2 dimensões e visualizados apenas de um ângulo. E tudo que precisávamos fazer para acessá-lo era declarar um projeto na SDK de Google Maps (Google API’s):


E declarar permissões no arquivo AndroidManifest.xml, como a permissão de Internet: <uses-permission android:name="android.permission.INTERNET"/>; e também a tag <uses-library android:name="com.google.android.maps"/>, também no AndroidManifest.xml.

E por fim, criar uma classe que extendesse da classe MapView.

Porém, em dezembro de 2012, a Google descontinuou esta versão, tornando-a deprecated (obsoleta), e criando uma nova, que é conhecida como Google Maps V2, tornando a versão anterior obsoleta. Por este motivo, neste tópico da apostila, sempre que falarmos de Mapas, estaremos falando dos mapas do Google Maps V2.

Logo, este post do Blog NÃO É MAIS FUNCIONAL, uma vez que a versão anterior de mapas em Android foi descontinuada.


Mapas V2


Com a nova versão de mapas, muitas melhorias foram realizadas. Ela possui mais funcionalidades, como: utilizar vetores para suportar visualizações 2D e 3D, o que torna a transição de renderização de mapas menos custosa; possibilitar a visualização de mapas por diversos ângulos; dentre outras, que veremos neste tópico.

E agora, ao invés de utilizarmos uma View (a MapView),  utilizaremos Fragments, que nada mais é do que uma View reutilizável que funciona em qualquer lugar de um layout.

Antes de criarmos um projeto que utilize Mapas em Android, precisamos: baixar o projeto Google Play Services; configurar nosso AndroidManifest.xml para as novas permissões advindas da V2; criar um projeto no Google API’s Console; obter uma chave de acesso ao Google Maps.

Na V2, o projeto Google Play Services é a classe que contém a API de mapas. Essa biblioteca é instalado pelo SDK Manager, na pasta Extras, no item Google Play Services:


Após o download deste projeto, é necessário importa-lo para o Eclipse. Para isto, basta clicarmos com o botão direito do mouse no Package Explorer, e depois em Import Android Existing Android Code Into Workspace, e então achar o projeto Google Play Services, que se localiza em /android-sdk/extras/google/google_play_services.


Então, precisamos criar um projeto para testar nossos mapas, e referenciar a biblioteca google-play-services_lib neste projeto:


O próximo passo é configurar as permissões do AndroidManifest.xml:



Repare os trechos de código circulados em vermelho. Para que nossos mapas funcionem, tudo que precisamos são esses trechos em nosso arquivo AndroidManifest.xml.

O primeiro trecho é a permissão para utilizarmos os mapas em Android. Repare que o prefixo do atributo android:name é o caminho do pacote da nossa aplicação. Esta permissão é bem específica.

O segundo trecho compreende mais permissões, sendo que apenas a primeira delas é análoga a permissão do primeiro trecho, uma vez que utiliza como prefixo o caminho do pacote da nossa aplicação.

O terceiro trecho compreende uma definição realizada para utilizarmos uma renderização melhorada para mapas em 3D.


O quarto trecho sinaliza uma mudança realizada pela Google em novembro de 2013. A partir deste mês, mapas em Android sem esta tag pararam de funcionar. Junto com esta mudança, veio a necessidade de se atualizar a biblioteca google-play-services_lib, e também mudou o layout do cadastro do nosso projeto do Google Maps, no site do Google Cloud Console.

O trecho final é a chave do Google Maps que precisamos ter para executar qualquer mapa. A obtenção deste chave será apresentada mais adiante, neste mesmo tópico.

Após a configuração do AndroidManifest.xml, o próximo passo é criar um projeto no Google Cloud Console.

Conforme mencionado no início desta página, em novembro de 2013 a Google mudou o layout do Google Cloud Console. Agora, para criar um projeto no Google Cloud Console, precisamos fazer login com uma conta de e-mail em https://cloud.google.com/console/

Então, será mostrada uma tela com o botão Create Project. Nesta página, criamos o projeto no servidor da Google (por exemplo, um projeto chamado “GoogleMapsProject”). Depois da criação do projeto, a página será redirecionada para um novo endereço, onde o nome do projeto faz parte da URL: https://cloud.google.com/console#/project/apps~steam-aria-415


Depois da criação do projeto, será mostrada uma tela parecida com a tela abaixo:



Agora, precisamos dar ao nosso aplicativo permissão para o Google Maps Android API v2. Para ativá-la, precisaríamos entrar no menu APIs & auth, e rolar a barra de rolagem até encontrar a opção Google Maps Android API v2. Então, mudar o checkbox do status para ON.

Após isto, o próximo passo seria clicar na aba Registered apps e então clicar no botão vermelho Register App. Então, será mostrada uma tela pedindo o nome do aplicativo de Android que queremos criar, e um rabio button pedindo a plataforma, ao qual marcaremos a opção “Android”.


Ao clicarmos no radio button “Android”, será pedido o “Package name” do nosso projeto, e o “SHA1 fingerprint”. No campo “Package name”, digitamos o caminho completo do nosso projeto (por exemplo, br.example.mapasv2). E no campo “SHA1 fingerprint” digitamos um valor que pode ser obtido tal qual é descrito abaixo.

Chaves Google Maps


Para gerar esta chave, primeiramente, precisamos o SHA-1 fingerprint de certificado para compilar o projeto. Para obtermos isso, precisamos primeiramente localizar o arquivo debug.keystore do nosso SDK do Android. Seu caminho pode ser encontrado através dos menus Window Preferences Android Build, do Eclipse.

Após obter o caminho deste arquivo, precisamos baixar um plugin do Eclipse para gerar o SHA-1. Para baixarmos este plugin, precisamos acessar o menu Help Install New Software, e então em “Work with:”, clicar em “Add...” e em “Location:” digitar http://keytool.sourceforge.net/update

E então realizar o download do plugin. Após isso, o Eclipse será reiniciado, e após isto, será mostrado um novo menu, chamando Keytool. Agora, precisamos abrir este menu, e clicar em “Open keystore”. Então, será mostrada a seguinte tela:


Em “Filename:”, precisamos passar o caminho do arquivo debug.keystore. Já em “Password:”, precisamos digitar android.

Após isto, será aberta uma nova aba no Eclipse, conforme mostrado abaixo.


Então, precisamos clicar em androiddebugkey, e será mostrada a seguinte tela:


E pronto! Conseguimos nosso SHA-1.

O próximo passo para obter a chave do Google Maps é copiar o valor do SHA-1, voltar para o Google Cloud Console, e colar o valor do SHA-1, e então no botão Register.


Então, será aberta uma nova janela (mostrada abaixo), e abrir a opção “Android Key”.


Após isto, será aberta uma nova tela, com o valor da nossa chave do Google Maps.



Agora, basta colarmos o valor desta chave em nosso AndroidManifest.xml, e executar nossa aplicação de mapas.

Exibindo um mapa


Então vamos lá, criar nossa primeira aplicação de mapas.

Um mapa da API V2 não utiliza mais uma MapView, mas sim um Fragment. Fragments foram introduzidos no Android a partir da API 11 (Android 3.0, Honeycomb). Por isso, a fim de que API’s tanto inferiores como superiores ao Honeycomb utilizem estes mapas, utilizaremos a classe SupportMapFragment, que possibilita que versões inferiores à Honeycomb consigam rodar os mapas da V2.

Nosso exemplo simplesmente mostrará um mapa, e para isso tudo que precisamos (além do nosso já configurado AndroidManifest.xml) é definir nosso mapa em um layout de XML, e que a tela principal da nossa aplicação extenda de FragmentActivity.

Eis o layout que inflará nosso mapa:


O mapa será inflado no fragment, que referencia a tela principal através do atributo class.

Eis a tela principal ao qual este fragment referencia:


Antes desse projeto ser executado, algo precisa ser esclarecido. A API V2 de mapas não suporta o emulador de Android. Logo, precisamos executar este projeto (e qualquer projeto que utilize mapas) em um dispositivo Android com depuração USB.

O resultado gerado pela execução do nosso projeto é mostrado na figura abaixo.

Repare que, automaticamente, nos é dado um controle de zoom. Em Android, o zoom varia de 2 até 21. A partir do zoom 17, começamos a obter renderizações de mapas em 3D.



Modos de visualização


Podemos visualizar um mapa em Android através do método setMapType da classe GoogleMap, onde podemos informar as seguintes constantes:

  • GoogleMap.MAP_TYPE_NONE → Modo de visualização mais simples do mapa, de forma que nenhuma informação extra será exibida.
  • GoogleMap.MAP_TYPE_NORMAL → Modo de visualização padrão nos mapas, onde podemos visualizar as ruas, estradas e rios.
  • GoogleMap.MAP_TYPE_SATELLITE → Modo de visualização com os dados de satélite.
  • GoogleMap.MAP_TYPE_HYBRID → Modo de visualização com os dados fotográficos do satélite, com os mapas das ruas. Este é o modo de satélite mais detalhado.
  • GoogleMap.MAP_TYPE_TERRAIN → Modo de visualização que exibe os dados topográficos do mapa.

Trabalhando com coordenadas


Para trabalharmos com coordenadas de um mapa, precisamos obter a instância do nosso mapa, e então utilizar esta instância na classe CameraUpdate.

Para obter a instância, utilizamos as linhas de código abaixo:


Através do método getSupportFragmentManager(), e seu sub-método findFragmentById(), conseguimos obter o fragmento que infla o nosso map. E através do método getMap(), conseguimos obter o mapa que é inflado no fragmento.

Com esta instância, conseguimos, por exemplo, setar o modo de visualização do nosso mapa, através do método setMapType().

Uma vez que temos a instância do mapa, já podemos utilizar a classe CameraUpdate. Com ela, podemos setar o mapa em uma coordenada específica, tal qual mostrado abaixo:


Utilizando o método CameraUpdateFactory.newLatLngZoom(), ao mesmo tempo setamos a coordenada que desejamos centrar no mapa, e setamos o zoom em 15. O método que, de fato, centra o mapa na coordenada que especificamos, é o método moveCamera().

Outra maneira de trabalhar com coordenadas é da maneira mostrada abaixo:


Qual é a diferença entre estas 2 metodologias de centrar o mapa em uma coordenada específica? Pelo segundo método, conseguimos obter mais informações. Isto será melhor explicado ainda neste tópico.

Controle de zoom


Conseguimos controlar o zoom de nosso mapa através dos métodos:

  • CameraUpdateFactory().zoomIn() → Aumenta o zoom do mapa em 1.
  • CameraUpdateFactory().zoomOut() → Diminui o zoom do mapa em 1.
  • CameraUpdateFactory().zoomTo(zoom) → Configura o valor do zoom utilizado pelo mapa.
  • CameraUpdateFactory().zoomBy(zoom) → Aumenta ou diminui o zoom do mapa, conforme o valor informado.

Tilt e Bearing


Conforme explicado anteriormente, pelo segundo método conseguimos obter mais informações. Mas que informações seriam essas? Seriam o Tilt e o Bearing. Bearing é o deslocamento que o mapa pode ter, no plano horizontal. E Tilt é o deslocamento que o mapa pode ter, no sentido vertical. Ambos podem ser chamados da seguinte maneira:


Ou seja, através do construtor CameraPosition.Builder(). A melhor maneira de entender como as propriedades Bearing e Tilt funcionam é modificando os parâmetros deste construtor, e verificando como o mapa se comporta com a calibragem destes parâmetros.

GPS


Por fim, aprenderemos a utilizar um GPS.

Para obtermos informações sobre o GPS, precisamos definir uma classe que implementa um LocationSource. Esta classe será utilizada como atributo de classe da nossa classe MainActivity.java. Eis a implementação desta classe:


Esta é a classe que, de fato, utilizará o GPS em nossa aplicação.

Eis como ela é chamada na nossa tela principal, que agora passou a ser chamada MapaV2.java:


O que temos de novo em nossa tela principal é:


Porém, apenas definimos o LocationSource. De fato, a verificação do status do GPS (se está ligado ou não), e a atualização da posição em que o usuário se encontra, são feitos na classe abaixo, que extende de MapaV2.java:


O que podemos notar nesta classe é:
  • Primeiramente, verificamos se o GPS está ligado. Se estiver, chamamos o método requestLocationUpdates(), para obtermos as atualizações de posição do usuário, através do GPS.
  • Caso o GPS não esteja ligado, mostramos na tela um Dialog, e caso o usuário aceite ligar o GPS, o redirecionamos para a tela de configurações, onde ele poderá ativar o GPS.
  • Após estas verificações:
    • No evento onPause() (ou seja, se pausarmos ou sairmos do nosso aplicativo), removemos as requisições de atualização de posição do usuário.
    • No evento onLocationChanged() (ou seja, quando a localização do usuário mudar), atualizamos a posição central da tela, uma vez que o usuário se deslocou pelo mapa.
    • Implementamos nada nos eventos seguintes (onProviderDisabled(), onProviderEnabled() e onStatusChanged()), pois, por hora, suas funções não nos interessam.

Desta forma, conseguimos obter com bastante precisão a localização do usuário no mapa, mesmo que ele se desloque.

-----

Agora somos capazes de chamar mapas bem mais modernos em nossas aplicações de Android. Existem muitas outras opções de uso de mapas. Porém, elas serão vistas em outros tópicos deste blog.

Caso alguém tenha uma dúvida, crítica ou sugestão, sinta-se à vontade.

16 comentários:

  1. Rodrigo, estou rodando seu exemplo em um android 2.2 API - Level 8, e está dando pau ao iniciar... utilizei o exemplo básico, você saberia me informar se esse exemplo é compatível com essa versão?

    (Parabéns pelo post!!!)

    Obrigado

    ResponderExcluir
  2. Recentemente o Google lançou uma nova verão da lib google_play_services que precisa ser atualizada pelo SDK Manager.

    Isto impactou nos exemplos dos Mapas V2.

    Depois de atualizar a lib, coloque essa linha dentro da tag

    ResponderExcluir
  3. Pronto, Eduardo Batistão.
    Este tópico do Blog já foi atualizado, e agora explica em detalhes o que é necessário para utilizarmos a nova versão do Google Maps, recém modificada (em novembro de 2013).

    ResponderExcluir
  4. Olá Rodrigo obrigado pela prontidão, realmente acredito que agora vai... mas a questão que quando rodo seu exemplo aqui no meu froyo api level 8 (celular físico), ele pede para atualizar o google play service, você ja chegou realizar essa atualização alguma vez, poderia me enviar os passos? No ambiente virtual realmente não vai !!!
    Obrigado!

    ResponderExcluir
  5. Nunca percebi essa mensagem. Mas um aluno meu já me relatou isso em um celular com Eclair (versão 2.1, API level 7). E no caso dele, não teve como rodar.
    Você tentou atualizar o SDK do Android pelo Eclipse?
    E o que você quer dizer com "no ambiente virtual não vai"?

    ResponderExcluir
    Respostas
    1. Tipo se eu rodo pelo emulador (AVD), dá pau....

      Excluir
    2. "Antes desse projeto ser executado, algo precisa ser esclarecido. A API V2 de mapas não suporta o emulador de Android. Logo, precisamos executar este projeto (e qualquer projeto que utilize mapas) em um dispositivo Android com depuração USB."

      Eu menciono isto no tópico.

      Excluir
    3. vou arranja um celular mais novo urgente rsss

      muito obrigado

      Excluir
    4. De nada. Precisando é só perguntar.

      Excluir
  6. Amigo, sabe me dizer se é possível a partir de um endereço capturar sua latitude e longitude e depois colocar um Marker nele?
    Sabe qual biblioteca utilizo?
    Obrigado.

    ResponderExcluir
  7. Sim, tem como. Confira o link abaixo:
    http://stackoverflow.com/questions/20814802/google-maps-android-api-v2-show-marker-on-zoom-level

    Em caso de dúvidas, estou à disposição!

    ResponderExcluir
    Respostas
    1. Opa!! Muito obrigado... E se eu quisesse usar a minha localização atual, usando esta estrutura que você criou com a classe GPS que valida se está ou não ligada, como poderia implementar a classe principal?

      Excluir
  8. Seria algo similar è este tópico:

    http://stackoverflow.com/questions/15142089/how-to-display-my-location-on-google-maps-for-android-api-v2

    ResponderExcluir
  9. porque quando damos o zoom no mapa criado ele não fica no zoom selecionado pelo usuario, mais ele fica voltando para o zoom inicial?

    ResponderExcluir
    Respostas
    1. Aqui pra mim funcionou. Estranho não ter rolado contigo. Você poderia me dar maiores detalhes do seu erro?

      Excluir