iOS アプリケーションの作成 - Amazon Location Service

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

iOS アプリケーションの作成

このセクションでは、ある場所で検索し、フォアグラウンドで追跡できる iOS アプリケーションを作成します。まず、Amazon Location リソースとアプリケーションの Amazon Cognito ID を作成します。

アプリ用の Amazon Location リソースを作成する

まだ持っていない場合は、アプリケーションが利用される Amazon Location リソースを作成する必要があります。アプリケーションにマップを表示するマップリソース、マップ上の位置を検索する場所インデックス、マップ全体のオブジェクトを追跡するトラッカーを作成します。

位置情報リソースをアプリケーションに追加
  1. 使用するマップスタイルを選択します。

    1. Amazon Location コンソールの マップページで、[マップを作成] を選択してマップスタイルをプレビューします。

    2. 新しいマップリソースの [名前][説明] を追加します。マップリソースに使用する名前をメモしておきます。チュートリアルの後半でスクリプトファイルを作成するときに必要になります。

    3. マップを選択します。

      注記

      マップスタイルを選択すると、利用するマップデータプロバイダーも選択されます。配送車両や従業員など、ビジネスで使用する資産をアプリケーションで追跡またはルーティングする場合、使用できる位置情報プロバイダーは HERE のみとなります。詳細については、「AWS サービス規約」のセクション 82 を参照してください。

    4. Amazon Location の利用規約に同意し、[マップを作成] を選択します。選択したマップを、拡大、縮小、または任意の方向への画面移動をすることができます。

    5. 新しいマップリソースに表示される Amazon リソースネーム (ARN) をメモします。チュートリアルの後半で、これを使って正しい認証を作成します。

  2. 使用するプレースインデックスを選択します。

    1. Amazon Location コンソールの[プレースインデックス」ページで、「プレイスーンデックスを作成」を選択します。

    2. 新しいプレースインデックスリソースの 名前説明を追加します。プレースインデックスリソースに入力した名前をメモしておきます。チュートリアルの後半でスクリプトファイルを作成するときに必要になります。

    3. データプロバイダーを選択します。

      注記

      ほぼすべてのケースでは、すでに選択したマッププロバイダーと一致するデータプロバイダーを選択します。これにより、検索が地図と一致するようになります。

      配送車両や従業員など、ビジネスで使用する資産をアプリケーションで追跡またはルーティングする場合、使用できる位置情報プロバイダーは HERE のみとなります。詳細については、「AWS サービス規約」のセクション 82 を参照してください。

    4. [データストレージオプション] を選択します。このチュートリアルでは結果は保存されないため、いいえ、1 回のみを選択することができます。

    5. Amazon Location の利用規約に同意し、[プレースインデックスを作成] を選択します。

    6. 新しいプレースインデックスリソースに表示される ARN をメモします。このチュートリアルの次のセクションで、これを使って正しい認証を作成します。

  3. Amazon Location コンソールを使用してトラッカーを作成するには。

    1. Amazon Location Service コンソール を開きます。

    2. 左のナビゲーションペインから、[トラッカー] を選択します。

    3. トラッカーを作成を選択します。

    4. すべての必須フィールドに入力します。

    5. 位置フィルタリング では、デフォルト設定 を使用することをお勧めしますTimeBased

    6. 終了するトラッカーの作成を選択します。

アプリケーションの認証の設定

このチュートリアルで作成したアプリケーションは匿名で使用できます。つまり、ユーザーはアプリケーション AWS を使用するためにサインインする必要はありません。しかし、Amazon Location Service API を使用するには認証が必要です。Amazon Cognito を使用して、匿名ユーザーに認証と承認を提供します。このチュートリアルでは、Amazon Cognito を使用してアプリケーションを認証します。

注記

Amazon Location Service で Amazon Cognito を使用する方法の詳細については、「」を参照してくださいAmazon Location Service へのアクセスを許可する

以下のチュートリアルでは、 で作成したマップ、場所インデックス、トラッカーの認証を設定する方法と、Amazon Location のアクセス許可を設定する方法を示します。

追跡用の IAM ポリシーを作成する
  1. 管理者権限を持つユーザーを使用して、https://console.aws.amazon.com/iam/で IAM コンソールにサインインします。

  2. ナビゲーションペインで、ポリシー を選択します。

  3. コンテンツペインで、[ポリシーの作成] を選択します。

  4. JSON オプションを選択し、この JSON ポリシーをコピーして JSON テキストボックスに貼り付けます。

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "geo:GetMapTile", "geo:GetMapStyleDescriptor", "geo:GetMapSprites", "geo:GetMapGlyphs", "geo:SearchPlaceIndexForPosition", "geo:GetDevicePositionHistory", "geo:BatchUpdateDevicePosition" ], "Resource": [ "arn:aws:geo:{Region}:{Account}:map/{MapName}", "arn:aws:geo:{Region}:{Account}:place-index/{IndexName}", "arn:aws:geo:{Region}:{Account}:tracker/{TrackerName}" ] } ] }

    これは 追跡のポリシーの例です。独自のポリシーに例を使用するには、Region、、AccountIndexNameMapNameおよび TrackerNameプレースホルダーを置き換えます。

    注記

    認証されていない ID プールはセキュリティで保護されていないインターネットサイトで公開されることを目的としていますが、標準で時間制限のある AWS 認証情報と交換されることに注意してください。

    認証されていないアイデンティティプールに関連付けられている IAM ロールの範囲を適切に設定することが重要です。Amazon Location Service で Amazon Cognito でポリシーを使用し、適切にスコープ設定する方法の詳細については、「Amazon Location Service へのアクセス権の付与」を参照してください。

  5. 確認と作成ページで、ポリシー名フィールドの名前を指定します。ポリシーによって付与されたアクセス許可を確認し、ポリシーの作成を選択して作業を保存します。

