API Maps no Wear OS

Mapas em dispositivos wearable

Com o SDK do Maps para Android, é possível criar um app para wearables com base em mapas para ser executado diretamente em dispositivos Wear OS by Google. Se os usuários quiserem ver onde estão em um mapa, só precisam olhar para o pulso. Eles podem conferir em que ponto do trajeto estão, aumentar o zoom para consultar detalhes ou tocar em um marcador para abrir a janela de informações fornecida pelo app, por exemplo.

Esta página descreve os recursos da API disponíveis para dispositivos Wear e ajuda na criação do seu aplicativo.

Primeiros passos no Wear OS

A criação de um app para wearables com o SDK do Maps para Android é quase igual à de um app Google Maps em outros dispositivos Android. A diferença está no design adaptado ao formato menor dos dispositivos wearable para otimizar a usabilidade e a performance do app.

Recomendamos usar o Android Studio no desenvolvimento para Wear OS. Ele oferece configuração de projetos, inclusão de bibliotecas e conveniências de empacotamento.

Se você quiser receber ajuda ao criar um app para wearables, consulte as Diretrizes de design para Wear OS. Consulte o guia sobre como criar apps para wearables se precisar de auxílio no seu primeiro desenvolvimento desse tipo.

Criar seu primeiro app com mapas no Wear OS

Para usar este guia rápido, é preciso conhecer o SDK do Maps para Android e ter criado um módulo wearable no seu app seguindo os guias do Wear OS, além de querer adicionar um mapa a esse módulo.

Adicionar dependências ao módulo wearable

Verifique se as seguintes dependências estão incluídas no arquivo build.gradle do módulo Wear OS do seu app:

dependencies {
    // ...
    compileOnly 'com.google.android.wearable:wearable:2.9.0'
    implementation 'com.google.android.support:wearable:2.9.0'
    implementation 'com.google.android.gms:play-services-maps:18.1.0'

    // This dependency is necessary for ambient mode
    implementation 'androidx.wear:wear:1.2.0'
}

Veja mais informações sobre as dependências no guia para adicionar um módulo Wear OS no seu projeto atual.

Implementar um gesto de deslizar para dispensar e definir a cor do plano de fundo inicial

É recomendável usar SwipeDismissFrameLayout para exibir o mapa no dispositivo wearable. Com a classe SwipeDismissFrameLayout, você pode implementar o gesto deslizar para dispensar. Com ele, os usuários saem do app deslizando o dedo a partir da borda esquerda da tela.

Para definir uma cor inicial personalizada de plano de fundo, use o atributo XML map:backgroundColor para escolher a cor a ser exibida até que os blocos do mapa sejam carregados.

Adicione os elementos SwipeDismissFrameLayout e backgroundColor à definição do layout como o contêiner do SupportMapFragment:

  <androidx.wear.widget.SwipeDismissFrameLayout
      android:id="@+id/map_container"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        map:backgroundColor="#fff0b2dd" />
  </androidx.wear.widget.SwipeDismissFrameLayout>

Quando você receber o objeto SwipeDismissFrameLayout na atividade, adicione um callback e defina o comportamento dele para realizar a ação necessária de dispensar, conforme mostrado abaixo:

Java


public class MainActivity extends AppCompatActivity implements OnMapReadyCallback,
    AmbientModeSupport.AmbientCallbackProvider {

    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);

        // Set the layout. It only contains a SupportMapFragment and a DismissOverlay.
        setContentView(R.layout.activity_main);

        // Enable ambient support, so the map remains visible in simplified, low-color display
        // when the user is no longer actively using the app but the app is still visible on the
        // watch face.
        AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
        Log.d(MainActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());

        // Retrieve the containers for the root of the layout and the map. Margins will need to be
        // set on them to account for the system window insets.
        final SwipeDismissFrameLayout mapFrameLayout = (SwipeDismissFrameLayout) findViewById(
            R.id.map_container);
        mapFrameLayout.addCallback(new SwipeDismissFrameLayout.Callback() {
            @Override
            public void onDismissed(SwipeDismissFrameLayout layout) {
                onBackPressed();
            }
        });

        // Obtain the MapFragment and set the async listener to be notified when the map is ready.
        mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    // ...
}

      

