在 Amazon Location Service 中使用适用于 iOS 的 MapLibre 本机 SDK - Amazon Location Service

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

在 Amazon Location Service 中使用适用于 iOS 的 MapLibre 本机 SDK

使用适用于 iOS 的MapLibre本机 SDK 将客户端地图嵌入到 iOS 应用程序中。

iOS MapLibre 原生 SDK 是一个基于 Mapbox GL Native 的库,与亚马逊定位服务地图 API 提供的样式和图块兼容。您可以集成适用于 iOS 的 MapLibre Native SDK,将带有可缩放、可自定义的矢量地图的交互式地图视图嵌入到您的 iOS 应用程序中。

本教程介绍如何将 iOS MapLibre 原生 SDK 与 Amazon Location 集成。本教程的示例应用程序已作为 Amazon Location Service 示例存储库的一部分提供GitHub

构建应用程序:初始化

要初始化应用程序,请执行以下操作:

  1. 应用程序模板中创建新的 Xcode 项目。

  2. 选择 SwiftUI 作为其界面。

  3. 选择 SwiftUI 应用程序作为其生命周期。

  4. 选择 Swift 作为其语言。

使用 Swift 软件包添加 MapLibre依赖关系

要向 Xcode 项目添加软件包依赖项,请执行以下操作:

  1. 导航到文件 > Swift 软件包 > 添加包依赖项

  2. 输入存储库 URL:https://github.com/maplibre/maplibre-gl-native-distribution

    注意

    有关 Swift Packages 的更多信息,请参阅 Apple .com 上的向应用程序添加软件包依赖项

  3. 在您的终端中,安装 CocoaPods:

    sudo gem install cocoapods
  4. 导航到应用程序的项目目录并使用 CocoaPods 包管理器初始化 Podfile

    pod init
  5. 打开要添加 AWSCore 为依赖项的 Podfile

    platform :ios, '12.0' target 'Amazon Location Service Demo' do use_frameworks! pod 'AWSCore' end
  6. 下载并安装依赖项:

    pod install --repo-update
  7. 打开 CocoaPods 创建以下内容的 Xcode 工作区:

    xed .

构建应用程序:配置

将以下键和值添加到 Info.plist 以配置应用程序:

AWSRegion us-east-1
IdentityPoolId us-east-1:54f2ba88-9390-498d-aaa5-0d97fb7ca3bd
MapName ExampleMap

构建应用程序: ContentView 布局

要渲染地图,请编辑 ContentView.swift

  • 添加渲染地图的 MapView

  • 添加显示属性的 TextField

这还会设置地图的初始中心点。