新しいポリシーが管理ポリシーの一覧に表示され、アタッチの準備ができます。

追跡用の認証を設定する
  1. Amazon Cognito コンソール でマップアプリケーションの認証を設定します。

  2. ID プールページを開きます。

    注記

    作成するプールは、前のセクションで作成した Amazon Location Service リソースと同じ AWS アカウントと AWS リージョンに存在する必要があります。

  3. ID プールの作成 を選択します。

  4. ID プールの信頼を設定するステップから開始します。ユーザーアクセス認証では、ゲストアクセス を選択し、次を押します。

  5. アクセス許可の設定ページで、既存の IAM ロールを使用する を選択し、前のステップで作成した IAM ロールの名前を入力します。準備ができたら、 の横にある を押して次のステップに進みます。

  6. 「プロパティの設定」ページで、ID プールの名前を指定します。次に、次へ を押します。

  7. 確認と作成ページで、存在するすべての情報を確認してから、アイデンティティプールの作成 を押します。

  8. ID プールページを開き、先ほど作成した ID プールを選択します。次に、ブラウザスクリプトで後 IdentityPoolId で使用する をコピーまたは書き留めます。

ベース iOS アプリケーションの作成

このチュートリアルでは、マップを埋め込む iOS アプリケーションを作成し、ユーザーがマップ上の場所にあるものを見つけられるようにします。

まず、Xcode のプロジェクトウィザードを使用して Swift アプリケーションを作成しましょう。

空のアプリケーションを作成するには (Xcode)
  1. Xcode を開き、メニューからファイル新規 新規プロジェクト を選択します。

  2. iOS タブから、アプリ を選択し、次へ を選択します。

  3. インターフェイスフィールドの入力 に、製品名組織識別子 、および を指定しますSwiftUIへ を選択して選択を確定します。

  4. プロジェクトを保存する場所を選択し、作成ボタンを押して空のアプリケーションを作成します。

ベースアプリケーションを作成したら、サンプルアプリケーションに必要なパッケージをインストールする必要があります。

必要な依存関係のインストール
  1. Xcode でプロジェクトを右クリックし、パッケージの追加... を選択します。これにより、パッケージウィンドウが開き、プロジェクトにパッケージを追加できます。

  2. パッケージウィンドウで、次のパッケージを追加します。

