Criar um app de navegação iOS simples em Swift com o SDK Navigation da Plataforma Google Maps

1. Antes de começar

Este codelab ensina a criar um app iOS simples que usa o SDK Navigation da Plataforma Google Maps para navegar até um destino pré-configurado.

O app vai ter esta aparência quando você terminar.

7e7c194a98d6dfa4.png

Pré-requisitos

O que você vai aprender

  • Como criar um app iOS Swift simples que usa o SDK Navigation para navegar até um destino.
  • Como integrar o SDK Navigation do repositório remoto do Cocoapods.
  • Como gerenciar permissões de localização e o contrato do usuário com os termos do usuário final do SDK Navigation.
  • Como inicializar o SDK.
  • Como definir um destino e iniciar o trajeto.

O que é necessário

  • A versão estável mais recente do Xcode.
  • Uma Conta do Google e um projeto com o faturamento ativado.
  • Um dispositivo iOS ou um dispositivo emulado executado no Xcode Simulator. Qualquer uma das opções escolhidas precisa atender aos requisitos mínimos do SDK Navigation.

2. Começar a configuração

Se você ainda não tiver uma conta do Google Cloud Platform e um projeto na nuvem com faturamento ativado, siga as instruções em Primeiros passos com a Plataforma Google Maps para configurar seu projeto do Google Cloud.

Selecionar um projeto na nuvem do Google no console

No Console do Cloud, clique no menu suspenso do projeto e selecione o projeto que você quer usar neste codelab.

O menu suspenso do seletor de projetos no console do Google Cloud.

Ativar o SDK Navigation no seu projeto

Ative as APIs e os SDKs da Plataforma Google Maps necessários para este codelab no Google Cloud Marketplace.

Acesse APIs e serviços > Biblioteca no console do Google Cloud e pesquise "SDK Navigation".

Você vai ver um resultado da pesquisa.

A tela da biblioteca de APIs no console do Google Cloud, mostrando a página do SDK Navigation.

Clique em SDK Navigation para abrir a página de detalhes do produto. Clique em Ativar para ativar o SDK no seu projeto.

Repita esse processo para o SDK do Google Maps para iOS.

crie uma chave de API

Gere uma chave de API na página Credenciais do Console do Cloud. Todas as solicitações à Plataforma Google Maps exigem uma chave de API. Na página "Credenciais" do console. Clique em "+ Criar credenciais" na parte de cima da página e selecione "Chave de API" nas opções.

Para uso em produção, a prática recomendada é definir uma restrição de aplicativo para sua chave de API, mas isso é opcional para este codelab.

3. Acessar os arquivos do projeto de exemplo

Nesta seção, descrevemos como configurar um projeto básico de app XCode vazio clonando arquivos do repositório do GitHub para este codelab. O repositório do GitHub contém versões do código do codelab antes e depois. O codelab vai começar com um modelo de projeto vazio e criar até o estado final. Se você tiver dificuldades, use o projeto concluído no repositório como referência.

Clonar o repositório ou baixar o código

Navegue até o diretório em que você quer armazenar o codelab.

Em seguida, clone o repositório ou faça o download do código:

git clone https://github.com/googlemaps-samples/codelab-navigation-101-ios-swift

Se você não tiver o git instalado, clique neste botão para acessar o código:

Para começar o mais rápido possível, o repositório contém um código inicial na pasta Starter para ajudar você a acompanhar este codelab. Há também um projeto Solution concluído caso você queira avançar ou verificar seu progresso a qualquer momento. Para usar o projeto de solução, siga as instruções de "Instalar usando o Cocoapods" abaixo e execute o comando "pod update" na pasta solution/Navigation SDK Codelab.

Depois de clonar o repositório localmente, use o Xcode para abrir a pasta Starter como um projeto existente. Verifique se o projeto é criado e executado.

Conectar um dispositivo ou configurar o simulador do XCode

4. Adicionar o SDK Navigation ao seu app

