iOS 앱 만들기 - Amazon Location Service

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

iOS 앱 만들기

이 섹션에서는 특정 위치를 검색하고 포그라운드에서 추적할 수 있는 iOS 애플리케이션을 생성합니다. 먼저 Amazon 위치 리소스와 애플리케이션을 위한 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. 데이터 스토리지 옵션을 선택합니다. 이 튜토리얼에서는 결과가 저장되지 않으므로 아니오, 한 번만 사용합니다를 선택할 수 있습니다.

    5. Amazon Location 이용 약관에 동의한 다음 장소 색인 생성을 선택합니다.

    6. 새 장소 색인 리소스에 표시되는 ARN을 기록해 둡니다. 이는 튜토리얼의 다음 섹션에서 올바른 인증을 만드는 데 사용합니다.

  3. Amazon 위치 콘솔을 사용하여 트래커를 만들려면

    1. Amazon 위치 서비스 콘솔을 엽니다.

    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 AccountIndexName, MapNameTrackerName자리 표시자를 바꾸십시오.

    참고

    인증되지 않은 자격 증명 풀은 보안되지 않은 인터넷 사이트에 노출되기 위한 것이지만, 이러한 자격 증명 풀은 기간 제한이 있는 표준 자격 증명으로 교환된다는 점에 유의하십시오. AWS

    인증되지 않은 자격 증명 풀과 관련된 IAM 역할의 범위를 적절하게 지정하는 것이 중요합니다. Amazon Location Service와 함께 Amazon Cognito에서 정책을 사용하고 적절하게 범위를 지정하는 방법에 대한 자세한 내용은 Amazon Location Service에 대한 액세스 권한 부여를 참조하십시오.

  5. 검토 및 생성 페이지에서 정책 이름 필드에 이름을 입력합니다. 정책에서 부여한 권한을 검토한 다음 [Create Policy] 를 선택하여 작업 내용을 저장합니다.

새로운 정책이 관리형 정책 목록에 나타나며 연결 준비가 완료됩니다.

추적에 대한 인증을 설정하세요.
  1. Amazon Cognito 콘솔에서 맵 애플리케이션에 대한 인증을 설정합니다.

  2. 자격 증명 풀 페이지를 엽니다.

    참고

    생성한 풀은 이전 섹션에서 생성한 Amazon Location Service 리소스와 동일한 AWS 계정 및 AWS 지역에 있어야 합니다.

  3. 자격 증명 풀 생성을 선택합니다.

  4. ID 풀 신뢰 구성 단계부터 시작합니다. 사용자 액세스 인증의 경우 게스트 액세스를 선택하고 다음을 누릅니다.

  5. 권한 구성 페이지에서 기존 IAM 역할 사용을 선택하고 이전 단계에서 생성한 IAM 역할의 이름을 입력합니다. 준비가 되면 다음을 눌러 다음 단계로 넘어갑니다.

  6. 속성 구성 페이지에서 자격 증명 풀의 이름을 입력합니다. 그런 다음 다음을 누릅니다.

  7. 검토 및 생성 페이지에서 제공되는 모든 정보를 검토한 다음 ID 풀 생성을 누릅니다.

  8. 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 } }

애플리케이션에 대화형 맵 추가

이제 애플리케이션에 맵 컨트롤을 추가해 보겠습니다. 이 자습서에서는 애플리케이션에서 맵 뷰를 관리하기 위해 AWS API를 사용합니다 MapLibre . 맵 컨트롤 자체는 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. Views 폴더에 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는 사용자의 위치 권한을 요청합니다. 애플리케이션은 사용 중 또는 Only Only Once 권한을 사용해야 합니다. 그렇지 않으면 애플리케이션에서 권한 거부 오류가 발생합니다.

추적 위치를 가져와 표시하려면 다음 절차를 따르십시오.

  1. 사용자 기기에서 위치를 가져오려면 시작 및 종료 날짜와 시간을 제공해야 합니다. 단일 호출은 최대 100개의 추적 위치를 반환하지만, 추적 위치가 100개 이상인 경우 'NextToken' 값을 반환합니다. 지정된 시작 및 종료 시간에 대해 더 많은 추적 지점을 로드하려면 'NextToken'으로 후속 'getTrackerDevice위치' 호출을 호출해야 합니다.

    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 위치 추적기에 업로드합니다. 또한 지도에 사용자 위치 변경, 추적 지점, 현재 주소도 표시됩니다.

퀵스타트 신청이 완료되었습니다. 이 자습서에서는 다음과 같은 iOS 애플리케이션을 만드는 방법을 보여 주었습니다.

  • 사용자가 상호 작용할 수 있는 맵을 만듭니다.

  • 사용자가 맵 뷰를 변경하는 것과 관련된 여러 맵 이벤트를 처리합니다.

  • 특히 Amazon 로케이션의 API를 사용하여 특정 위치의 지도를 검색하기 위해 Amazon Location Service searchByPosition API를 호출합니다.

다음에 있는 것

이 애플리케이션의 소스 코드는 에서 확인할 수 있습니다 GitHub.

Amazon Location을 최대한 활용하려면 다음 리소스를 확인하세요.