初期コードのセットアップ

アプリでロケーション許可を有効にする
  1. Xcode プロジェクトを開きます。

  2. プロジェクトの Info.plist ファイルを見つけます。

  3. アプリの要件に基づいて、ロケーション許可に必要なキーを追加します。キーは次のとおりです。

    • NSLocationWhenInUseUsageDescription: アプリケーションが使用中にロケーションアクセスを必要とする理由の説明。

    • NSLocationAlwaysAndWhenInUseUsageDescription: アプリが継続的なロケーションアクセスを必要とする理由の説明。

次に、アプリでリソース値を設定する必要があります。という名前の新しいファイルを追加Config.xcconfigし、Amazon コンソールで以前に作成した値を入力します。

REGION = INDEX_NAME = MAP_NAME = IDENTITY_POOL_ID = TRACKER_NAME =
  1. 左側のナビゲーターセクションで、プロジェクトを選択します。

  2. ターゲットセクションで、アプリを選択し、情報タブをクリックします。

  3. 次のような値を持つ情報プロパティを追加します。

  4. 以下の内容の Config.swift ファイルを追加します。これにより、バンドル情報ファイルから設定値が読み取られます。

    import Foundation enum Config { static let region = Bundle.main.object(forInfoDictionaryKey: "Region") as! String static let mapName = Bundle.main.object(forInfoDictionaryKey: "MapName") as! String static let indexName = Bundle.main.object(forInfoDictionaryKey: "IndexName") as! String static let identityPoolId = Bundle.main.object(forInfoDictionaryKey: "IdentityPoolId") as! String static let trackerName = Bundle.main.object(forInfoDictionaryKey: "TrackerName") as! String }
  5. という名前の新しいフォルダViewModelを作成し、その中にTrackingViewModel.swiftファイルを追加します。

    import SwiftUI import AmazonLocationiOSAuthSDK import MapLibre final class TrackingViewModel : ObservableObject { @Published var trackingButtonText = NSLocalizedString("StartTrackingLabel", comment: "") @Published var trackingButtonColor = Color.blue @Published var trackingButtonIcon = "play.circle" @Published var region : String @Published var mapName : String @Published var indexName : String @Published var identityPoolId : String @Published var trackerName : String @Published var showAlert = false @Published var alertTitle = "" @Published var alertMessage = "" @Published var centerLabel = "" var clientIntialised: Bool var client: LocationTracker! var authHelper: AuthHelper var credentialsProvider: LocationCredentialsProvider? var mlnMapView: MLNMapView? var mapViewDelegate: MapViewDelegate? var lastGetTrackingTime: Date? var trackingActive: Bool init(region: String, mapName: String, indexName: String, identityPoolId: String, trackerName: String) { self.region = region self.mapName = mapName self.indexName = indexName self.identityPoolId = identityPoolId self.trackerName = trackerName self.authHelper = AuthHelper() self.trackingActive = false self.clientIntialised = false } func authWithCognito(identityPoolId: String?) { guard let identityPoolId = identityPoolId?.trimmingCharacters(in: .whitespacesAndNewlines) else { alertTitle = NSLocalizedString("Error", comment: "") alertMessage = NSLocalizedString("NotAllFieldsAreConfigured", comment: "") showAlert = true return } credentialsProvider = authHelper.authenticateWithCognitoUserPool(identityPoolId: identityPoolId) initializeClient() } func initializeClient() { client = LocationTracker(provider: credentialsProvider!, trackerName: trackerName) clientIntialised = true } }

アプリケーションにインタラクティブマップを追加

