將 MapLibre Native SDK for Android 與 Amazon Location Service 搭配使用 - Amazon Location Service

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

將 MapLibre Native SDK for Android 與 Amazon Location Service 搭配使用

使用MapLibre原生SDK將互動式地圖內嵌至 Android 應用程式。

MapLibre Native SDK for Android 是以 Mapbox Native 為基礎的程式庫,且與 Amazon Location Service Maps 提供的樣式和動態磚相容API。您可以整合 MapLibre Native SDK for Android,將互動式地圖檢視與可擴展、可自訂的向量圖嵌入 Android 應用程式。

本教學課程說明如何將 MapLibre Native SDK for Android 與 Amazon Location 整合。此教學課程的範例應用程式可作為 Amazon Location Service 範例儲存庫的一部分GitHub

建置應用程式:初始化

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

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

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

  3. 選取最低 SDK API 14:Android 4.0 (冰淇淋三明治) 或更新版本。

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

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

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

  7. 新增 MapLibre Native SDK for Android 9.4.0 版或更新版本。例如:org.maplibre.gl:android-sdk:9.4.0

  8. build.gradle 檔案的專案層級,新增下列 maven 儲存庫來存取 MapLibre Android 套件:

    allprojects { repositories { // Retain your existing repositories google() jcenter() // Declare the repositories for MapLibre mavenCentral() } }

建置應用程式:組態

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

<?xml version="1.0" encoding="utf-8"?> <resources> <string name="identityPoolId">us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd</string> <string name="mapName">ExampleMap</string> <string name="awsRegion">us-east-1</string> </resources>

建置應用程式:活動配置

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

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

  • 新增 TextView,顯示屬性。

<?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.mapbox.mapboxsdk.maps.MapView android:id="@+id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" app:mapbox_cameraTargetLat="49.2819" app:mapbox_cameraTargetLng="-123.1187" app:mapbox_cameraZoom="12" app:mapbox_uiAttribution="false" app:mapbox_uiLogo="false" /> <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>
注意

您必須為應用程式或文件上使用的每個資料提供者提供文字標記或文字屬性。屬性字串包含在 sources.esri.attributionsources.here.attributionsource.grabmaptiles.attribution金鑰下的樣式描述符回應中。搭配資料提供者 使用 Amazon Location 資源時,請務必閱讀服務條款與條件

建置應用程式:請求轉換

建立名為 的類別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 版攔截器。

  • 將地圖指向地圖樣式描述符,並顯示適當的屬性,藉此設定地圖。

MainActivity 也負責將生命週期事件轉送至地圖檢視,允許其在調用之間保留作用中視埠。

package aws.location.demo.maplibre 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.mapbox.mapboxsdk.Mapbox import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.Style import com.mapbox.mapboxsdk.module.http.HttpRequestUtil import okhttp3.OkHttpClient private const val SERVICE_NAME = "geo" class MainActivity : AppCompatActivity() { private var mapView: MapView? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // configuration val identityPoolId = getString(R.string.identityPoolId) val region = getString(R.string.awsRegion) val mapName = getString(R.string.mapName) // Credential initialization val credentialProvider = CognitoCachingCredentialsProvider( applicationContext, identityPoolId, Regions.fromName(identityPoolId.split(":").first()) ) // initialize MapLibre Mapbox.getInstance(this, null) HttpRequestUtil.setOkHttpClient( OkHttpClient.Builder() .addInterceptor(SigV4Interceptor(credentialProvider, SERVICE_NAME)) .build() ) // initialize the view setContentView(R.layout.activity_main) // initialize the map view mapView = findViewById(R.id.mapView) mapView?.onCreate(savedInstanceState) mapView?.getMapAsync { map -> map.setStyle( Style.Builder() .fromUri("https://maps.geo.${region}.amazonaws.com/maps/v0/maps/${mapName}/style-descriptor") ) { style -> findViewById<TextView>(R.id.attributionView).text = style.sources.first()?.attribution } } } override fun onStart() { super.onStart() mapView?.onStart() } override fun onResume() { super.onResume() mapView?.onResume() } override fun onPause() { super.onPause() mapView?.onPause() } override fun onStop() { super.onStop() mapView?.onStop() } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) mapView?.onSaveInstanceState(outState) } override fun onLowMemory() { super.onLowMemory() mapView?.onLowMemory() } override fun onDestroy() { super.onDestroy() mapView?.onDestroy() } }

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