Highlight
MapKit 在 2025 推出
PlaceDescriptor、把地理编码从 CoreLocation 搬到 MapKit、新增骑行路线,并把 Look Around 带到 MapKit JS 与 watchOS。
核心内容
MapKit 一直有个尴尬的问题。你的地点数据来自 CRM、自家后端、第三方服务,但 MapKit 只认自己去年推出的 Place ID。如果没有 Place ID,你就拿不到 Apple Maps 的富数据——名字、图标、营业时间、地址。开发者只剩两条路:要么先用 MKLocalSearch 做一遍搜索把第三方数据匹配回 MapKit Place ID(结果可能有多条,还得人工挑),要么干脆放弃富数据,自己在地图上画个光秃秃的 Marker。
WWDC25 这一场把这层胶水干掉了。Apple 推出 PlaceDescriptor,放在新框架 GeoToolbox 里。它允许你用坐标、地址或服务标识符(甚至同时提供多种)来描述一个地点,然后交给 MKMapItemRequest 去找到对应的 MKMapItem。同时,CLGeocoder 被废弃,地理编码改用 MKReverseGeocodingRequest 和 MKGeocodingRequest,返回的 MKMapItem 上带着新增的 MKAddress 和 MKAddressRepresentations,地址格式化不再需要自己拼字符串。骑行路线作为新的 transportType 加入,超过 20 个 MapKit API 第一次登陆 watchOS,Look Around 街景登陆 MapKit JS。一次会议覆盖了 Apple Maps 平台跨端化的所有关键拼图。
详细内容
PlaceDescriptor:用你已有的信息找到 Apple Maps 的富数据
最常见的场景:你只有一个坐标和名字,但想拿到 Apple Maps 的富数据。在 SwiftUI Map 里用坐标画 Marker 很简单,但那是个没有 Apple Maps 数据的空 Marker(04:49):
// Putting Marker on the Map with a coordinate
let annaLiviaCoordinates = CLLocationCoordinate2D(
latitude: 53.347673,
longitude: -6.290198
)
var body: some View {
Map {
Marker(
"Anna Livia Fountain",
coordinate: annaLiviaCoordinates
)
}
}
关键点:
CLLocationCoordinate2D只是一个经纬度对,没有任何与 Apple Maps 数据关联的信息。Marker用这个坐标画出来的图钉,名字是你自己传的字符串,没有 Apple Maps 的图标、颜色和点击后的富数据。
PlaceDescriptor 把已有信息打包成结构化描述(05:07):
// 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 GeoToolbox引入新框架,PlaceDescriptor类型在这里定义。representations数组按精确度从高到低排序,可以混合.coordinate、.address、.deviceLocation三种类型。commonName是地点的公开名称(如 Guggenheim Museum),不应该填用户隐私数据(如「妈妈家」),它本身不会帮 MapKit 找到地点,主要用于显示。MKMapItemRequest(placeDescriptor:)把 descriptor 转成请求,try await request.mapItem异步返回单个MKMapItem——与MKLocalSearch不同,这里只返回一个最佳匹配。
如果只有地址也行(05:56):
let address = "121-122 James's St, Dublin 8"
let descriptor = PlaceDescriptor(
representations: [.address(address)],
commonName: "Obelisk Fountain"
)
let request = MKMapItemRequest(placeDescriptor: descriptor)
obeliskFountain = try await request.mapItem
关键点:
.address(_:)用一个完整的邮政地址作为表示,地址越完整匹配越准。- 整个调用形态跟坐标版本一致,差别只在 representation 类型——表明 representations 数组是 PlaceDescriptor 的核心抽象。
跨服务场景下,supportingRepresentations 可以同时挂多家服务的标识符(06:45):
let identifiers = ["com.apple.MapKit" : "ICBB5FD7684CE949"]
let annaLiviaDescriptor = PlaceDescriptor(
representations: [.coordinate(annaLiviaCoordinates)],
commonName: "Anna Livia Fountain",
supportingRepresentations: [.serviceIdentifiers(identifiers)]
)
关键点:
.serviceIdentifiers(_:)接受一个字典,key 是服务的 bundle identifier,value 是该服务给这个地点的 ID。- 如果字典里有
com.apple.MapKit,MKMapItemRequest会优先用它去取数据;失败时自动回退到representations里的坐标或地址。 - 这套机制对 App Intents 特别重要:你给另一个 app 传
PlaceDescriptor时,对方可能并不用 MapKit,但能从字典里找到自己认识的那个 ID。
Geocoding 搬家到 MapKit
CLGeocoder 在 iOS 26 被废弃,CLPlacemark 被软废弃(10:07)。反向地理编码改成(10:45):
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)")
}
}
关键点:
MKReverseGeocodingRequest(location:)的初始化器返回可选值——如果传进无效坐标会直接返回 nil,省掉 runtime 抛错。request.mapItems返回一个数组,文档说绝大多数情况只有一项,取.first即可。- 这里返回的
MKMapItem只包含地址点信息,不带 POI(兴趣点)富数据——不要指望它告诉你这是一家咖啡馆,它只告诉你这是哪条街多少号。
正向地理编码用 MKGeocodingRequest,地址变 MKMapItem 一步到位(13:50):
let request = MKGeocodingRequest(
addressString: "1 Ferry Building, San Francisco"
)
mapItem = try await request?.mapItems.first
返回的 MKMapItem 上的 address: MKAddress? 有 fullAddress 和 shortAddress 两个字符串属性;addressRepresentations: MKAddressRepresentations? 提供更多展示策略,比如 fullAddress(includingRegion: false) 去掉国家、cityWithContext 自动决定补州还是补国家(Los Angeles, California vs. Paris, France)——具体用哪种,MapKit 会综合地址本身和设备 locale 做判断。
骑行路线 + Look Around 跨端化
骑行只需改 transportType(16:06):
let request = MKDirections.Request()
request.source = MKMapItem.forCurrentLocation()
request.destination = selectedItem
request.transportType = .cycling
let directions = MKDirections(request: request)
let response = try await directions.calculate()
returnedRoutes = response.routes
关键点:
.cycling是新的 transport type,跟.walking、.automobile平级。- 骑行路线会利用驾车不可用的小路和绿道,并跳过不适合骑行的道路。
- 同样的请求形态在 MapKit JS 用
mapkit.Directions.Transport.Cycling也能拿到。 - watchOS 26 SDK 新带了 20+ 个 MapKit API,骑行路径终于能在手表上直接算。
Look Around 在 MapKit JS 上的接入(18:10):
const placeLookup = new mapkit.PlaceLookup();
const place = await new Promise(
resolve => placeLookup.getPlace(
"IBE1F65094A7A13B1",
(error, result) => resolve(result)
)
);
const lookAround = new mapkit.LookAround(
document.getElementById("container"),
place,
options
);
关键点:
mapkit.PlaceLookup().getPlace(id, callback)用 Place ID 取 place 对象,回调风格。new mapkit.LookAround(container, place, options)把交互式街景注入指定 DOM 元素。options支持openDialog(加载即全屏)、showsDialogControl(提供进出全屏的按钮)、showsCloseControl(提供关闭按钮)。- 静态预览用
mapkit.LookAroundPreview,不可拖动,点击后弹出全屏交互式视图。
核心启发
-
做什么:把 App 里所有「自己拼坐标 / 地址 + 自己画 Marker」的页面切到 PlaceDescriptor。
- 为什么值得做:你现在的 Marker 不带 Apple Maps 的图标、营业时间、电话、官网链接;用户点开看到的是个空气。换成
MKMapItemRequest(placeDescriptor:)拿到的MKMapItem后再画 Marker,所有这些数据自动出现,外加.mapItemDetailSelectionAccessory(.callout)就能弹出官方 Place Card。 - 怎么开始:找出 app 里所有用
Marker(_:, coordinate:)或Marker(_:, location:)的位置,在数据层加一个把(coordinate, name)转PlaceDescriptor再 resolve 成MKMapItem的方法。先在一个低风险页面试,对比前后用户停留时长。
- 为什么值得做:你现在的 Marker 不带 Apple Maps 的图标、营业时间、电话、官网链接;用户点开看到的是个空气。换成
-
做什么:评估
CLGeocoder->MKReverseGeocodingRequest的迁移,特别是中文地址。- 为什么值得做:
CLGeocoder已废弃,未来某个 iOS 版本会被移除;现在迁移成本可控。但更现实的动机是MKAddressRepresentations比CLPlacemark自己拼字符串清晰得多——比如「列表里同省地址省略省份」这种场景以前要写一堆 if-else,现在.fullAddress(includingRegion: false)一行解决。 - 怎么开始:找一个用户能直接看到地址的页面(订单收货地址、打卡记录),并行跑新旧 API,对比中文地址里省/市/区的顺序与简繁差异。如果差异可接受就推全量。
- 为什么值得做:
-
做什么:骑行路线作为短平快收益加进去。
- 为什么值得做:API 形态跟驾车几乎一样,只改一行
transportType = .cycling,但对骑行用户体验提升明显——骑行路径会走小路、避开不安全路段,估算时间也更准。Apple Watch 上的 MapKit 同样新增了这一能力,骑行场景下看手表比掏手机自然。 - 怎么开始:在现有路线规划界面加一个 Cycling tab;watchOS 26 上做一个独立的小 widget 显示「下一段骑行的距离 + ETA」。
- 为什么值得做:API 形态跟驾车几乎一样,只改一行
-
做什么:MapKit JS Look Around 替换 iframe 嵌入的 Google Street View。
- 为什么值得做:房产、旅游、餐饮 web 项目长期被 Street View 锁定,UI 风格和品牌不匹配。Look Around 提供 360 度交互视图,支持
openDialog等可定制 options,事件回调允许接入自家加载动画和错误提示。 - 怎么开始:先用
mapkit.LookAroundPreview在房源卡片上做静态预览;点击后再切到全屏LookAround。监听error事件准备好回退 UI(很多地区还没有 Look Around 覆盖)。
- 为什么值得做:房产、旅游、餐饮 web 项目长期被 Street View 锁定,UI 风格和品牌不匹配。Look Around 提供 360 度交互视图,支持
关联 Session
- What’s new in MapKit — MapKit 在 iOS 26 的全部更新一览,包括 PlaceDescriptor、Geocoding、骑行路线的完整列表。
- What’s new in watchOS — watchOS 26 新增 20+ 个 MapKit API,骑行路线和地图导航第一次在手表上原生可用。
- What’s new in watchOS 26 — 围绕 watchOS 26 的开发者视角更新,包含地图、健身与运动场景。
- What’s new in Wallet — Wallet 与位置/场所交互的更新,跟 MapKit Place Card 的统一 URL 方案配合使用。
评论
GitHub Issues · utterances