次に、アプリケーションにマップコントロールを追加します。このチュートリアルでは、 MapLibre と AWS API を使用して、アプリケーションでマップビューを管理します。マップコントロール自体は MapLibre GL Native iOS ライブラリの一部です。

  1. 次のコードを使用して、Views フォルダの下に MapView.swift ファイルを追加します。

    import SwiftUI import MapLibre struct MapView: UIViewRepresentable { var onMapViewAvailable: ((MLNMapView) -> Void)? var mlnMapView: MLNMapView? var trackingViewModel: TrackingViewModel func makeCoordinator() -> MapView.Coordinator { return Coordinator(self, trackingViewModel: trackingViewModel) } func makeUIView(context: Context) -> MLNMapView { let styleURL = URL(string: "https://maps.geo.\(trackingViewModel.region).amazonaws.com/maps/v0/maps/\(trackingViewModel.mapName)/style-descriptor") let mapView = MLNMapView(frame: .zero, styleURL: styleURL) mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] mapView.setZoomLevel(15, animated: true) mapView.showsUserLocation = true mapView.userTrackingMode = .follow context.coordinator.mlnMapView = mapView mapView.delegate = context.coordinator mapView.logoView.isHidden = true context.coordinator.addCenterMarker() onMapViewAvailable?(mapView) trackingViewModel.mlnMapView = mapView return mapView } func updateUIView(_ uiView: MLNMapView, context: Context) { } class Coordinator: NSObject, MLNMapViewDelegate, MapViewDelegate { var control: MapView var mlnMapView: MLNMapView? var trackingViewModel: TrackingViewModel var centerMarker: MLNPointAnnotation? public init(_ control: MapView, trackingViewModel: TrackingViewModel) { self.control = control self.trackingViewModel = trackingViewModel super.init() self.trackingViewModel.mapViewDelegate = self } func mapViewDidFinishRenderingMap(_ mapView: MLNMapView, fullyRendered: Bool) { if(fullyRendered) { mapView.accessibilityIdentifier = "MapView" mapView.isAccessibilityElement = false } } func addCenterMarker() { guard let mlnMapView = mlnMapView else { return } let centerCoordinate = mlnMapView.centerCoordinate let marker = MLNPointAnnotation() marker.coordinate = centerCoordinate marker.accessibilityLabel = "CenterMarker" mlnMapView.addAnnotation(marker) centerMarker = marker trackingViewModel.reverseGeocodeCenter(centerCoordinate: centerCoordinate, marker: marker) } func mapView(_ mapView: MLNMapView, regionDidChangeAnimated animated: Bool) { if let marker = centerMarker { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { mapView.deselectAnnotation(marker, animated: false) marker.coordinate = mapView.centerCoordinate let centerCoordinate = mapView.centerCoordinate self.trackingViewModel.reverseGeocodeCenter(centerCoordinate: centerCoordinate, marker: marker) } } } } }
  2. ViewModel フォルダの下に AWSSignatureV4Delegate ファイルを追加します。このファイルは、マップをレンダリングするためのすべての MapView http リクエストで署名するために使用されます。

    import MapLibre import AmazonLocationiOSAuthSDK class AWSSignatureV4Delegate : NSObject, MLNOfflineStorageDelegate { private let awsSigner: AWSSigner init(credentialsProvider: LocationCredentialsProvider) { self.awsSigner = DENY LIST ERROR , serviceName: "geo") super.init() } func offlineStorage(_ storage: MLNOfflineStorage, urlForResourceOf kind: MLNResourceKind, with url: URL) -> URL { if url.host?.contains("amazonaws.com") != true { return url } let signedURL = awsSigner.signURL(url: url, expires: .hours(1)) return signedURL } }
  3. ビューフォルダにUserLocationView.swiftファイルを追加します。これにより、マップをユーザーの位置の中央に配置するボタンが追加されます。

    import SwiftUI struct UserLocationView: View { @ObservedObject var trackingViewModel: TrackingViewModel var body: some View { Button(action: { trackingViewModel.locateMe() }) { Image(systemName: "scope") .resizable() .frame(width: 24, height: 24) .padding(5) .background(Color.white) .foregroundColor(.blue) .clipShape(RoundedRectangle(cornerRadius: 8)) .shadow(color: Color.black.opacity(0.3), radius: 3, x: 0, y: 2) } .accessibility(identifier: "LocateMeButton") .padding(.trailing, 10) .padding(.bottom, 10) .frame(maxWidth: .infinity, alignment: .trailing) } }
  4. 次のコードで TrackingView.swift ファイルを追加します。

    import SwiftUI struct TrackingView: View { @ObservedObject var trackingViewModel: TrackingViewModel var body: some View { ZStack(alignment: .bottom) { MapView(trackingViewModel: trackingViewModel) VStack { UserLocationView(trackingViewModel: trackingViewModel) } } .onAppear() { if !trackingViewModel.identityPoolId.isEmpty { trackingViewModel.authWithCognito(identityPoolId: trackingViewModel.identityPoolId) } } } }