Kotlin


class MainActivity : AppCompatActivity(), OnMapReadyCallback,
                     AmbientModeSupport.AmbientCallbackProvider {

    public override fun onCreate(savedState: Bundle?) {
        super.onCreate(savedState)

        // Set the layout. It only contains a SupportMapFragment and a DismissOverlay.
        setContentView(R.layout.activity_main)

        // Enable ambient support, so the map remains visible in simplified, low-color display
        // when the user is no longer actively using the app but the app is still visible on the
        // watch face.
        val controller = AmbientModeSupport.attach(this)
        Log.d(MainActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)

        // Retrieve the containers for the root of the layout and the map. Margins will need to be
        // set on them to account for the system window insets.
        val mapFrameLayout = findViewById<SwipeDismissFrameLayout>(R.id.map_container)
        mapFrameLayout.addCallback(object : SwipeDismissFrameLayout.Callback() {
            override fun onDismissed(layout: SwipeDismissFrameLayout) {
                onBackPressed()
            }
        })

        // Obtain the MapFragment and set the async listener to be notified when the map is ready.
        mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

    // ...
}

      

Adicionar um mapa

Use o método de callback onMapReady(GoogleMap) como de costume para receber um identificador para o objeto GoogleMap. O callback será acionado quando o mapa estiver pronto para ser utilizado. No método de callback, você pode adicionar marcadores ou polilinhas ao mapa, incluir listeners ou mover a câmera. O exemplo abaixo coloca um marcador perto da Sydney Opera House:

Java


private static final LatLng SYDNEY = new LatLng(-33.85704, 151.21522);

@Override
public void onMapReady(@NonNull GoogleMap googleMap) {
    // Add a marker with a title that is shown in its info window.
    googleMap.addMarker(new MarkerOptions().position(SYDNEY)
        .title("Sydney Opera House"));

    // Move the camera to show the marker.
    googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, 10));
}

      

Kotlin


private val sydney = LatLng(-33.85704, 151.21522)

override fun onMapReady(googleMap: GoogleMap) {
    // Add a marker with a title that is shown in its info window.
    googleMap.addMarker(
        MarkerOptions().position(sydney)
            .title("Sydney Opera House")
    )

    // Move the camera to show the marker.
    googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 10f))
}

      

Ativar o modo ambiente

O SDK do Maps para Android é compatível com o modo ambiente em apps para wearables. Os aplicativos compatíveis com o modo ambiente podem ser chamados de apps sempre ativados. Esse modo é habilitado quando o usuário deixa de usar o app ativamente e permite que ele fique visível no dispositivo wearable.

O SDK do Maps para Android oferece uma renderização simplificada do mapa, com poucas cores, para uso no modo ambiente, e o estilo do mapa é ajustado automaticamente quando o dispositivo sai do modo interativo. Todos os marcadores, objetos e controles de IU desaparecem no modo ambiente. Isso reduz o consumo de energia do app e garante um visual consistente com outros apps no mesmo modo, como os mostradores de relógio.

