스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
MapKit으로 장소 정보를 효과적으로 활용하기
MapKit 및 MapKit JS로 지도를 앱과 웹사이트에 통합하는 새롭고 효과적인 방법을 확인해 보세요. Place ID를 사용하여 특정 장소를 저장하고 참조할 수 있습니다. 관련성 높은 장소를 더욱 효율적으로 찾을 수 있도록 해주는 향상된 검색 기능에 대해서도 알아보세요. 새로운 Place Card API를 사용하면 고객이 앱에서 바로 목적지를 살펴볼 수 있도록 자세한 장소 정보를 표시할 수 있습니다. 또한 Apple의 간소화된 토큰 권한 설정과 Web Embed API로 웹사이트에 지도를 임베드하는 간단한 방법을 소개합니다.
챕터
- 0:00 - Introduction
- 0:54 - Reference a place
- 6:12 - Display place details
- 12:05 - Find a place
리소스
- Displaying place information using the Maps Embed API
- Forum: Maps & Location
- Identifying unique locations with Place IDs
- Interacting with nearby points of interest
- Resources - Apple Maps - Apple Developer
관련 비디오
WWDC23
-
다운로드
안녕하세요, Mike입니다 안녕하세요, Jeff입니다 저희는 MapKit 엔지니어입니다 이번 세션에서는 MapKit 프레임워크 및 웹용 MapKit JS에서 사용할 수 있는 몇 가지 새 기능을 소개해 드릴게요 지도를 사용하는 대부분의 이유는 장소를 찾기 위해서죠 Apple 지도를 사용하여 장소를 탐색하거나 살펴볼 때 사용자는 전 세계 장소에 대한 풍부한 정보에 접근할 수 있습니다 올해 MapKit에는 새로운 방식으로 앱에서 장소를 구현할 수 있도록 하는 기능이 추가되었습니다 오늘 다룬 내용은 3가지 주요 사용 사례에 초점을 두죠 구체적으로는, 식별자로 장소를 참조하는 방법과 앱의 UI를 통해 장소에 대한 세부 정보를 표시하는 방법 그리고 개선된 Search API로 장소를 효과적으로 찾는 방법을 다룰게요 우선 장소를 참조하는 방법을 설명하겠습니다 올해 장소에 대한 식별자가 도입됩니다 Place ID는 MapKit 프레임워크의 지도 항목과 MapKit JS의 Place로 나타나는 장소를 참조하기 위해 사용할 수 있습니다 Place ID를 통해 다양한 장소를 참조할 수 있습니다 박물관, 음식점, 공원, 학교와 같은 관심 지점에 Place ID를 사용할 수 있죠 앱에서 Place ID를 사용하여 저자가 신작 출간을 기념하기 위한 사인회 투어에서 방문할 서점을 참조할 수 있습니다 참조는 고유하므로 시간이 지나도 유효한 상태로 남죠 장소가 남아 있는 한 유지되도록 설계되었습니다 도서 사인회 투어 앱에서 투어에 관여하는 서점에 대한 웹사이트 링크를 제공할 수도 있죠 Apple에서 웹사이트 URL 등 서점에 대한 데이터를 업데이트해도 Place ID를 사용하는 앱은 최신 정보를 표시할 수 있습니다 이러한 ID는 고유하므로 앱은 자체 데이터 구조에서 Place ID를 키로 사용할 수 있죠 ID는 유지되고 공유될 수 있습니다 이 데이터는 Apple에서 추적하므로 언제든지 참조할 수 있습니다 최근에 앱을 빌드하고 있다고 말씀하셨죠 Place ID를 비롯한 새 기능을 많이 사용하는 앱을요 어떤 앱을 빌드했는지 보여 주시겠어요? 물론이죠 제 앱은 장소 수집이 주요 기능이므로 Place ID가 유용하죠 My Apple Store Collector 앱입니다 다양한 국가를 살펴보면서 영업을 막 시작한 Apple Store를 모으는 것을 좋아해요 Apple Store를 위한 멋진 매장 색인을 만들 때 Place ID를 쓸 수 있죠 우선 수집할 항목을 찾아야 하는데요 Apple Park Visitor Center를 먼저 수집해 볼게요 인덱스를 시작하기 위해 Visitor Center의 Place ID를 찾겠습니다 Search, Geocoding 등 기존 API로도 Place ID를 찾을 수 있지만 저는 새로운 Place ID 조회 도구를 사용할게요 ID 몇 개만 찾을 때는 이 도구가 더 빠르기 때문이죠 먼저 developer.apple.com/maps로 이동하고 오른쪽 상단의 리소스 링크를 클릭합니다 리소스 페이지에서 아래로 스크롤하면 Place ID 조회가 있죠
이 도구로 간편하게 Apple Park Visitor Center를 찾을 수 있죠 또는 지도에서 Visitor Center에 탭하여 Place ID를 볼 수 있습니다 훌륭하네요 ID를 파악했으니 앱의 지도에 해당 장소를 표시하려고 합니다 몇 줄의 코드만으로 가능합니다 Apple Park Visitor Center를 표시하기 위한 코드입니다 여기에서 조회 도구를 통해 파악한 Place ID로 식별자를 만듭니다 이 ID는 비동기 요청을 통해 지도 항목을 가져올 때 사용됩니다 앱에서는 해당 항목을 포함하는 마커가 있는 지도를 표시하죠 하드 코딩된 좌표 대신에 Place ID를 사용하면 Apple 지도 편집자가 제공하는 이점을 누릴 수 있습니다 예를 들어 특정 장소가 잘못 배치되었다고 편집자가 판단하여 마커를 옮겨야 한다면 코드 업데이트 없이 편집자의 변경 사항이 상속됩니다 Place ID를 모든 네이티브 앱 및 웹 콘텐츠와 공유할 수도 있죠 동등한 디스플레이를 웹에서 만들기 위한 JavaScript 코드입니다 먼저 entryPoint라는 함수를 만듭니다 이 함수가 초기화된 후 호출하도록 MapKit JS에 지시할게요 이 함수에서 장소 ID 조회 웹사이트에서 찾은 ID를 해당 장소를 검색하고 콜백에 전송해 주는 새 함수로 전달하겠습니다 이 경우 annotatePlace입니다 annotatePlace 함수는 장소를 중심으로 한 새 지도를 구성하고 장소 객체를 표시하기 위해 설계된 새 주석인 PlaceAnnotation을 추가합니다 entryPoint 함수가 로드된 후 호출하도록 MapKit JS에 알릴게요 올해부터는 MapKit JS 초기화에 필요한 코드가 줄어듭니다 시작하려면 이 비동기 스크립트 태그를 MapKit JS src 속성과 함께 추가한 다음 entryPoint 함수를 data-callback으로 나열하여 함수가 로드된 후 호출하도록 MapKit JS에 알립니다 마지막 속성은 data-token입니다 이 토큰을 처음 보시나요? 올해 Apple에서는 동적 JWT 생성 프로세스를 도메인별 토큰 문자열을 생성하는 간소화된 UI로 대체합니다 이러한 문자열은 수동으로 취소하기 전까지 유효하죠 새 토큰 프로비저닝 도구로 새 토큰을 만들게요 먼저 developer.apple.com/maps로 이동하고 오른쪽 상단의 리소스 링크를 클릭합니다 리소스 페이지에서 아래로 스크롤하면 토큰 생성하기가 있죠
추가 버튼을 클릭하면 만료되지 않고 내 도메인에서만 유효한 MapKit JS 생성 토큰을 만들기 위한 간단한 양식을 작성할 수 있죠 만든 토큰이 더 이상 유효하지 않으면 나중에 여기로 돌아와서 토큰을 취소할 수 있습니다 이제 토큰을 스크립트 태그에 바로 복사할 수 있죠 만료일, 동적 JWT 생성이나 mapkit.init 호출에 대해 더 이상 신경 쓰지 않아도 됩니다 이제 개점한 Apple Store를 앱과 웹에서 보여 줄 준비가 된 것 같네요 앱 빌드 과정이 순조롭네요 같은 식별자를 사용하여 앱과 웹사이트에서 특정 Apple Store를 참조할 수 있어 편리하네요 Place ID로 할 수 있는 작업은 매우 다양합니다 이 기술을 Place ID 수집 경험을 빌드하고 유지하는 데 활용하는 방법을 자세히 알아보려면 이 세션의 리소스에서 제공된 ‘Place ID로 고유한 위치 식별하기’를 확인해 보세요 장소 ID를 사용하면 관심의 장소에 대해 최신 정보를 받을 수 있죠 이제 해당 장소를 정보를 앱이나 웹사이트에 표시해야 합니다 지도 앱에서 장소를 탭하면 장소 카드가 표시됩니다 장소 카드에는 영업시간, 전화번호와 같은 정보를 보여 줍니다 올해부터 MapKit로 웹사이트와 앱에 장소 카드를 도입할 수 있죠 새 SelectionAccessory API를 사용하면 지도에서 장소가 선택될 때 장소 정보를 표시할 수 있습니다 정보는 큰 전체 보기 유형이나 공간을 절약하는
콤팩트 보기로 표시할 수 있죠 지도 앱에서 장소를 확인하기 위한 링크만 보여 줄 수도 있습니다 사용 사례에 가장 적합한 스타일을 선택하거나 기본 자동 스타일을 사용하면 플랫폼과 지도 보기의 크기에 따라 MapKit가 최적의 스타일을 선택하죠 지도 보기가 없는 앱과 웹사이트도 장소 카드를 보여 줄 수 있습니다 MapItemDetail 및 PlaceDetail API는 유연성을 제공하며 다양한 사용 사례를 지원합니다 그리고 코드 삽입으로 웹사이트에 지도를 쉽게 추가할 수 있죠 개발자 웹사이트의 지도 생성하기 도구는 복사 및 붙여넣을 수 있는 HTML 코드를 생성합니다 Mike가 앱에 장소 카드를 구현하고 있거든요, 앱을 보여 주세요 네! 이제 지도에서 Visitor Center가 표시되었으니 이에 대한 최신 정보를 근사한 방식으로 보여 주고 싶네요 제가 방문한 모든 매장을 보여 주는 앱 내 지도입니다 한 줄의 코드만 추가하면 끝납니다 이제 제가 방문한 매장 중 하나를 탭하면 해당 매장에 관한 다양한 정보를 앱이 보여 줍니다 어디서든지 이렇게 근사한 데이터를 확인할 수 있도록 아까 보여 드린 웹사이트도 업데이트하겠습니다 이전의 MapKit JS 코드에 두 줄의 코드를 추가했습니다 첫 코드는 새로운 PlaceSelectionAccessory를 만들고 두 번째 코드는 이 Accessory를 기존 주석에 추가합니다 이제 Apple Park Visitor Center가 선택되면 장소 데이터가 표시되죠 MapKit JS로 장소 정보를 표시하는 이러한 방식은 페이지에 여러 관심 장소가 있거나 복잡한 사용 패턴이 있는 경우 유용하지만 한 장소만의 데이터를 표시하는 웹사이트의 경우 Jeff가 언급한 코드 삽입 방식을 사용할 수 있습니다 제 웹사이트는 현재 하나의 Apple Store에 대한 정보만 표시하므로 코드 내장으로 같은 기능을 어떻게 구현할 수 있는지 보여 드릴게요 먼저 developer.apple.com/maps로 이동하고 오른쪽 상단의 리소스 링크를 클릭합니다 리소스 페이지에서 아래로 스크롤하면 지도 생성하기가 있죠
여기서 새 Web Embed 버튼을 선택하여 장소 ID, 개발자 토큰 등이 있는 내장형 지도를 맞춤화합니다 제가 원하는 내용이 지도에 표시되면 생성된 HTML 스니펫을 웹사이트에 간편하게 복사하여 JavaScript를 작성하지 않고도 멋진 지도를 구현할 수 있습니다 풍부한 장소 정보를 표시하는 마지막 방법은 아예 지도 외 컨텍스트를 사용하는 것입니다 지금까지 수집한 모든 매장을 보여 주는 스크롤 가능한 목록이 필요할 때도 있죠 지도 대신에요 그리고 각 목록 항목에서 장소 정보를 제공하면 더 유용하겠죠 제 즐겨찾기 목록을 표시하는 코드입니다 우선 수집된 모든 매장을 포함하고 목록 항목이 해당 매장의 이름을 표시하는 목록을 보여 줍니다 이 코드가 추가되어 목록 항목을 탭할 때 전체 장소 카드가 표시되죠 웹에서도 즐겨찾기로 등록된 장소의 정보를 볼 수 있도록 웹사이트도 업데이트하겠습니다 이전에 사용한 웹 코드인데 annotatePlace 함수를 2개의 구문으로 대체했습니다 첫 번째 구문은 페이지에서 요소를 가져오고 두 번째는 제가 검색한 장소에 대한 세부 정보를 요소에 추가하죠 또한 새로운 적응형 색상 체계를 사용했으므로 이 장소 세부 정보는 시스템에서 선호하는 색상 체계와 맞추어 라이트 또는 다크 모드로 표시됩니다 이제 동일한 값으로 적응형 MapKit JS 지도도 만들 수 있죠 제 앱과 웹사이트가 더 근사해졌네요 어떻게 생각하세요? 정말 멋있네요 Mike는 새 API로 수집한 매장에 대한 장소 정보를 표시했습니다 MapItemDetail API는 장소 카드를 표시하기 위해 사용할 수 있습니다 앱에 지도 보기가 없어도 됩니다 API는 UIKit, AppKit, SwiftUI에서 사용할 수 있습니다 MapKit JS를 사용하면 PlaceDetail API로 장소 카드를 웹페이지의 콘텐츠로 추가할 수 있죠 SelectionAccessory API는 지도에서 바로 장소 정보를 표시하는 데 사용할 수 있습니다 MapKit은 다양한 플랫폼 및 기술과 호환되는 여러 SelectionAccessory API를 제공하죠
Mike가 좋아하는 매장이 포함된 지도를 보니 Mike의 발자취를 따라 그중 하나를 방문하고 싶네요 딸과 함께 방문하여 Apple 티셔츠를 사줄 수 있겠네요 딸이 소풍을 좋아하므로 공원에서 간단히 식사해도 되겠네요 이건 어떨까요 SelectionAccessory API로 지도의 다른 모든 장소에 대해 장소 카드 표시를 활성화할 수 있죠 Apple Store 외 장소도요 좋아하는 매장 근처의 지역을 탭하여 소풍하기에 적합한 공원을 찾을 수 있어요 이러면 방문할 Apple Store를 선택하는 데 도움이 되겠네요 방법을 알아보겠습니다 앱은 좋아하는 매장을 나타내는 지도 항목별로 Marker를 추가하죠 SwiftUI에서는 MapSelection을 사용하여 지도에서 찾은 콘텐츠와 지형지물에 대한 선택을 모두 지원할 수 있습니다 이 한정자를 사용하면 지도 지형지물이 선택되었을 때 장소 카드 콜아웃을 표시할 수 있습니다 SelectionAccessory API를 시작하기에 좋은 방법이죠 기존 앱 코드에서 지도 지형지물에 대해 활성화하면 됩니다 현재 방식대로 앱에서 주석 콘텐츠를 표시할 수 있으며 고객은 지도에 표시된 콘텐츠 근처에 있는 장소에 대해 자세히 알아볼 수 있습니다 이러한 추가 맥락은 상당히 유용할 수 있습니다 이제 Place ID로 장소를 참조하고 장소 카드로 유용한 정보를 표시할 수 있습니다 그런데 어떤 장소를 표시하죠? Place ID 조회 도구로 찾은 특정 장소만 표시하는 것이 아니라면 앱에서 장소를 검색해야 할 수도 있습니다 올해 Search API에 여러 개선 사항이 적용되었는데 검색 결과를 필터링하는 새 방법도 추가되었습니다 이제 더욱더 다양한 장소를 검색할 수 있습니다 콘서트장, 스케이트 파크 심지어 성도요 강, 산맥과 같은 물리적 특징을 검색하거나 도시, 우편번호와 같은 주소의 특정 구성 요소로도 검색할 수 있습니다 특정 경계 내 영역으로 제한된 검색이 지원되므로 나에게 중요한 지역에만 집중할 수 있죠 그리고 Server API의 경우 페이지 나누기가 추가되었습니다 이를 사용하면 결과가 매우 많은 검색도 가능합니다 이러한 새 검색 기능을 사용하면 매장을 더 효율적으로 찾고 수집할 수 있지 않을까요? 물론이죠! 베이 에어리어에서 여러 Apple Store를 찾고 다니다 보면 커피를 마시며 잠시 쉬어야 할 수도 있죠 Jeff가 언급한 새 검색 기능을 웹사이트에서 사용하여 해당 지역의 카페를 찾아서 미리 계획을 세울 수 있겠네요 그다음 네이티브 앱에 동일한 기능을 추가하겠습니다 먼저 쿠퍼티노를 찾아야 합니다 새로운 AddressFilter를 사용하면 되죠 여기에 AddressFilter를 만들어 인근 지역만 검색하도록 할게요 대부분의 국가에서는 도시에 해당하죠 그다음 해당 필터를 새 Search 객체에 추가합니다 마지막으로 Cupertino로 검색을 실행하여 도시를 찾으면 Cupertino's Classy Cleaners처럼 업체명에 Cupertino가 포함된 엉뚱한 결과가 반환되지 않죠 Cupertino와 일치하는 도시에 대한 검색 결과는 제가 설정한 showMap 함수로 전송됩니다 이 함수에서 첫 번째 검색 결과를 가져와 새 지도에 전달할 영역을 만드는 데 사용합니다 이 코드는 지도의 중심을 Cupertino에 둡니다 정확히 의도했던 대로죠 그다음 해당 지역에 대해 Search를 새로 만들어 coffee를 검색합니다 마지막으로 각 coffee 관련 결과에 새 PlaceAnnotation을 추가하죠 이제 모든 결과가 지도에 표시됩니다 그러나 문제가 있습니다 지도를 축소해 보니 초기 뷰포트 외부 지역에 많은 주석이 추가되어 있네요 이렇게 멀리 떨어진 카페에 대한 정보는 필요하지 않습니다 그러므로 RegionPriority로 이러한 정보는 삭제할게요 이 속성 하나만 사용하면 Search로 전달한 지역 내 결과만 사용되도록 할 수 있습니다 변경 사항이 적용되면 페이지의 검색 결과가 원래 지역에 있는 카페로만 제한되죠 자전거로 갈 수 있는 거리에 있는 카페만 표시되죠 이러한 기능은 네이티브 앱에서도 구현할 수 있습니다 동일한 방식으로 앱도 개선할게요 각 카페에 대한 마커를 표시하는 보기를 만들었습니다 비동기식으로 findCity로 도시 지역을 가져온 다음 findCoffee로 해당 지역의 카페를 찾습니다 findCity입니다 JS 코드처럼 addressFilter를 통해 장소를 검색합니다 findCoffee입니다 여기에서는 Cupertino 지역을 가져온 후 해당 지역에 있는 카페만 검색하도록 regionPriority를 사용합니다 좋습니다 이러한 개선 사항 덕분에 저는 최고의 Apple Store 수집가가 될 것입니다 동의해요, Apple Store를 얼마나 많이 수집할 수 있는지 기대되네요 출입국 도장을 수집할 수도 있겠네요
좋습니다 많은 내용을 다루었네요 최신 버전의 MapKit으로 간편하게 Place ID를 통해 장소를 참조하고 장소 카드로 유용한 정보를 보여 주고 웹페이지에 장소를 삽입할 수 있죠 이를 통해 다양한 장소를 검색할 수 있으며 검색을 특정 지역으로 제한할 수도 있습니다 MapKit Server API의 페이지 나누기는 그 어느 때보다 많은 결과를 제공하죠 MapKit JS는 간소화된 토큰 프로비저닝 절차를 제공하므로 토큰 관련 작업을 쉽게 시작할 수 있죠 세션을 마치기 전에 몇 가지 작업을 추천해 드릴게요 Place ID로 토요일 오전에 파머스 마켓이 열리는 공원을 참조해 보세요 장소 카드로 앱에서 장소 정보를 표시해 보세요 장소 카드는 앱의 검색 결과와 사용자가 관심을 갖는 위치에 대한 세부 정보를 제공합니다 지도의 모든 관심 장소에 대해 장소 카드를 활성화하여 앱으로 지역을 탐색하는 사용자에게 유용한 정보를 제공하세요 ‘Place ID로 고유한 위치 식별하기’ 링크를 통해 Place ID를 사용하는 방법을 자세히 알아보세요 MapKit의 새 기능에 대한 이번 세션이 도움이 되었기를 바랍니다 재미있는 지도를 구현하세요 저는 수집을 이어 나가겠습니다
-
-
3:06 - Display a visitor center annotation
// Display a visitor center annotation struct PlaceMapView: View { var placeID: String // "I63802885C8189B2B" @State private var item: MKMapItem? var body: some View { Map { if let item { Marker(item: item) } } .task { guard let identifier = MKMapItem.Identifier( rawValue: placeID ) else { return } let request = MKMapItemRequest( mapItemIdentifier: identifier ) item = try? await request.mapItem } } }
-
3:44 - Display an annotation for the center
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style> #map { margin: 0 auto; } </style> </head> <body> <script crossorigin async src="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js" data-callback="entryPoint" data-token="TODO: Add your token here" ></script> <script> window.entryPoint = () => { const id = "I63802885C8189B2B"; const lookup = new mapkit.PlaceLookup(); lookup.getPlace(id, annotatePlace); }; const annotatePlace = (error, place) => { const center = place.coordinate; const span = new mapkit.CoordinateSpan(0.01, 0.01); const region = new mapkit.CoordinateRegion(center, span); const map = new mapkit.Map("map", { region }); const annotation = new mapkit.PlaceAnnotation(place); map.addAnnotation(annotation); }; </script> <div id="map" style="width: 100dvw; height: 100dvh;"></div> </body> </html>
-
7:32 - Display my favorite apple stores
// Display my favorite apple stores struct VisitedStoresView: View { var visitedStores: [MKMapItem] @State private var selection: MKMapItem? var body: some View { Map(selection: $selection) { ForEach(visitedStores, id: \.self) { store in Marker(item: store) } .mapItemDetailSelectionAccessory() } } }
-
7:50 - Display a selectable annotation
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style> #map { margin: 0 auto; } </style> </head> <body> <script crossorigin async src="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js" data-callback="entryPoint" data-token="TODO: Add your token here" ></script> <script> window.entryPoint = () => { const id = "I63802885C8189B2B"; const lookup = new mapkit.PlaceLookup(); lookup.getPlace(id, annotatePlace); }; const annotatePlace = (error, place) => { const center = place.coordinate; const span = new mapkit.CoordinateSpan(0.01, 0.01); const region = new mapkit.CoordinateRegion(center, span); const map = new mapkit.Map("map", { region }); const annotation = new mapkit.PlaceAnnotation(place); map.addAnnotation(annotation); const accessory = new mapkit.PlaceSelectionAccessory(); annotation.selectionAccessory = accessory; }; </script> <div id="map" style="width: 100dvw; height: 100dvh;"></div> </body> </html>
-
9:15 - List stores and show details when selected
// List stores and show details when selected struct StoreList: View { var stores: [MKMapItem] @State private var selectedStore: MKMapItem? var body: some View { List( stores, id: \.self, selection: $selectedStore ) { Text($0.name ?? "Apple Store") } .mapItemDetailSheet(item: $selectedStore) } }
-
9:37 - Show visitor center details
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style> #map { margin: 0 auto; } </style> </head> <body> <script crossorigin async src="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js" data-callback="entryPoint" data-token="TODO: Add your token here" ></script> <script> window.entryPoint = () => { const id = "I63802885C8189B2B"; const lookup = new mapkit.PlaceLookup(); lookup.getPlace(id, annotatePlace); }; const annotatePlace = (error, place) => { const el = document.getElementById("place"); const detail = new mapkit.PlaceDetail(el, place, { colorScheme: mapkit.PlaceDetail.ColorSchemes.Adaptive }); }; </script> <div id="place"></div> </body> </html>
-
11:17 - Display a place card for the selected map feature, too
// Display a place card for the selected map feature, too struct VisitedStoresView: View { var visitedStores: [MKMapItem] @State private var selection: MapSelection<MKMapItem>? var body: some View { Map(selection: $selection) { ForEach(visitedStores, id: \.self) { store in Marker(item: store) .tag(MapSelection(store)) } .mapItemDetailSelectionAccessory(.callout) } .mapFeatureSelectionAccessory(.callout) } }
-
13:09 - Find Cupertino, then find coffee
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style> #map { margin: 0 auto; } </style> </head> <body> <script crossorigin async src="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js" data-callback="entryPoint" data-token="TODO: Add your token here" ></script> <script> window.entryPoint = () => { const addressFilter = mapkit.AddressFilter.including([ mapkit.AddressCategory.Locality ]); const citySearch = new mapkit.Search({ addressFilter }); citySearch.search("Cupertino", showMap); }; const showMap = (error, cities) => { const center = cities.places[0].coordinate; const span = new mapkit.CoordinateSpan(0.01, 0.01); const region = new mapkit.CoordinateRegion(center, span); const map = new mapkit.Map("map", { region }); const coffeeSearch = new mapkit.Search({ region, regionPriority: mapkit.Search.RegionPriority.Required, pointOfInterestFilter: mapkit.PointOfInterestFilter.including([ mapkit.PointOfInterestCategory.Cafe ]) }); coffeeSearch.search("coffee", (error, results) => { for (const place of results.places) { const marker = new mapkit.PlaceAnnotation(place); map.addAnnotation(marker); } }); }; </script> <div id="map" style="width: 100dvw; height: 100dvh;"></div> </body> </html>
-
14:41 - Finding coffee in Cupertino
// Finding coffee in Cupertino struct CoffeeMap: View { @State private var position: MapCameraPosition = .automatic @State private var coffeeShops: [MKMapItem] = [] var body: some View { Map(position: $position) { ForEach(coffeeShops, id: \.self) { café in Marker(item: cafe) } } .task { guard let cupertino = await findCity() else { return } coffeeShops = await findCoffee(in: cupertino) } } private func findCity() async -> MKMapItem? { let request = MKLocalSearch.Request() request.naturalLanguageQuery = "cupertino" request.addressFilter = MKAddressFilter( including: .locality ) let search = MKLocalSearch(request: request) let response = try? await search.start() return response?.mapItems.first } private func findCoffee(in city: MKMapItem ) async -> [MKMapItem] { let request = MKLocalSearch.Request() request.naturalLanguageQuery = "coffee" let downtown = MKCoordinateRegion( center: city.placemark.coordinate, span: .init( latitudeDelta: 0.01, longitudeDelta: 0.01 ) ) request.region = downtown request.regionPriority = .required let search = MKLocalSearch(request: request) let response = try? await search.start() return response?.mapItems ?? [] } }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.