これで、アプリケーションを構築できます。これを実行するには、Xcode でエミュレートするデバイスを設定するか、デバイスでアプリを使用する必要がある場合があります。このアプリを使用して、マップコントロールの動作を確認します。マップをドラッグしてパンし、ピンチしてズームできます。マップコントロールの仕組みを自分で変更して、アプリケーションのニーズに合わせてカスタマイズできます。

次に、リバースジオコーディング検索をアプリケーションに追加します。ここでは、ある場所にある項目を見つけます。iOS アプリの使用を簡素化するために、画面の中央を検索します。新しい場所を見つけるには、検索したい場所にマップを移動します。マップの中央にマーカーを配置して、検索している場所を示します。

  1. リバースジオコーディング検索に関連する次のコードを TrackingViewModel`.swift` ファイルに追加します。

    func reverseGeocodeCenter(centerCoordinate: CLLocationCoordinate2D, marker: MLNPointAnnotation) { let position = [NSNumber(value: centerCoordinate.longitude), NSNumber(value: centerCoordinate.latitude)] searchPositionAPI(position: position, marker: marker) } func searchPositionAPI(position: [Double], marker: MLNPointAnnotation) { if let amazonClient = authHelper.getLocationClient() { Task { let searchRequest = SearchPlaceIndexForPositionInput(indexName: indexName, language: "en" , maxResults: 10, position: position) let searchResponse = try? await amazonClient.searchPosition(indexName: indexName, input: searchRequest) DispatchQueue.main.async { self.centerLabel = searchResponse?.results?.first?.place?.label ?? "" self.mlnMapView?.selectAnnotation(marker, animated: true, completionHandler: {}) } } } }
  2. マップビューの中央ロケーションのアドレスを示す次のコードでTrackingView.swiftファイルを更新します。

    import SwiftUI struct TrackingView: View { @ObservedObject var trackingViewModel: TrackingViewModel var body: some View { ZStack(alignment: .bottom) { if trackingViewModel.mapSigningIntialised { MapView(trackingViewModel: trackingViewModel) VStack { UserLocationView(trackingViewModel: trackingViewModel) CenterAddressView(trackingViewModel: trackingViewModel) } } else { Text("Loading...") } } .onAppear() { if !trackingViewModel.identityPoolId.isEmpty { Task { do { try await trackingViewModel.authWithCognito(identityPoolId: trackingViewModel.identityPoolId) } catch { print(error) } } } } } }

アプリケーションへの追跡の追加

