使用七巧板 ES 安卓系統與亞馬遜定 Location Service - Amazon Location Service

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

使用七巧板 ES 安卓系統與亞馬遜定 Location Service

七巧板 ES 是一個 C ++ 庫,用於使用 OpenGL ES 從矢量數據渲染 2D 和 3D 地圖。這是七巧板的原生對應物。

使用來自 HERE 的地圖時,為與 Tlezen 架構搭配使用而建立的七巧板樣式與 Amazon 位置大致相容。其中包含:

  • 泡沫包裝-一個全功能的尋路風格,帶有興趣點的有用圖標。

  • 朱砂 — 一般地圖應用的經典外觀和首選。

  • 筆芯 — 一種簡約的地圖風格,專為數據可視化覆蓋而設計,靈感來自 Stamen Design 的開創性碳粉樣式。

  • Tron — TRON 視覺語言中規模轉換的探索。

  • Walkabout — 一種以戶外為中心的風格,非常適合遠足或外出。

本指南介紹如何使用稱為朱砂的七巧板風格將 Android 版七巧板 ES 與亞馬遜位置集成。此範例可作為上 Amazon 定 Location Service 範例儲存庫的一部分提供GitHub

雖然其他七巧板樣式最好配有對地形資訊進行編碼的點陣圖磚,但 Amazon Location 尚未支援此功能。

重要

以下教學中的七巧板樣式僅與使用該樣VectorHereContrast式設定的 Amazon 位置地圖資源相容。

構建應用程序:初始化

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

  1. 空活動模板創建一個新的 Android 工作室項目。

  2. 確保為項目語言選擇了 Kotlin

  3. 選取 API 16 的最低開發套件:安卓 4.1(果凍豆)或更高版本。

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

  5. 選取後<All Modules>,選擇「+」按鈕以新增「程式庫相依性」。

  6. 新增 AWS 安卓開發套件 2.19.1 版或更新版本。例如:com.amazonaws:aws-android-sdk-core:2.19.1

  7. 加入七巧板版本 0.13.0 或更高版本。例如:com.mapzen.tangram:tangram:0.13.0

    注意

    搜尋七巧板: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.attribution和下的樣式描述元回應中sources.here.attribution keys

由於七巧板不會要求這些資源,而且只能與 HERE 的地圖相容,因此請使用「© 2020 這裡」。搭配資料供應商使用 Amazon 位置資源時,請務必閱讀服務條款與條件

<?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請求並使用簽名版本 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 CognitoCredentialsProvider

  • 註冊簽名版本 4 攔截器。

  • 透過將地圖指向地圖樣式、覆寫並排 URL,以及顯示適當的歸因來設定地圖。

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