Siga estas etapas para garantir que o app use o modo ambiente do mapa:

  1. Atualize o SDK do Android para incluir a plataforma Android 6.0 (API 23) ou mais recente. Ela disponibiliza as APIs que permitem que as atividades entrem no modo ambiente. Para ver informações sobre como atualizar seu SDK, consulte a documentação do Android sobre como adicionar pacotes do SDK.
  2. Para o projeto ser direcionado ao Android 6.0 ou versões mais recentes, defina targetSdkVersion como 23 ou superior no manifesto do app.
  3. Adicione as dependências de wearables ao arquivo build.gradle do seu app. Veja um exemplo nesta página.
  4. Adicione a entrada da biblioteca compartilhada wearable ao manifesto do app para wearables, conforme descrito na aula de treinamento do Android sobre como manter seu app visível.
  5. Adicione a permissão WAKE_LOCK aos manifestos de apps para dispositivos wearable e portáteis, conforme descrito na aula de treinamento do Android sobre como manter seu app visível.
  6. No método onCreate() da sua atividade, chame o método AmbientModeSupport.attach(). O sistema operacional recebe a notificação de que o app está sempre ativado. Assim, quando o dispositivo desliga, ele entra no modo ambiente em vez de mostrar o relógio.
  7. Implemente a interface AmbientModeSupport.AmbientCallbackProvider na sua atividade para que ela receba as mudanças de estado do modo ambiente.
  8. Configure seu mapa para permitir o modo ambiente. Defina o atributo map:ambientEnabled="true" no arquivo de layout XML da atividade ou faça isso de maneira programática definindo GoogleMapOptions.ambientEnabled(true). Essa configuração informa à API que é preciso carregar previamente os blocos de mapa necessários para uso no modo ambiente.
  9. Quando a atividade muda para o modo ambiente, o sistema chama o método onEnterAmbient() no AmbientCallback informado. Modifique onEnterAmbient() e chame SupportMapFragment.onEnterAmbient(ambientDetails) ou MapView.onEnterAmbient(ambientDetails). A API muda para uma renderização não interativa do mapa com poucas cores.
  10. Da mesma forma, em onExitAmbient(), chame o SupportMapFragment.onExitAmbient() ou MapView.onExitAmbient(). A API muda para a renderização normal do mapa.

O exemplo de código a seguir ativa o modo ambiente na atividade:

Java


public class AmbientActivity extends AppCompatActivity implements
    AmbientModeSupport.AmbientCallbackProvider {

    private SupportMapFragment mapFragment;

    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);

        // Set the layout. It only contains a SupportMapFragment and a DismissOverlay.
        setContentView(R.layout.activity_main);

        // Enable ambient support, so the map remains visible in simplified, low-color display
        // when the user is no longer actively using the app but the app is still visible on the
        // watch face.
        AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
        Log.d(AmbientActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());

        // Obtain the MapFragment and set the async listener to be notified when the map is ready.
        mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    }

    @Override
    public AmbientCallback getAmbientCallback() {
        return new AmbientCallback() {
            /**
             * Starts ambient mode on the map.
             * The API swaps to a non-interactive and low-color rendering of the map when the user is no
             * longer actively using the app.
             */
            @Override
            public void onEnterAmbient(Bundle ambientDetails) {
                super.onEnterAmbient(ambientDetails);
                mapFragment.onEnterAmbient(ambientDetails);
            }

            /**
             * Exits ambient mode on the map.
             * The API swaps to the normal rendering of the map when the user starts actively using the app.
             */
            @Override
            public void onExitAmbient() {
                super.onExitAmbient();
                mapFragment.onExitAmbient();
            }
        };
    }
}

      

Kotlin


class AmbientActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider {

    private lateinit var mapFragment: SupportMapFragment

    public override fun onCreate(savedState: Bundle?) {
        super.onCreate(savedState)

        // Set the layout. It only contains a SupportMapFragment and a DismissOverlay.
        setContentView(R.layout.activity_main)

        // Enable ambient support, so the map remains visible in simplified, low-color display
        // when the user is no longer actively using the app but the app is still visible on the
        // watch face.
        val controller = AmbientModeSupport.attach(this)
        Log.d(AmbientActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)

        // Obtain the MapFragment and set the async listener to be notified when the map is ready.
        mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
    }