アプリケーションの最後のステップは、アプリケーションに追跡機能を追加することです。この場合、アプリに追跡の開始、追跡の停止、トラッカーポイントの取得と表示を追加します。

  1. プロジェクトに TrackingBottomView.swift ファイルを追加します。ユーザーの位置の追跡を開始および停止するボタンがあり、マップ上に追跡ポイントを表示します。

    import SwiftUI struct TrackingBottomView: View { @ObservedObject var trackingViewModel: TrackingViewModel var body: some View { Button(action: { Task { if(trackingViewModel.trackingButtonText == NSLocalizedString("StartTrackingLabel", comment: "")) { trackingViewModel.startTracking() } else { trackingViewModel.stopTracking() } } }) { HStack { Spacer() Text("Tracking") .foregroundColor(trackingViewModel.trackingButtonColor) .background(.white) .cornerRadius(15.0) Image(systemName: trackingViewModel.trackingButtonIcon) .resizable() .frame(width: 24, height: 24) .padding(5) .background(.white) .foregroundColor(trackingViewModel.trackingButtonColor) } } .accessibility(identifier: "TrackingButton") .background(.white) .clipShape(RoundedRectangle(cornerRadius: 8)) .padding(.trailing, 10) .padding(.bottom, 40) .frame(width: 130, alignment: .trailing) .shadow(color: Color.black.opacity(0.3), radius: 3, x: 0, y: 2) } }
  2. 次のコードでTrackingView.swiftファイルを更新する

    import SwiftUI struct TrackingView: View { @ObservedObject var trackingViewModel: TrackingViewModel var body: some View { ZStack(alignment: .bottom) { if trackingViewModel.mapSigningIntialised { MapView(trackingViewModel: trackingViewModel) VStack { UserLocationView(trackingViewModel: trackingViewModel) CenterAddressView(trackingViewModel: trackingViewModel) TrackingBottomView(trackingViewModel: trackingViewModel) } } else { Text("Loading...") } } .onAppear() { if !trackingViewModel.identityPoolId.isEmpty { Task { do { try await trackingViewModel.authWithCognito(identityPoolId: trackingViewModel.identityPoolId) } catch { print(error) } } } } } }
  3. ファイルに次のコードを追加しますTrackingViewModel.swift。これらの関数は、追跡の開始と停止を担当します。また、ユーザーロケーションのアクセス許可が拒否されると、エラーアラートも表示されます。

  4. フォアグラウンド追跡コピーを実装するには、次のコード例を貼り付けます。

    func showLocationDeniedRationale() { alertTitle = NSLocalizedString("locationManagerAlertTitle", comment: "") alertMessage = NSLocalizedString("locationManagerAlertText", comment: "") showAlert = true } // Required in info.plist: Privacy - Location When In Use Usage Description func startTracking() { do { print("Tracking Started...") if(client == nil) { initializeClient() } try client.startTracking() DispatchQueue.main.async { [self] in self.trackingButtonText = NSLocalizedString("StopTrackingLabel", comment: "") self.trackingButtonColor = .red self.trackingButtonIcon = "pause.circle" trackingActive = true } } catch TrackingLocationError.permissionDenied { showLocationDeniedRationale() } catch { print("error in tracking") } } func stopTracking() { print("Tracking Stopped...") client.stopTracking() trackingButtonText = NSLocalizedString("StartTrackingLabel", comment: "") trackingButtonColor = .blue trackingButtonIcon = "play.circle" trackingActive = false }
    注記

    startTracking は、ユーザーの場所のアクセス許可を要求します。アプリケーションは、使用中または 1 回のみのアクセス許可を使用する必要があります。そうしないと、アプリケーションはアクセス許可拒否エラーをスローします。

