WWDC Quick Look 💓 By SwiftGGTeam
What's new in MapKit

What's new in MapKit

元の動画を見る

Highlight

MapKit は iOS 26 で PlaceDescriptor、統一された MKGeocodingRequest / MKReverseGeocodingRequest、自転車経路用の transportType、そして MapKit JS の Look Around ビューを導入しました。


主要内容

多くの App の地図体験には共通の課題があります。手元には住所の文字列か緯度経度の組しか持っていないのに、Apple Maps のようなリッチな店舗データを取得できない、という問題です。これまでは情報量の乏しいアノテーションを自前で組み立てるか、MKLocalSearch で候補を引いてから絞り込むしかなく、CRM の同期、App Intents 間での値の受け渡し、プロセスをまたいで特定の地点を参照するようなケースでは扱いが煩雑でした。

今年の MapKit には PlaceDescriptor が追加され、新しい GeoToolbox フレームワークに収められています。これは commonName、住所、座標、デバイスの位置情報をひとつの構造化された参照としてまとめ、MKMapItemRequest に渡すと完全な MKMapItem に解決してくれる、という仕組みです。解決された MapItem は Place ID 経由で取得したものと同等で、公式の名称、アイコン、営業時間をそのまま表示でき、Place Card にもそのまま接続できます。

ジオコーディングの入り口も今回統合されました。MKGeocodingRequest(住所 → 座標)と MKReverseGeocodingRequest(座標 → 住所)が、MapKit のコンテキストにおける CLGeocoder の役割を引き継ぎます。経路 API には transportType = .cycling が追加され、自転車経路がはじめてファーストクラスの存在になりました。MapKit JS 側でも Look Around のインタラクティブビューとイベントコールバックが揃い、Web ページに 3D ストリートビューを直接埋め込めるようになっています。


詳細

PlaceDescriptor の最小構成は、representation ひとつと commonName ひとつだけで作れます。

// Creating and resolving a PlaceDescriptor with coordinate PlaceRepresentation

import GeoToolbox
import MapKit

let annaLiviaCoordinates = CLLocationCoordinate2D(
    latitude: 53.347673,
    longitude: -6.290198
)
let annaLiviaDescriptor =  PlaceDescriptor(
    representations: [.coordinate(annaLiviaCoordinates)],
    commonName: "Anna Livia Fountain"
)

let request = MKMapItemRequest(placeDescriptor: annaLiviaDescriptor)
do {
    annaLiviaMapItem = try await request.mapItem
} catch {
    print("Error resolving placeDescriptor: \(error)")
}

ポイントは以下のとおりです。

  • import GeoToolboxPlaceDescriptor は MapKit 本体には入っておらず、新フレームワークを別途 import する必要があります。
  • representations: [.coordinate(...)]:representations 配列は精度の高い順に並べます。ここでは座標ひとつだけです。
  • commonName:Sydney Opera House のような公に知られた名称を渡します。「ママの家」のようなプライベートな別名は解決の役には立ちません。
  • MKMapItemRequest(placeDescriptor:):Apple Maps のバックエンドに非同期でリクエストを投げ、descriptor を MKMapItem に解決します。
  • try await request.mapItem:失敗時は throw されるため、do/catch でフォールバックを用意しておきます。

元データが座標ではなく住所の場合は、representation を .address に差し替えます(05:56)。

// Creating and resolving a PlaceDescriptor with address PlaceRepresentation

import GeoToolbox
import MapKit

let address = "121-122 James's St, Dublin 8"
let descriptor =  PlaceDescriptor(
    representations: [.address(address)],
    commonName: "Obelisk Fountain"
)

let request = MKMapItemRequest(placeDescriptor: descriptor)
do {
    obeliskFountain = try await request.mapItem
} catch {
    print("Error resolving placeDescriptor: \(error)")
}

ポイントは以下のとおりです。

  • .address(address):番地、市区町村、郵便番号までできるだけ完全な住所文字列を渡したほうが、ヒット率が上がります。
  • representations 配列の順序は重要です。座標が住所から逆算したものなのであれば、address を先頭に置くべきです。
  • 解決ロジックは MapKit のバックエンド側で決まるため、呼び出し側は記述(descriptor)を渡すだけで済みます。

App をまたいで地点を受け渡すケース(App Intents など)では、supportingRepresentations に複数のサービスの ID をまとめて入れておけます(06:45)。

// Creating a PlaceDescriptor with identifiers

import GeoToolbox

let annaLiviaCoordinates = CLLocationCoordinate2D(
    latitude: 53.347673,
    longitude: -6.290198
)
let identifiers = ["com.apple.MapKit" : "ICBB5FD7684CE949"]
let annaLiviaDescriptor =  PlaceDescriptor(
    representations: [.coordinate(annaLiviaCoordinates)],
    commonName: "Anna Livia Fountain",
    supportingRepresentations: [.serviceIdentifiers(identifiers)]
)

ポイントは以下のとおりです。

  • serviceIdentifiers は辞書型です。key には地図サービスの bundle id(com.apple.MapKit)、value にはそのサービス上の place id を入れます。
  • MapKit の identifier があれば、MKMapItemRequest はそれを優先的に利用します。解決に失敗した場合は座標や住所の representation にフォールバックします。
  • 複数サービスの id を並べて格納できるので、受け取り側は自分が利用している SDK に対応する値を取り出せます。これが PlaceDescriptor を App Intents のパラメータに使うのに向いている理由です。