import SwiftUI struct ContentView: View { @State private var attribution = "" var body: some View { MapView(attribution: $attribution) .centerCoordinate(.init(latitude: 49.2819, longitude: -123.1187)) .zoomLevel(12) .edgesIgnoringSafeArea(.all) .overlay( TextField("", text: $attribution) .disabled(true) .font(.system(size: 12, weight: .light, design: .default)) .foregroundColor(.black) .background(Color.init(Color.RGBColorSpace.sRGB, white: 0.5, opacity: 0.5)) .cornerRadius(1), alignment: .bottomTrailing) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
注意

您必须在应用程序或文档中为使用的每个数据提供程序提供文字标记或文本属性。属性字符串包含在样式描述符响应中的 sources.esri.attributionsources.here.attributionsource.grabmaptiles.attribution 键下。在数据提供程序处使用 Amazon Location 资源时,请务必阅读服务条款和条件

构建应用程序:请求转换

创建一个名为 AWSSignatureV4Delegate.swift 的新 Swift 文件,其中包含以下类定义,以拦截 AWS 请求并使用 Signature Version 4 对其进行签名。该类的一个实例将被分配为离线存储委托,该委托人还负责在地图视图中重写 URL。

import AWSCore import Mapbox class AWSSignatureV4Delegate : NSObject, MGLOfflineStorageDelegate { private let region: AWSRegionType private let identityPoolId: String private let credentialsProvider: AWSCredentialsProvider init(region: AWSRegionType, identityPoolId: String) { self.region = region self.identityPoolId = identityPoolId self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: region, identityPoolId: identityPoolId) super.init() } class func doubleEncode(path: String) -> String? { return path.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)? .addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) } func offlineStorage(_ storage: MGLOfflineStorage, urlForResourceOf kind: MGLResourceKind, with url: URL) -> URL { if url.host?.contains("amazonaws.com") != true { // not an AWS URL return url } // URL-encode spaces, etc. let keyPath = String(url.path.dropFirst()) guard let percentEncodedKeyPath = keyPath.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else { print("Invalid characters in path '\(keyPath)'; unsafe to sign") return url } let endpoint = AWSEndpoint(region: region, serviceName: "geo", url: url) let requestHeaders: [String: String] = ["host": endpoint!.hostName] // sign the URL let task = AWSSignatureV4Signer .generateQueryStringForSignatureV4( withCredentialProvider: credentialsProvider, httpMethod: .GET, expireDuration: 60, endpoint: endpoint!, // workaround for https://github.com/aws-amplify/aws-sdk-ios/issues/3215 keyPath: AWSSignatureV4Delegate.doubleEncode(path: percentEncodedKeyPath), requestHeaders: requestHeaders, requestParameters: .none, signBody: true) task.waitUntilFinished() if let error = task.error as NSError? { print("Error occurred: \(error)") } if let result = task.result { var urlComponents = URLComponents(url: (result as URL), resolvingAgainstBaseURL: false)! // re-use the original path; workaround for https://github.com/aws-amplify/aws-sdk-ios/issues/3215 urlComponents.path = url.path // have Mapbox GL fetch the signed URL return (urlComponents.url)! } // fall back to an unsigned URL return url } }

构建应用程序:地图视图

地图视图负责初始化实例 AWSSignatureV4Delegate 和配置底层 MGLMapView,底层视图获取资源并渲染地图。它还处理将属性字符串从样式描述符的来源传播回 ContentView

创建一个名为 MapView.swift 的新 Swift 文件,其中包含以下 struct 定义:

import SwiftUI import AWSCore import Mapbox struct MapView: UIViewRepresentable { @Binding var attribution: String private var mapView: MGLMapView private var signingDelegate: MGLOfflineStorageDelegate init(attribution: Binding<String>) { let regionName = Bundle.main.object(forInfoDictionaryKey: "AWSRegion") as! String let identityPoolId = Bundle.main.object(forInfoDictionaryKey: "IdentityPoolId") as! String let mapName = Bundle.main.object(forInfoDictionaryKey: "MapName") as! String let region = (regionName as NSString).aws_regionTypeValue() // MGLOfflineStorage doesn't take ownership, so this needs to be a member here signingDelegate = AWSSignatureV4Delegate(region: region, identityPoolId: identityPoolId) // register a delegate that will handle SigV4 signing MGLOfflineStorage.shared.delegate = signingDelegate mapView = MGLMapView( frame: .zero, styleURL: URL(string: "https://maps.geo.\(regionName).amazonaws.com/maps/v0/maps/\(mapName)/style-descriptor")) _attribution = attribution } func makeCoordinator() -> Coordinator { Coordinator($attribution) } class Coordinator: NSObject, MGLMapViewDelegate { var attribution: Binding<String> init(_ attribution: Binding<String>) { self.attribution = attribution } func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) { let source = style.sources.first as? MGLVectorTileSource let attribution = source?.attributionInfos.first self.attribution.wrappedValue = attribution?.title.string ?? "" } } // MARK: - UIViewRepresentable protocol func makeUIView(context: UIViewRepresentableContext<MapView>) -> MGLMapView { mapView.delegate = context.coordinator mapView.logoView.isHidden = true mapView.attributionButton.isHidden = true return mapView } func updateUIView(_ uiView: MGLMapView, context: UIViewRepresentableContext<MapView>) { } // MARK: - MGLMapView proxy func centerCoordinate(_ centerCoordinate: CLLocationCoordinate2D) -> MapView { mapView.centerCoordinate = centerCoordinate return self } func zoomLevel(_ zoomLevel: Double) -> MapView { mapView.zoomLevel = zoomLevel return self } }

运行此应用程序会以您选择的样式显示全屏地图。此示例作为 Amazon Location Service 示例存储库的一部分提供GitHub