News & Events
MapView: Utilizando mapas no iOS e Android com Delphi ou C++ XE8
- 14 de agosto de 2015
- Posted by: Adriano Santos
- Category: Tutoriais vídeo vídeo-aula vídeo-aulas XE8 [Arquivo] [Tutorial]
O desenvolvimento de aplicativos para as plataformas iOS e Android tem sido tema de diversos blogs e sites voltados a linguagens de programação. E em se tratando de mobile há outro tema bastante procurado e que nos faz receber muitas mensagens: Mapas. Como utilizar mapas do iOS e Android em aplicativos de forma fácil e natural? Não entraremos em detalhes de desenvolvimento nesse post, mas mostraremos os passos iniciais para se criar um pequeno app.
MapView: Utilizando mapas no iOS e Android
Há basicamente duas formas de se trabalhar com mapas nativamente no Delphi. Utilizando-se de WebBrowser ou ainda o novo componente MapView do RAD Studio XE8. Utilizando WebBrowser talvez muitos acharão muito mais complicado, pois o requisito mínimo é conhecer bem as APIs de mapas do Google. Mesmo programando para iOS, podemos utilizar os métodos HTTP GET e POST para fazer as chamadas às APIs e mostrar o que precisamos no WebBrowser, tais como: marcadores, direções, e outros elementos. Mas como mencionamos, você precisará conhecer muito o Google APIs.
Há, evidentemente, outras formas, como a compra de componentes de terceiros para utilização de mapas. Mas costumam ser caros e complicados. Fica a critério de cada um. O que veremos aqui é o uso do TMapView.
O componente MapView, da paleta Services, foi incorporado no RAD Studio e Delphi/C++ XE8 e sua maior vantagem é que ele usa nativamente as APIs do Google Maps quando distribuído para Android e as respectivas APIs do iOS quando distribuído para iPhone, iPad e iPod Touch. É possível plotar marcadores, direções, interagir com distâncias e tudo que há de recursos de mapas.
Configurações especiais Android
O uso do MapView no iOS não requer nenhuma configuração especial além de inserir um componente em tela. Já no Android a coisa complica um pouco mais, mas não se assuste, é relativamente fácil apesar do trabalho que dá preparar o aplicativo.
A primeira coisa a se fazer é cadastrar-se com uma conta Google no console de desenvolvedor do grande G. Acesse o site https://console.developers.google.com/. Caso não esteja logado com sua conta do Google (Gmail por exemplo), o site solicitará seu login e senha e você então cairá em uma tela inicial, como mostrado na Figura 1.
Figura 1. Primeiro acesso ao console do Google
Basta clicar em “Criar um projeto vazio“. Toda interação entre serviços do Google precisa ter necessariamente um projeto criado nesse painel, inclusive o uso de Push Notifications, tema para outro post. Após isso você cairá em uma tela onde poderemos fazer todas as configurações nos serviços que utilizaremos. No menu à esquerda escolha primeiro o item APIs em seguida localize a opção Google Maps Android API como na Figura 2.
Clique no botão Enable API. Isso ativará o serviço para que possamos ter acesso ao serviço através do Delphi ou C++ Builder.
O próximo passo é solicitar uma API Key, uma chave única que identifica o uso de mapas no seu aplicativo Android. Isso é feito pelo item Credentials. Clique nele e em seguida no botão Create a new Key. Na pop-up aberta, clique em Android Key. Você pode ver esses passos nas Figuras 3 e 4.
Aqui o processo se complica um pouco, mas vamos devagar. O Google requer uma chave SHA1 conforme mostrado na janela. Essa chave pode ser gerada pelo aplicativo KeyTool.exe presente no diretório de SDK do Android ou ainda no diretório do Java criado no momento da instalação do Delphi, normalmente em C:\Program Files\Java\jdk1.7.0_71\bin\keytool.exe. Mas para que possamos gerar a chave, necessitamos de um arquivo de certificado do Google gerado em Project > Options > Provisioning. Entretanto, só conseguimos gerar esse arquivo quando estamos “buildando” o nosso projeto para a loja Google Play que no momento não é nosso caso. Portanto vamos usar o arquivo de certificado gerado automaticamente pelo Delphi.
No diretório C:\Users\NOME_DO_USUARIO\AppData\Roaming\Embarcadero\BDS\16.0 você encontrará o arquivo debug.keystore. Esse arquivo é gerado toda vez que nós “buildamos” algo em Delphi para Android, por isso para termos certeza de que o arquivo gerado no diretório refere-se ao nosso aplicativo, apague esse arquivo do diretório.
Mantenha a tela de geração de chave no browser e abra o Delphi. Nós criaremos um app vazio para que possamos criar o arquivo .keystore. Crie um novo app e chame-se de DemoMaps.dproj. Não é necessário inserir ainda nenhum controle em tela, esse passo servirá apenas para gerar o arquivo de certificado. Builde o projeto e execute-o em seu aparelho Android. Vá até o diretório e veja que um novo debug.keystore foi gerado. Copie-o e cole-o no diretório onde encontra-se o executável KeyTool.exe.
Gerando a Chave SHA1
Agora será necessário abrir um prompt do MS-DOS em seu Windows. Faça isso e navegue até a pasta onde encontra-se o KeyTool.exe. Digite a linha de comando abaixo:
keytool -list -v -keystore debug.keystore -alias androiddebugkey -storepass android -keypass android
Você receberá um resultado semelhante ao que podemos ver abaixo:
Alias name: androiddebugkey Creation date: Jan 24, 2015 Entry type: PrivateKeyEntry Certificate chain length: 1 Certificate[1]: Owner: CN=Unnamed, OU=Mobile Organization, O=My Company, L=San Francisco, ST=California, C=US Issuer: CN=Unnamed, OU=Mobile Organization, O=My Company, L=San Francisco, ST=California, C=US Serial number: 1af9d77f Valid from: Sat Jan 24 23:12:12 GST 2015 until: Wed Jun 11 23:12:12 GST 2042 Certificate fingerprints: MD5: 20:E1:7D:12:4F:83:2A:37:FB:F5:43:3B:CC:27:88:4B SHA1: 0B:4D:1E:83:2F:91:3A:BD:92:EB:87:62:6D:34:66:9D:6A:51:3B:ED SHA256: 91:75:AC:BE:C9:74:6F:67:3E:9A:E4:35:04:D4:05:E0:8F:A4:54:30:41:4A:EB:0A:61:E0:D1:33:7C:D8:0F:82 Signature algorithm name: SHA256withRSA Version: 3
Perceba que recebemos várias chaves. Uma delas é a SHA1, essa é a mais importante. Copie essa chave inteira e retorne até a criação de chaves no site do Google Console. Você precisa colar essa chave lá e adicionar mais uma informação no final, o nome do pacote. Isso é encontrado no Project > Options na opção Version Info. Localize a célula package. Você terá algo como com.embarcadero.$(ModuleName). A chave completa no console ficará algo como:
0B:4D:1E:83:2F:91:3A:BD:92:EB:87:62:6D:34:66:9D:6A:51:3B:ED;com.embarcadero.DemoMaps
Note que adicionamos um “;” ao final da chave e em seguida o nome do pacote substituindo $(ModuleName) pelo nome de nosso app: DemoMaps. O site do Google então irá gerar automaticamente uma API Key, esse código deverá ser copiado e incluído em nosso projeto. Por isso copie a chave e volte ao Delphi em Project > Options > Version Info. Repare que a última célula da tela chama-se apikey, cole essa chave no local.
Ainda na tela Project > Options, selecione o item Entitlement List à esquerda. Localize o item Maps Service e marque essa opção. Isso finaliza nosso processo para uso de mapas em Android. Para iOS não são necessários todos esses passos.
Nessa publicação nós suprimimos alguns passo publicando apenas os mais importantes. Caso você tenha o interesse em saber mais, recomendamos ler uma publicação na DocWiki da Embarcadero nesse link.
Desenvolvendo o Projeto
Como mencionado, não vamos detalhar o projeto, mas mostrar os principais passos do desenvolvimento. Insira no projeto um TLayout com alinhamento Client e o Name igual a lytMain. Dentro do layout insira um TabControl e renomeie para tbCtrlMaps. Adicione uma TabItem. Você vai inserir nessa TabItem um Toolbar um ComboBox e um SpeedButton. Mude o StyleLoockup do SpeedButton para refreshtoolbutton. Na propriedade Items do ComboBox insira as opções: Normal, Satélite e Híbrido. Mude também o ItemIndex do Combo para 0 (Zero). Usaremos isso para selecionar o tipo de mapa a ser mostrado ao usuário.
Coloque um ListBox dentro da TabItem com o alinhamento Top. Em nosso projeto estamos pegando as coordenadas Latitude e Longitude, insira apenas uma linha do ListBox e dentro dessa linha dois TEdits com os nomes edtLat e edtLong, um alinhado à esquerda e outro à direita ou como você desejar. A ideia é pegar a posição atual e atualizar de tempo em tempo as propriedades Text de ambos edits. Insira um componente MapView com alinhamento Client dentro to TabItem. E por fim coloque um componente LocationSensor em tela e dê o nome de locSensor. A tela deverá se parecer com a Figura 5.
Codificando
Agora vamos colocar a mão na massa e codificar um pouco. Precisamos entender primeiro como o projeto deverá se comportar. A ideia principal é fazer com que o usuário veja sua localização em tempo real plotada no mapa. Já nos perguntaram se precisamos inserir um Timer na tela para que ele fique atualizando a posição, mas nossa opinião é: “Pelo amor de Deus, não façam isso :D”. O principal impacto disso é gastar bateria demais. O que precisamos fazer é mais simples do que imaginamos. Basta usar o evento OnLocationChange do componente LocationSensor. Esse componente é capaz de pegar a posição exata de onde estamos e expor a Latitude e Longitude.
Por isso vamos criar quatro variáveis na seção Private do projeto. Seguem as variáveis abaixo:
FLatitude : Double; FLongitude : Double; MyMarker : TMapMarkerDescriptor; MapCoord : TMapCoordinate; FMarkers : TList<TMapMarker>; FShowMarkers: Boolean;
As variáveis FLatitude e FLongitude vão armazenar as informações recebidas pelo LocationSensor. As demais MyMarker, MapCoord, FMarkers e FShowMarkers serão usadas para criarmos um marcador na tela do mapa.
Crie também três métodos: CenterMap, ClearPointers e vamos sobrepor o Create do Form. Veja abaixo:
procedure CenterMap; procedure ClearPointers; constructor Create(Owner: TComponent);override;
Pressione Ctrl + Shift + C para que o Delphi crie o escopo das funções e vamos a codificação de todos os métodos. Veja na Listagem 1 a codificação de todos os métodos.
procedure TMain.CenterMap; begin if FMarkers.Count = 0 then mapviewPrincipal.Location := FMarkers.Last.Descriptor.Position else mapviewPrincipal.Location := TMapCoordinate.Zero; end; constructor TMain.Create(Owner: TComponent); begin inherited; FMarkers := TList<TMapMarker>.Create; FShowMarkers := True; end; procedure TMain.ClearPointers; var Marker: TMapMarker; begin for Marker in FMarkers do Marker.Remove; FMarkers.Clear; CenterMap; end;
Listagem 1. Métodos para atualização dos marcadores
O primeiro método, CenterMap, como o próprio nome sugere, centraliza o mapa de acordo com o último pino inserido no mapa. Como iremos inserir somente um pino, estaremos sempre centralizados. Já no método Create, nós estamos criando FMarkers para uso posterior e deixando FShowMarkers como Visible = True para podermos visualizar cada ponto na tela. E por último ClearPointers. Essa função faz um loop no mapa através da variável FMarkers. Cada marcador encontrado é removido. Isso vai nos ajudar, pois a cada movimentação do celular, apagamos todos os marcadores (no nosso caso somente um marcador, o que será bem rápido) e então centralizamos o mapa.
A parte mais importante vem agora. Para que a posição serja realmente atualizada, basta programarmos o evento OnLocationChange do componente LocationSensor como já mencionado. Selecione esse componente (locSensor) e clique duas vezes no evento mencionado. Codifique-o como na Listagem 2.
procedure TMain.locSensorLocationChanged(Sender: TObject; const OldLocation, NewLocation: TLocationCoord2D); var LSettings : TFormatSettings; LDecSeparator : Char; begin {Latitude e Longitude atuais} FLatitude := NewLocation.Latitude; FLongitude := NewLocation.Longitude; edtLat.Text := FLatitude.ToString(); edtLong.Text := FLongitude.ToString(); ClearPointers; MapCoord := TMapCoordinate.Create(FLatitude, FLongitude); MapCoord.Latitude := FLatitude; MapCoord.Longitude := FLongitude; MyMarker := TMapMarkerDescriptor.Create(MapCoord, 'Localização Atual'); MyMarker.Draggable := True; MyMarker.Visible := True; mapviewPrincipal.Zoom := 15; FMarkers.Add(mapviewPrincipal.AddMarker(MyMarker)); CenterMap; end;
Listagem 2. Evento OnLocationChange
Logo no início do nosso código, nós atualizamos as variáveis FLatitude e FLongitude com os respectivos valores retirados das variáveis NewLocation e em seguida atualizamos o texto dos dois edits. Na sequência chamamos ClearPointers para apagar todos os marcadores de tela, justamente porque faremos uma nova criação de marcador com a posição atual.
Chamamos o método Create da classe TMapCoordinate passando a Latitude e Longitude. Por fim criamos um novo marcador usando a classe TMapMarkerDescriptor para gerar o marcador em si. Para finalizar chamamos o método Add da variável FMarkers passando para ela o componente MapView (No nosso caso mapviewPrincipal). E centralizamos o mapa.
Evidentemente há muitos outros detalhes a se falar, mas não temos esse tempo. Esses são os principais passos a executar. Abaixo disponibilizamos um vídeo desse protótipo funcionando corretamente em um celular Moto G 2nd geração.
Caso não consiga visualizar o vídeo, acesse diretamente o link:
https://www.youtube.com/watch?v=AC42oryoJCc
Conclusão
Como pudemos ver, não é difícil trabalhar com mapas no RAD Studio XE8. Esse exemplo mostra apenas uma quantidade bastante mínima de recursos que podem ser utilizados. Em aplicativos mais complexos podemos extrair muito mais recursos e desenvolver features extremamente avançadas, tais como: trabalhar com direções, movimentação do mapas, mapas 3D e uma série de outras coisas.
#GoToDelphi
Pessoal, algumas correções. Por algum motivo na codificação, alguns caracteres foram substituídos por caracteres estranhos. Já arrumamos isso nos códigos.
O segundo ponto é com relação a declaração da variável TList. É necessária a declaração da unit System.Generics.Collections no uses do projeto.