自転車経路は、既存の MKDirections.RequesttransportType を一行足すだけで取得できます(16:06)。

// Fetch a cycling route

let request = MKDirections.Request()
request.source = MKMapItem.forCurrentLocation()
request.destination = selectedItem
request.transportType = .cycling
let directions = MKDirections(request: request)
do {
    let response = try await directions.calculate()
    returnedRoutes = response.routes
} catch {
    print("Error calculating directions: \(error)")
}

ポイントは以下のとおりです。

  • transportType = .cycling:今年追加された enum 値です。これまでは walking / automobile / transit のみでした。
  • MKMapItem.forCurrentLocation():source として現在地を使う場合は、座標を組み立てる必要はありません。
  • directions.calculate() は引き続き async / throws のインターフェースです。
  • 返ってくる response.routes は、SwiftUI の Map 上で MapPolyline と組み合わせてそのまま描画できます。

逆ジオコーディングは MKReverseGeocodingRequestCLGeocoder を置き換える形になります(10:45)。

// Reverse geocode with MapKit

import MapKit

let millCreekCoordinates = CLLocation(latitude: 39.042617, longitude: -94.587526)
if let request = MKReverseGeocodingRequest(location: millCreekCoordinates) {
    do {
        let mapItems = try await request.mapItems
        millCreekMapItem = mapItems.first
    } catch {
        print("Error reverse geocoding location: \(error)")
    }
}

ポイントは以下のとおりです。

  • イニシャライザは optional を返します。if let でアンラップに失敗する場合は、入力の座標が不正だということになります。
  • request.mapItemsMKMapItem の配列を直接返してくれるため、CLPlacemark から MKMapItem への二段変換が不要です。
  • 先頭要素が最良一致になることが多いものの、信頼度の判定は業務要件にあわせて行う必要があります。

重要ポイント

  1. 既存の CRM や Excel の住所データを PlaceDescriptor に流し込む:多くの App のバックエンドには名称と住所しかなく、これまで Apple Maps スタイルのアノテーションを地図上に出すことができませんでした。なぜやる価値があるのか:リリースすれば、ユーザーは App 内で公式の営業時間・電話番号・Place Card を見られるようになります。どう始めるか:CLGeocoder.geocodeAddressStringPlaceDescriptor(representations: [.address(...)], commonName:) + MKMapItemRequest に置き換えるだけで、データインポート全体を一箇所の変更でカバーできます。

  2. 自転車向け App に transportType = .cycling を組み込む:これまでは徒歩経路で代用するか、サードパーティの自転車経路 API をつなぐしかありませんでした。なぜやる価値があるのか:Apple Maps の自転車データは標高、勾配、自転車道の優先度までカバーしていて、ネイティブで完結した体験になります。どう始めるか:既存の MKDirections.Request のコードに request.transportType = .cycling を一行追加し、まず経路品質を検証してから、ユーザーにモード切り替えとして公開するかを判断します。

  3. App Intents の入力に PlaceDescriptor を使う:App をまたいで CLLocation を渡すと、店舗名や ID といった意味情報が失われます。なぜやる価値があるのか:Shortcuts や Siri から「近くの X 店」のようなパラメータを、安定して自分の App に渡せるようになります。どう始めるか:既存の IntentParameter の location フィールドを PlaceDescriptor に差し替え、supportingRepresentations に自社サービスの ID を併せて格納しておきます。

  4. MapKit JS で Look Around ビューを埋め込む:Web 側はこれまで 2D 地図しか出せず、ストリートビューはサードパーティに飛ばすしかありませんでした。なぜやる価値があるのか:観光・不動産系のサイトが詳細ページに Apple の 3D ストリートビューを直接表示できるようになり、滞在時間の伸びが期待できます。どう始めるか:mapkit.PlaceLookup で Place を取得したあと、mapkit.LookAround(container, place, options) を組み立てます。最初は LookAroundPreview でサムネイルを置き、クリックで本体を展開する構成にすると扱いやすいです。

  5. 古い CLGeocoder の呼び出しを MKGeocodingRequest / MKReverseGeocodingRequest にまとめて書き換える:旧 API は CLPlacemark を返すため、MKMapItem への変換がもう一段必要になります。なぜやる価値があるのか:変換層がひとつ減り、エラーポイントもひとつ減ります。どう始めるか:コードベース内の CLGeocoder() の呼び出し箇所を grep し、住所 → MKGeocodingRequest、座標 → MKReverseGeocodingRequest で置換します。イニシャライザが optional を返す点に注意してください。


関連 Session

  • Go further with MapKit — 同テーマの完全版 session。PlaceDescriptor、自転車経路、Look Around、統一された地図 URL までを一通りカバーします。
  • Get to know App Intents — App Intents フレームワークの基礎。PlaceDescriptor は地点パラメータの推奨型として位置付けられています。
  • What’s new in SwiftUI — SwiftUI の Map ビューと MapContentBuilder の最新アップデート。
  • Develop for Shortcuts and Spotlight with App IntentsPlaceDescriptor を Intent パラメータとして Shortcuts と Spotlight に公開する方法。

コメント

GitHub Issues · utterances