    override fun getAmbientCallback(): AmbientModeSupport.AmbientCallback {
        return object : AmbientModeSupport.AmbientCallback() {
            /**
             * Starts ambient mode on the map.
             * The API swaps to a non-interactive and low-color rendering of the map when the user is no
             * longer actively using the app.
             */
            override fun onEnterAmbient(ambientDetails: Bundle) {
                super.onEnterAmbient(ambientDetails)
                mapFragment.onEnterAmbient(ambientDetails)
            }

            /**
             * Exits ambient mode on the map.
             * The API swaps to the normal rendering of the map when the user starts actively using the app.
             */
            override fun onExitAmbient() {
                super.onExitAmbient()
                mapFragment.onExitAmbient()
            }
        }
    }
}

      

Você pode atualizar a tela enquanto o app está no modo ambiente. Para saber mais sobre atualização de conteúdo e o modo ambiente em geral, consulte a aula de treinamento do Android sobre como manter seu app visível.

Usar o Street View no Wear OS

O Street View é totalmente compatível com dispositivos wearable.

Se quiser permitir que os usuários saiam do app enquanto estiverem visualizando um panorama do Street View, use a interface StreetViewPanorama.OnStreetViewPanoramaLongClickListener para escutar um gesto de clique longo. Quando um usuário dá um clique longo em algum lugar da imagem do Street View, você recebe um evento onStreetViewPanoramaLongClick(StreetViewPanoramaOrientation). Chame DismissOverlayView.show() para exibir um botão de saída.

Exemplo de código

Um app de amostra está disponível no GitHub e pode ser usado como ponto de partida. O exemplo mostra como configurar um mapa básico do Google no Wear OS.

Funcionalidades compatíveis com a API Maps no Wear OS

Esta seção descreve as diferenças das funcionalidades permitidas para mapas em dispositivos wearable e portáteis (smartphones e tablets). Todos os recursos de API não mencionados abaixo funcionam conforme a documentação da API completa.

Funcionalidade
Modo totalmente interativo e Modo Lite

Você pode usar o SDK do Maps para Android no modo totalmente interativo ou no Modo Lite. Use o Modo Lite se quiser otimizar a performance no dispositivo wearable e seu app não precisar de compatibilidade com interações, como gestos, deslocamento ou alteração de zoom do mapa.

No Modo Lite, a intenção de iniciar o app Google Maps para dispositivos móveis quando o usuário toca no mapa é desativada e não pode ser ativada em um dispositivo wearable.

Para ver uma lista completa das diferenças entre o Modo Lite e o totalmente interativo, consulte a documentação do Modo Lite.

Barra de ferramentas do mapa A barra de ferramentas do mapa fica desativada e não pode ser habilitada em dispositivos wearable.
Controles de IU Os controles de IU são desativados por padrão em dispositivos wearable. Isso inclui os controles de zoom, bússola e Meu local. É possível ativá-los usando a classe UiSettings normalmente.
Gestos Os gestos de toque único funcionam conforme esperado. Por exemplo, toque e arraste para movimentar o mapa, toque duas vezes para aumentar o zoom e com dois dedos para diminui-lo. Os gestos de vários toques disponíveis variam de acordo com o dispositivo do usuário. Alguns exemplos de gestos multitoque são empurrar com dois dedos para inclinar o mapa, fazer gesto de pinça para aumentar o zoom e rotação com dois dedos.
Mapas internos e edifícios Os Indoor Maps são desativados por padrão em um dispositivo wearable. É possível ativá-los chamando GoogleMap.setIndoorEnabled(true). Se os mapas internos estiverem ativados, o mapa mostrará o nível de andar padrão. O elemento da IU do seletor de nível não é compatível com dispositivos wearable.
Sobreposições de blocos As sobreposições de blocos não são compatíveis com dispositivos wearable.

Práticas recomendadas de desenvolvimento usando a API Maps no Wear OS

Como oferecer a melhor experiência ao usuário no app:

  • O mapa deve ocupar uma grande parte da tela. Isso é necessário para otimizar a usabilidade do mapa no formato pequeno em um dispositivo wearable.
  • Ao projetar a experiência do usuário no app, lembre-se de que os dispositivos wearable têm pouca energia de bateria. Manter a tela ativa e o mapa visível afetam o desempenho dela.