Usando o Tangram ES para Android com o Amazon Location Service - Amazon Location Service

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Usando o Tangram ES para Android com o Amazon Location Service

O Tangram ES é uma biblioteca C++ para renderizar mapas 2D e 3D a partir de dados vetoriais usando o OpenGL ES. É a contraparte nativa do Tangram.

Os estilos do Tangram criados para funcionar com o esquema Tilezen são amplamente compatíveis com o Amazon Location ao usar mapas da HERE. Isso inclui:

  • Bubble Wrap — Um estilo de orientação completo com ícones úteis para pontos de interesse.

  • Cinnabar — Uma aparência clássica e ideal para aplicativos gerais de mapeamento.

  • Refill — Um estilo de mapa minimalista projetado para sobreposições de visualização de dados, inspirado no estilo seminal de Toner da Stamen Design.

  • Tron — Uma exploração das transformações de escala na linguagem visual de TRON.

  • Walkabout — Um estilo voltado para atividades ao ar livre que é perfeito para caminhar ou sair de casa.

Este guia descreve como integrar o Tangram ES para Android com o Amazon Location usando o estilo Tangram chamado Cinnabar. Essa amostra está disponível como parte do repositório de amostras do Amazon Location Service em GitHub.

Embora outros estilos do Tangram sejam melhor acompanhados por blocos raster, que codificam informações sobre o terreno, esse atributo ainda não é suportado pelo Amazon Location.

Importante

Os estilos do Tangram no tutorial a seguir são compatíveis somente com os recursos de mapa do Amazon Location configurados com o estilo VectorHereContrast.

Construindo o aplicativo: inicialização

Para inicializar seu aplicativo:

  1. Crie um novo projeto do Android Studio a partir do modelo Atividade vazia.

  2. Certifique-se de que o Kotlin esteja selecionado para o idioma do projeto.

  3. Selecione um SDK mínimo de API 16: Android 4.1 (Jelly Bean) ou mais recente.

  4. Abra a Estrutura do projeto para selecionar Arquivo, Estrutura do projeto... e escolha a seção Dependências.

  5. Com a opção <Todos os módulos> selecionada, escolha o botão + para adicionar uma nova Dependência de biblioteca.

  6. Adicione o SDK para Android da AWS versão 2.19.1 ou posterior. Por exemplo: com.amazonaws:aws-android-sdk-core:2.19.1

  7. Adicione o Tangram versão 0.13.0 ou posterior. Por exemplo: com.mapzen.tangram:tangram:0.13.0.

    nota

    Pesquisar por Tangram: com.mapzen.tangram:tangram:0.13.0 gerará uma mensagem de que “não foi encontrado”, mas escolher OK permitirá que ele seja adicionado.

Construindo o aplicativo: configuração

Para configurar seu aplicativo com seus recursos e sua região da AWS:

  1. Criar app/src/main/res/values/configuration.xml.

  2. Insira os nomes e identificadores dos seus recursos e também a região AWS em que foram criados:

<?xml version="1.0" encoding="utf-8"?> <resources> <string name="identityPoolId">us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd</string> <string name="mapName">TangramExampleMap</string> <string name="awsRegion">us-east-1</string> <string name="sceneUrl">https://www.nextzen.org/carto/cinnabar-style/9/cinnabar-style.zip</string> <string name="attribution">© 2020 HERE</string> </resources>

Construindo o aplicativo: layout da atividade

Edite app/src/main/res/layout/activity_main.xml.

  • Adicione um MapView, que renderiza o mapa. Isso também definirá o ponto central inicial do mapa.

  • Adicione um TextView, que exibe a atribuição.

Isso também definirá o ponto central inicial do mapa.

nota

Você deve fornecer uma marca nominativa ou atribuição de texto para cada provedor de dados que você usa, seja em seu aplicativo ou em sua documentação. As strings de atribuição estão incluídas na resposta do descritor de estilo sob as teclas sources.esri.attribution, sources.here.attribution e source.grabmaptiles.attribution.

Como o Tangram não solicita esses recursos e só é compatível com mapas da HERE, use “© 2020 HERE”. Ao usar os recursos do Amazon Location com provedores de dados, certifique-se de ler os termos e condições do serviço.

<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <com.mapzen.tangram.MapView android:id="@+id/map" android:layout_height="match_parent" android:layout_width="match_parent" /> <TextView android:id="@+id/attributionView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#80808080" android:padding="5sp" android:textColor="@android:color/black" android:textSize="10sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" tools:ignore="SmallSp" /> </androidx.constraintlayout.widget.ConstraintLayout>

Construindo o aplicativo: Solicitar transformação

Crie uma classe nomeada SigV4Interceptor para interceptar solicitações da AWS e assiná-las usando o Signature versão 4. Isso será registrado no cliente HTTP usado para buscar recursos do mapa quando a Atividade Principal for criada.

