搭配 Amazon Location Service 使用適用於 Android 的 Tangram ES - Amazon Location Service

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

搭配 Amazon Location Service 使用適用於 Android 的 Tangram ES

Tangram ES 是 C++ 程式庫,用於使用 OpenGL ES 從向量資料轉譯 2D 和 3D 映射。這是 Tangram 的原生複本。

使用來自 的映射時,為搭配 Tilezen 結構描述使用而建置的 Tangram 樣式在很大程度上與 Amazon Location 相容HERE。其中包含:

  • Bubble Wrap – 功能完整的尋路樣式,具有適用於興趣點的有用圖示。

  • Cinnabar – 一般映射應用程式的經典外觀和首選。

  • 補充 – 專為資料視覺化重疊所設計的極簡地圖樣式,其設計靈感來自 Stamen Design 的精算 Toner 樣式。

  • Tron – 探索 視覺化語言的規模轉換TRON。

  • Walkabout – 專注於戶外的樣式,非常適合健行或外出。

本指南說明如何使用名為 Cinnabar 的 Tangram 樣式,將適用於 Android 的 Tangram ES 與 Amazon Location 整合。此範例可作為 Amazon Location Service 範例儲存庫的一部分GitHub

雖然其他 Tangram 樣式最好搭配編碼地形資訊的光柵圖磚,但 Amazon Location 尚不支援此功能。

重要

下列教學課程中的 Tangram 樣式僅與以 VectorHereContrast樣式設定的 Amazon Location Map 資源相容。

建置應用程式:初始化

若要初始化您的應用程式:

  1. 空活動範本建立新的 Android Studio 專案。

  2. 確保已為專案語言選取 Kotlin

  3. 選取最低 SDK API 16:Android 4.1 (Jelly Bean) 或更新版本。

  4. 開啟專案結構以選取檔案 專案結構...,然後選擇相依性區段。

  5. 選取 <所有模組> 後,選擇 按鈕以新增新的程式庫相依性

  6. 新增 AWS Android SDK 2.19.1 版或更新版本。例如:com.amazonaws:aws-android-sdk-core:2.19.1

  7. 新增 Tangram 0.13.0 版或更新版本。例如:com.mapzen.tangram:tangram:0.13.0

    注意

    搜尋 Tangram com.mapzen.tangram:tangram:0.13.0會產生訊息,指出它「找不到」,但選擇「確定」將允許新增它。

建置應用程式:組態

若要使用 資源和 AWS 區域設定應用程式:

  1. 建立 app/src/main/res/values/configuration.xml

  2. 輸入資源的名稱和識別符,以及它們在下列 AWS 位置建立的區域:

<?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>

建置應用程式:活動配置

編輯 app/src/main/res/layout/activity_main.xml

  • 新增 MapView,其會轉譯映射。這也會設定地圖的初始中心點。

  • 新增 TextView,顯示屬性。

這也會設定地圖的初始中心點。

注意

您必須為應用程式或文件上使用的每個資料提供者提供文字標記或文字屬性。屬性字串包含在 sources.esri.attributionsources.here.attributionsource.grabmaptiles.attribution金鑰下的樣式描述符回應中。

由於 Tangram 不會請求這些資源,並且只與來自 的映射相容HERE,請使用「© 2020HERE」。將 Amazon Location 資源與資料提供者 搭配使用時,請務必閱讀服務條款與條件

<?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>

建置應用程式:請求轉換

建立名為 的類別SigV4Interceptor來攔截 AWS 請求,並使用 Signature 第 4 版簽署請求。這將在建立主要活動時,向用來擷取地圖資源的HTTP用戶端註冊。

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() } } }

建置應用程式:主要活動

主要活動負責初始化將向使用者顯示的檢視。這涉及:

  • 初始化 Amazon Cognito CredentialsProvider

  • 註冊 Signature 第 4 版攔截器。

  • 透過指向地圖樣式、覆寫動態磚 和顯示適當的屬性URLs來設定地圖。

MainActivity 也負責將生命週期事件轉送至地圖檢視。

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() } }

執行此應用程式會以您選擇的樣式顯示全螢幕地圖。此範例可作為 Amazon Location Service 範例儲存庫的一部分GitHub