Há três maneiras de integrar o SDK Navigation a um projeto do Xcode. Este codelab usa o CocoaPods. Para detalhes sobre como fazer a integração usando o Swift Package Manager ou instalar manualmente baixando o SDK, consulte Criar o projeto do Xcode e instalar o SDK Navigation na documentação do SDK Navigation.

Instalar usando o Cocoapods

Se você ainda não tem essa ferramenta, instale-a no macOS executando o seguinte comando no terminal. Para saber mais, consulte o Guia de primeiros passos do CocoaPods (em inglês).

sudo gem install cocoapods

Crie um arquivo chamado Podfile na pasta do projeto, dentro da pasta starter/Navigation SDK Codelab (no XCode, File > New > File > Other > Empty, salve como "Podfile")

Adicione o seguinte conteúdo ao seu Podfile:

source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '15.0'

target 'Navigation SDK Codelab' do
  pod 'GoogleNavigation', '9.1.1'
end

Economize Podfile.

Abra um terminal e mude o diretório para o local em que você salvou o Podfile (a pasta "starter/Navigation SDK Codelab" no repositório do codelab).

cd "<path-to-starter-project-folder>/Navigation SDK Codelab"

Execute o comando pod install. Isso instala as APIs especificadas no Podfile e as respectivas dependências.

pod install

Feche o Xcode e abra o arquivo .xcworkspace do projeto para iniciar o programa. Depois disso, é preciso usar o arquivo .xcworkspace para abrir o projeto.

Verifique se um diretório "Pods" foi adicionado à estrutura do projeto e se ele contém os pods "GoogleMaps" e "GoogleNavigation".

6e81772ee067d452.png

Adicionar sua chave de API

Inclua sua chave de API ao AppDelegate.swift da seguinte maneira:

  1. Adicione as seguintes declarações de importação:
import GoogleMaps
import GoogleNavigation
  1. Adicione o seguinte ao método application(_:didFinishLaunchingWithOptions:):
GMSServices.provideAPIKey("YOUR_API_KEY")

Substitua "YOUR_API_KEY" pela chave de API criada na etapa anterior.

Crie seu projeto e corrija os erros.

5. Configurar permissões do app

O SDK Navigation depende de sinais de GPS para fornecer localização ajustada à via e orientação curva a curva. Por isso, seu app precisa pedir ao usuário que conceda acesso a dados de localização exata.

Para isso, adicione algumas propriedades ao Info.plist dos apps no Xcode, adicione um código ao app para pedir permissão ao usuário durante a execução e processe erros, como permissão não concedida ou localização indisponível.

Abra o arquivo Info.plist no Xcode. A aparência será semelhante a esta.

6532a85bd9ac8fb4.png

Solicitar permissão de localização exata

Para adicionar novos valores, passe o ponteiro do mouse sobre a linha "Lista de propriedades de informações" até que um ícone "+" apareça. Clique no "+" para ver uma caixa de diálogo com nomes de propriedades sugeridos. Também é possível adicionar propriedades manualmente.

Adicione as seguintes propriedades e valores a Info.plist:

Propriedade

Valor

Privacidade - Descrição de uso de localização sempre e durante o uso

"Este app precisa da localização do seu dispositivo para oferecer navegação guiada"

Privacidade: descrição do uso de localização durante o uso

"Este app precisa da localização do seu dispositivo para oferecer navegação guiada"

allowsBackgroundLocationUpdates

SIM

Solicitar permissão de localização em segundo plano

Adicione as seguintes propriedades e valores a Info.plist:

UIBackgroundModes > Adicionar linha > Item 0: App registers for location updates (selecione esse valor na lista suspensa de sugestões)

O Info.plist vai ficar parecido com isso quando você terminar.

3b0c49018451d0ff.png

Solicitar acesso à localização no momento da execução

Adicione as seguintes declarações de importação a ViewController.swift:

import GoogleNavigation

Adicione a seguinte declaração à classe ViewController:

var locationManager: CLLocationManager!

Adicione uma substituição de método para loadView() e chame locationManager.requestAlwaysAuthorization():