package aws.location.demo.okhttp import com.amazonaws.DefaultRequest import com.amazonaws.auth.AWS4Signer import com.amazonaws.auth.AWSCredentialsProvider import com.amazonaws.http.HttpMethodName import com.amazonaws.util.IOUtils import okhttp3.HttpUrl import okhttp3.Interceptor import okhttp3.Request import okhttp3.Response import okio.Buffer import java.io.ByteArrayInputStream import java.net.URI class SigV4Interceptor( private val credentialsProvider: AWSCredentialsProvider, private val serviceName: String ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() if (originalRequest.url().host().contains("amazonaws.com")) { val signer = if (originalRequest.url().encodedPath().contains("@")) { // the presence of "@" indicates that it doesn't need to be double URL-encoded AWS4Signer(false) } else { AWS4Signer() } val awsRequest = toAWSRequest(originalRequest, serviceName) signer.setServiceName(serviceName) signer.sign(awsRequest, credentialsProvider.credentials) return chain.proceed(toSignedOkHttpRequest(awsRequest, originalRequest)) } return chain.proceed(originalRequest) } companion object { fun toAWSRequest(request: Request, serviceName: String): DefaultRequest<Any> { // clone the request (AWS-style) so that it can be populated with credentials val dr = DefaultRequest<Any>(serviceName) // copy request info dr.httpMethod = HttpMethodName.valueOf(request.method()) with(request.url()) { dr.resourcePath = uri().path dr.endpoint = URI.create("${scheme()}://${host()}") // copy parameters for (p in queryParameterNames()) { if (p != "") { dr.addParameter(p, queryParameter(p)) } } } // copy headers for (h in request.headers().names()) { dr.addHeader(h, request.header(h)) } // copy the request body val bodyBytes = request.body()?.let { body -> val buffer = Buffer() body.writeTo(buffer) IOUtils.toByteArray(buffer.inputStream()) } dr.content = ByteArrayInputStream(bodyBytes ?: ByteArray(0)) return dr } fun toSignedOkHttpRequest( awsRequest: DefaultRequest<Any>, originalRequest: Request ): Request { // copy signed request back into an OkHttp Request val builder = Request.Builder() // copy headers from the signed request for ((k, v) in awsRequest.headers) { builder.addHeader(k, v) } // start building an HttpUrl val urlBuilder = HttpUrl.Builder() .host(awsRequest.endpoint.host) .scheme(awsRequest.endpoint.scheme) .encodedPath(awsRequest.resourcePath) // copy parameters from the signed request for ((k, v) in awsRequest.parameters) { urlBuilder.addQueryParameter(k, v) } return builder.url(urlBuilder.build()) .method(originalRequest.method(), originalRequest.body()) .build() } } }

Construindo o aplicativo: atividade principal

A Atividade Principal é responsável por inicializar as visualizações que serão exibidas aos usuários. Isso envolve:

  • Instanciando um CredentialsProvider do Amazon Cognito.

  • Registrando o interceptador Signature versão 4.

  • Configurando o mapa apontando-o para um estilo de mapa, substituindo URLs de blocos e exibindo a atribuição apropriada.

O MainActivity também é responsável por encaminhar os eventos do ciclo de vida para a visualização do mapa.

package aws.location.demo.tangram import android.os.Bundle import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import aws.location.demo.okhttp.SigV4Interceptor import com.amazonaws.auth.CognitoCachingCredentialsProvider import com.amazonaws.regions.Regions import com.mapzen.tangram.* import com.mapzen.tangram.networking.DefaultHttpHandler import com.mapzen.tangram.networking.HttpHandler private const val SERVICE_NAME = "geo" class MainActivity : AppCompatActivity(), MapView.MapReadyCallback { private var mapView: MapView? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mapView = findViewById(R.id.map) mapView?.getMapAsync(this, getHttpHandler()) findViewById<TextView>(R.id.attributionView).text = getString(R.string.attribution) } override fun onMapReady(mapController: MapController?) { val sceneUpdates = arrayListOf( SceneUpdate( "sources.mapzen.url", "https://maps.geo.${getString(R.string.awsRegion)}.amazonaws.com/maps/v0/maps/${ getString( R.string.mapName ) }/tiles/{z}/{x}/{y}" ) ) mapController?.let { map -> map.updateCameraPosition( CameraUpdateFactory.newLngLatZoom( LngLat(-123.1187, 49.2819), 12F ) ) map.loadSceneFileAsync( getString(R.string.sceneUrl), sceneUpdates ) } } private fun getHttpHandler(): HttpHandler { val builder = DefaultHttpHandler.getClientBuilder() val credentialsProvider = CognitoCachingCredentialsProvider( applicationContext, getString(R.string.identityPoolId), Regions.US_EAST_1 ) return DefaultHttpHandler( builder.addInterceptor( SigV4Interceptor( credentialsProvider, SERVICE_NAME ) ) ) } override fun onResume() { super.onResume() mapView?.onResume() } override fun onPause() { super.onPause() mapView?.onPause() } override fun onLowMemory() { super.onLowMemory() mapView?.onLowMemory() } override fun onDestroy() { super.onDestroy() mapView?.onDestroy() } }

A execução deste aplicativo exibe um mapa em tela cheia no estilo de sua escolha. Essa amostra está disponível como parte do repositório de amostras do Amazon Location Service em GitHub.