追跡場所を取得して表示するには、次の手順に従います。

  1. ユーザーのデバイスからロケーションを取得するには、開始日時と終了日時を指定する必要があります。1 回の呼び出しで最大 100 個の追跡場所が返されますが、100 個を超える追跡場所がある場合、`nextToken` 値が返されます。指定された開始時刻と終了時刻の追跡ポイントをロードするには、「nextToken」で後続のgetTrackerDevice「Location」呼び出しを呼び出す必要があります。

    func getTrackingPoints(nextToken: String? = nil) async throws { guard trackingActive else { return } // Initialize startTime to 24 hours ago from the current date and time. let startTime: Date = Date().addingTimeInterval(-86400) var endTime: Date = Date() if lastGetTrackingTime != nil { endTime = lastGetTrackingTime! } let result = try await client?.getTrackerDeviceLocation(nextToken: nextToken, startTime: startTime, endTime: endTime) if let trackingData = result { lastGetTrackingTime = Date() let devicePositions = trackingData.devicePositions let positions = devicePositions!.sorted { (pos1: LocationClientTypes.DevicePosition, pos2: LocationClientTypes.DevicePosition) -> Bool in guard let date1 = pos1.sampleTime, let date2 = pos2.sampleTime else { return false } return date1 < date2 } let trackingPoints = positions.compactMap { position -> CLLocationCoordinate2D? in guard let latitude = position.position!.last, let longitude = position.position!.first else { return nil } return CLLocationCoordinate2D(latitude: latitude, longitude: longitude) } DispatchQueue.main.async { self.mapViewDelegate!.drawTrackingPoints( trackingPoints: trackingPoints) } if let nextToken = trackingData.nextToken { try await getTrackingPoints(nextToken: nextToken) } } }
  2. 次に、 MapView.swift ファイル内のコードを次のコードに置き換えます。

    import SwiftUI import MapLibre struct MapView: UIViewRepresentable { var onMapViewAvailable: ((MLNMapView) -> Void)? var mlnMapView: MLNMapView? var trackingViewModel: TrackingViewModel func makeCoordinator() -> MapView.Coordinator { return Coordinator(self, trackingViewModel: trackingViewModel) } func makeUIView(context: Context) -> MLNMapView { let styleURL = URL(string: "https://maps.geo.\(trackingViewModel.region).amazonaws.com/maps/v0/maps/\(trackingViewModel.mapName)/style-descriptor") let mapView = MLNMapView(frame: .zero, styleURL: styleURL) mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] mapView.setZoomLevel(15, animated: true) mapView.showsUserLocation = true mapView.userTrackingMode = .follow context.coordinator.mlnMapView = mapView mapView.delegate = context.coordinator mapView.logoView.isHidden = true context.coordinator.addCenterMarker() onMapViewAvailable?(mapView) trackingViewModel.mlnMapView = mapView return mapView } func updateUIView(_ uiView: MLNMapView, context: Context) { } class Coordinator: NSObject, MLNMapViewDelegate, MapViewDelegate { var control: MapView var mlnMapView: MLNMapView? var trackingViewModel: TrackingViewModel var centerMarker: MLNPointAnnotation? public init(_ control: MapView, trackingViewModel: TrackingViewModel) { self.control = control self.trackingViewModel = trackingViewModel super.init() self.trackingViewModel.mapViewDelegate = self } func mapViewDidFinishRenderingMap(_ mapView: MLNMapView, fullyRendered: Bool) { if(fullyRendered) { mapView.accessibilityIdentifier = "MapView" mapView.isAccessibilityElement = false } } func addCenterMarker() { guard let mlnMapView = mlnMapView else { return } let centerCoordinate = mlnMapView.centerCoordinate let marker = MLNPointAnnotation() marker.coordinate = centerCoordinate marker.accessibilityLabel = "CenterMarker" mlnMapView.addAnnotation(marker) centerMarker = marker trackingViewModel.reverseGeocodeCenter(centerCoordinate: centerCoordinate, marker: marker) } func mapView(_ mapView: MLNMapView, regionDidChangeAnimated animated: Bool) { if let marker = centerMarker { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { mapView.deselectAnnotation(marker, animated: false) marker.coordinate = mapView.centerCoordinate let centerCoordinate = mapView.centerCoordinate self.trackingViewModel.reverseGeocodeCenter(centerCoordinate: centerCoordinate, marker: marker) } } } func mapView(_ mapView: MLNMapView, viewFor annotation: MLNAnnotation) -> MLNAnnotationView? { guard let pointAnnotation = annotation as? MLNPointAnnotation else { return nil } let reuseIdentifier: String var color: UIColor = .black if pointAnnotation.accessibilityLabel == "Tracking" { reuseIdentifier = "TrackingAnnotation" color = UIColor(red: 0.00784313725, green: 0.50588235294, blue: 0.58039215686, alpha: 1) } else if pointAnnotation.accessibilityLabel == "LocationChange" { reuseIdentifier = "LocationChange" color = .gray } else { reuseIdentifier = "DefaultAnnotationView" } var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier) if annotationView == nil { if reuseIdentifier != "DefaultAnnotationView" { annotationView = MLNAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier) //If point annotation is an uploaded Tracking point the radius is 20 and color is blue, otherwise radius is 10 and color is gray let radius = pointAnnotation.accessibilityLabel == "Tracking" ? 20:10 annotationView?.frame = CGRect(x: 0, y: 0, width: radius, height: radius) annotationView?.backgroundColor = color annotationView?.layer.cornerRadius = 10 if pointAnnotation.accessibilityLabel == "Tracking" { annotationView?.layer.borderColor = UIColor.white.cgColor annotationView?.layer.borderWidth = 2.0 annotationView?.layer.shadowColor = UIColor.black.cgColor annotationView?.layer.shadowOffset = CGSize(width: 0, height: 2) annotationView?.layer.shadowRadius = 3 annotationView?.layer.shadowOpacity = 0.2 annotationView?.clipsToBounds = false } } else { return nil } } return annotationView } func mapView(_ mapView: MLNMapView, didUpdate userLocation: MLNUserLocation?) { if (userLocation?.location) != nil { if trackingViewModel.trackingActive { let point = MLNPointAnnotation() point.coordinate = (userLocation?.location!.coordinate)! point.accessibilityLabel = "LocationChange" mapView.addAnnotation(point) Task { do { try await trackingViewModel.getTrackingPoints() } catch { print(error) } } } } } func checkIfTrackingAnnotationExists(on mapView: MLNMapView, at coordinates: CLLocationCoordinate2D) -> Bool { let existingAnnotation = mapView.annotations?.first(where: { annotation in guard let annotation = annotation as? MLNPointAnnotation else { return false } return annotation.coordinate.latitude == coordinates.latitude && annotation.coordinate.longitude == coordinates.longitude && annotation.accessibilityLabel == "Tracking" }) return existingAnnotation != nil } public func drawTrackingPoints(trackingPoints: [CLLocationCoordinate2D]?) { guard let mapView = mlnMapView, let newTrackingPoints = trackingPoints, !newTrackingPoints.isEmpty else { return } let uniqueCoordinates = newTrackingPoints.filter { coordinate in !checkIfTrackingAnnotationExists(on: mapView, at: coordinate) } let points = uniqueCoordinates.map { coordinate -> MLNPointAnnotation in let point = MLNPointAnnotation() point.coordinate = coordinate point.accessibilityLabel = "Tracking" return point } mapView.addAnnotations(points) } } } protocol MapViewDelegate: AnyObject { func drawTrackingPoints(trackingPoints: [CLLocationCoordinate2D]?) }

文字列値 をローカライズするには、次の手順を使用します。

  1. という名前の新しいファイルを作成して追加しますLocalizable.xcstrings

  2. Localizable.xcstrings ファイルを右クリックし、ソースコード として開きます。

  3. その内容を以下に置き換えます。

    { "sourceLanguage" : "en", "strings" : { "Cancel" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", "value" : "Cancel" } } } }, "Error" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", "value" : "Error" } } } }, "Loading..." : { }, "locationManagerAlertText" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", "value" : "Allow \\\"Quick Start App\\\" to use your location" } } } }, "locationManagerAlertTitle" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", "value" : "We need your location to detect your location in map" } } } }, "NotAllFieldsAreConfigured" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", "value" : "Not all the fields are configured" } } } }, "OK" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", "value" : "OK" } } } }, "StartTrackingLabel" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", "value" : "Start Tracking" } } } }, "StopTrackingLabel" : { "localizations" : { "en" : { "stringUnit" : { "state" : "translated", "value" : "Stop Tracking" } } } }, "Tracking" : { } }, "version" : "1.0" }
  4. ファイルを保存し、アプリを構築して実行し、機能をプレビューします。

  5. ロケーション許可を付与し、追跡ボタンをタップします。アプリはユーザーロケーションのアップロードを開始し、Amazon Location トラッカーにアップロードします。また、ユーザーの位置変更、追跡ポイント、現在の住所がマップに表示されます。

クイックスタートアプリケーションが完了しました。このチュートリアルでは、以下の iOS アプリケーションを作成する方法を説明します。

  • ユーザーが操作できるマップを作成します。

  • マップビューを変更するユーザーに関連するいくつかのマップイベントを処理します。

  • Amazon Location Service API を呼び出します。具体的には、Amazon Location の searchByPosition API を使用して、特定の場所でマップを検索します。

次のステップ

このアプリケーションのソースコードは、 で入手できますGitHub

Amazon Location をさらに活用するには、以下のリソースをご覧ください。