override func loadView() {
        locationManager = CLLocationManager()
        locationManager.requestAlwaysAuthorization()

Agora, o app vai pedir a localização do usuário e disponibilizá-la se ele conceder permissão .

Solicitar permissão para mostrar notificações

Adicione o seguinte código a loadView() para pedir permissão ao usuário para mostrar notificações, o que é necessário para mostrar instruções de manobra de navegação.

UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) {
        granted, error in
        // Handle denied authorization to display notifications.
          if !granted || error != nil {
              print("User rejected request to display notifications.")
          }
        }

Crie e execute o app e verifique se você recebe uma solicitação para compartilhar a localização e ativar as notificações.

ad5f665a21170c49.png

6. Adicionar uma interface do usuário de navegação

Nesta etapa, você vai adicionar um mapa e configurá-lo para mostrar um local. Em seguida, mostre ao usuário uma caixa de diálogo com os Termos de Uso do SDK Navigation.

Adicionar uma visualização de mapa ao seu app

Adicione esta linha para declarar uma variável GMSMapView no seu ViewController.

var mapView: GMSMapView!

Adicione o seguinte código ao loadView() no Viewcontroller.swift para inicializar o mapa.

let camera = GMSCameraPosition.camera(withLatitude: 51.483174, longitude: -0.177369, zoom: 14)
let options = GMSMapViewOptions()
options.camera = camera
options.frame = .zero
        
mapView = GMSMapView(options: options)
view = mapView

Crie e execute o app. Você vai ver um mapa centralizado no sudoeste de Londres.

1d46ce5c0851cae3.png

Mostrar a caixa de diálogo dos termos de uso do produto do SDK do Navigation

Adicione o código a seguir a ViewController.swift no mesmo método loadView() do código anterior. Isso vai mostrar os termos de uso do usuário final do SDK Navigation. Se não for aceito, a navegação não será ativada.

// Show the terms and conditions.
let companyName = "Navigation SDK Codelab"
GMSNavigationServices.showTermsAndConditionsDialogIfNeeded(withCompanyName: companyName) { termsAccepted in
  if termsAccepted {
    // Enable navigation if the user accepts the terms.
    self.mapView.isNavigationEnabled = true
    // Request authorization for alert notifications which deliver guidance instructions
    // in the background.
  } else {
    // Handle the case when the user rejects the terms and conditions.
  }
}

Crie e execute o app para ver a caixa de diálogo.

29f17ae5b4c07c9f.png

7. Adicionar listeners para eventos principais de navegação

Esta etapa mostra como configurar listeners para eventos principais, como a chegada a um destino ou o redirecionamento do motorista.

Para detectar esses eventos, seu controlador de visualização precisa adotar o protocolo GMSNavigatorListener.

Adicione esse protocolo à definição de classe em ViewController.swift.

class ViewController: UIViewController,
                      GMSNavigatorListener {

Agora, adicione uma linha de código para configurar o listener em loadView():.

// Add a listener for GMSNavigator.
mapView.navigator?.add(self)

Por fim, adicione dois métodos à classe para processar os eventos gerados.

// Listener to handle arrival events.
func navigator(_ navigator: GMSNavigator, didArriveAt waypoint: GMSNavigationWaypoint) {
  print("You have arrived at: \(waypoint.title)")
}

// Listener for route change events.
func navigatorDidChangeRoute(_ navigator: GMSNavigator) {
  print("The route has changed.")
}

8. Definir um destino e iniciar o trajeto

Esta seção ensina como definir um destino e iniciar o trajeto.

Crie uma nova função para a lógica de navegação.

Primeiro, adicione uma nova função chamada startNav() ao seu ViewController. Ele vai conter a lógica para definir um destino e iniciar a navegação.

// Create a route and start guidance.
@objc func startNav() {
}

Crie um Waypoint para o destino.

Em seguida, crie uma matriz de destinos com um único ponto de parada.

// Create a route and start guidance.
@objc func startNav() {
  var destinations = [GMSNavigationWaypoint]()
  destinations.append(
    GMSNavigationWaypoint.init(
      placeID: "ChIJH-tBOc4EdkgRJ8aJ8P1CUxo",
      title: "Trafalgar Square")!)
}

Chame setDestinations()e processe a resposta.

Em seguida, chame setDestinations e processe o GMSRouteStatus retornado.

Se o GMSRouteStatus for "OK", inicie a orientação definindo isGuidanceActive=true no objeto navigator do mapView. Caso contrário, imprima uma instrução para mostrar que houve um erro.

Se o valor GMSRouteStatus retornado for "OK", comece a simular a direção ao longo do trajeto chamando mapView.locationSimulator.simulateLocationsAlongExistingRoute().

// Create a route and start guidance.
@objc func startNav() {
  var destinations = [GMSNavigationWaypoint]()
    destinations.append(
      GMSNavigationWaypoint.init(
        placeID: "ChIJH-tBOc4EdkgRJ8aJ8P1CUxo",
          title: "Trafalgar Square")!)
      
  mapView.navigator?.setDestinations(
    destinations
  ) { routeStatus in
    guard routeStatus == .OK else {
      print("Handle route statuses that are not OK.")
      return
    }
    //If routeStatus is OK, start guidance.
    self.mapView.navigator?.isGuidanceActive = true
    //start simulating driving along the route. self.mapView.locationSimulator?.simulateLocationsAlongExistingRoute()
    self.mapView.cameraMode = .following
  }
}

Lidar com status de erro comuns

É útil processar os erros do GMSRouteStatus de maneira mais explícita, principalmente ao depurar problemas iniciais com seu novo app. Por exemplo, você pode descobrir que recebe erros de permissão de localização, chave de API ou "nenhuma rota encontrada" com mais frequência no início devido à configuração de depuração. Portanto, pode ser útil processar esses estados de erro.

Adicione um código que processe esses casos específicos e imprima uma instrução no console.

mapView.navigator?.setDestinations(
  destinations
) { routeStatus in
    guard routeStatus == .OK else {
      print("Handle route statuses that are not OK.")
      switch routeStatus {
       case .locationUnavailable:
        print("Location unavailable.") //check permissions
      case .noRouteFound:
        print("No route found.") //check start location and destination
      case .waypointError:
        print("Waypoint error") //check Place ID
      default:
        print("Not sure what happened")
      }
    return
  }

Adicionar um botão para iniciar a orientação de navegação

Por fim, adicione um botão à interface e conecte-o ao método startNav. Crie um método chamado makeButton() com o seguinte código. Chame a função makeButton() do loadView().

// Add a button to the view.
func makeButton() {
  // A button to start navigation.
  let navButton = UIButton(frame: CGRect(x: 5, y: 150, width: 200, height: 35))
  navButton.backgroundColor = .blue
  navButton.alpha = 0.5
  navButton.setTitle("Start navigation", for: .normal)
  navButton.addTarget(self, action: #selector(startNav), for: .touchUpInside)
  self.mapView.addSubview(navButton)
}

Compile e execute o app.

Observação: executar o código em

startNav()

vai ligar para o

setDestinations()

método que gera uma cobrança após os primeiros 1.000 destinos usados. Consulte Uso e faturamento para mais informações.

9. Parabéns!

Parabéns, você chegou ao destino!

7a69dcb75c904d7.png

Você criou um app simples que oferece navegação guiada até um destino usando o SDK Navigation da Plataforma Google Maps.

Você configurou as permissões do app e a caixa de diálogo dos termos do usuário final do SDK Navigation e especificou um destino usando um ID de lugar. Você processou vários estados de sucesso e erro no seu app.

10. Como ir além

Se quiser ir além no desenvolvimento de apps, confira os tópicos a seguir para se inspirar.

  • Detectar mais eventos de navegação. Adicione código para mostrar uma mensagem se o tempo ou a distância restante exceder um limite.
  • Personalize a interface de navegação.
  • Se quiser um desafio maior, tente adicionar um seletor de lugar da API Places para permitir que o usuário defina o destino. Dica: os apps de demonstração do SDK do Navigation têm uma implementação de exemplo. Execute pod try GoogleNavigation na pasta do projeto para ver o código.