View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

打开菜单 关闭菜单
  • 专题
  • 相关主题
  • 所有视频
  • 关于

返回 WWDC25

  • 简介
  • 概要
  • 转写文稿
  • 代码
  • 深入探索 MapKit

    了解 MapKit 和 MapKit JS 的最新更新。我们将介绍一种新的路线类型——骑行路线,并向你展示如何在网页上启用 3D 环视图像。了解新的 Geocoding API 如何支持坐标与地址之间的转换,以及如何使用 Address Representations API 来获取某一区域最恰当的地址。最后,我们将介绍一种新的地点引用方式,确保你的 App 能与 App Intents 无缝协作。

    章节

    • 0:00 - 简介
    • 0:45 - 查找地点
    • 9:34 - 显示地点
    • 14:14 - 畅行四方

    资源

    • Adopting unified Maps URLs
    • Place ID Lookup
    • Searching, displaying, and navigating to places
      • 高清视频
      • 标清视频

    相关视频

    WWDC24

    • 使用 MapKit 充分优化位置相关功能

    WWDC23

    • 认识 SwiftUI 版 MapKit

    WWDC22

    • MapKit 的新功能
  • 搜索此视频…

    大家好 我叫 Alex 是 MapKit 团队的一名工程师 借助 Apple 地图 你可以 从自己的设备上导航和探索 世界各地的不同地点 这里有很多值得探索的地方 从历史地标到舒适的咖啡馆、 当地商店和绝佳的徒步路线 今天我将介绍 MapKit 和 MapKit JS 的更新 这些更新可让你将地图世界 带入你的 App 和网站 我将先介绍 PlaceDescriptor 这是一种查找和引用地点的新方法 然后我将介绍地理编码 以及如何使用它 来展示关于某个地点的信息 最后 我将演示如何通过 Directions 和 Look Around API 将用户带到要去的地方 我将从查找和引用地点开始 去年 我们推出了一种 用来引用地点的标识符 适用于 MapKit 框架中 由地图项表示的地点 以及 MapKit JS 中 由地点对象表示的地点 引用是唯一的 而且能够 随时间推移保持有效状态 每当地图团队更新某个地点的数据 例如网站 URL 使用地点 ID 的 App 就能显示这些更新信息 由于这些标识符是唯一的 因此 App 可以用它们 作为自身数据结构中的键 标识符可以持久保存和共享 Apple 会持续追踪数据 而你可以随时引用这些数据 如果你想持久引用 通过 MapKit 找到的特定地点 地点标识符仍然是最佳选择 但在某些情况下 它可能并非最合适的 有时即使没有标识符 你仍会希望 能够找到特定地点的 MapKit 丰富数据 例如 如果你有一个 Web API 或 CRM 可以为你提供 所有营业地点的名称和地址 或者比如你有 特定地点的名称和坐标 但你想获得确切的单个地址 那么会返回多个结果的 API 如 Local Search 就不是最佳选择 还有些时候 我想将地点引用 添加到非自有代码中 或从非自有代码传出 或许我想提供来自框架的地点 或当我使用 App Intents 时 我可能想接收某个地点 作为意图参数、 返回某个地点作为意图结果 或将地点作为属性 添加到我的 App 实体上 在这些情况下 你进行交互的那些 App 可能 根本不使用 MapKit 我可以传递像 CLLocation 这样的纯地理表示 但却无法通过这种方式 像使用 MapKit 标识符那样 找到丰富的兴趣点数据 为了解决这些情况 我们引入了一个新类型: PlaceDescriptor 它位于新的 GeoToolbox 框架中 PlaceDescriptor 允许你提供 以结构化方式描述地点的信息

    然后 MapKit 或其他地图服务提供商 就可以使用 PlaceDescriptor 来尝试查找有关这个地点的丰富数据 PlaceDescriptor 包含三种顶层信息: 一个名为 commonName 的字符串 在构建 PlaceDescriptor 时 你应该提供众所周知的名称 例如古根海姆博物馆或悉尼歌剧院 这个字段不适用于隐私数据 例如“妈妈家” 添加隐私数据无法帮助 MapKit 找到你的地点

    PlaceDescriptor 还包含 representations 数组 这些表示采用常见格式 任一款处理地理信息的 App 或 框架应该都能理解 其中有三种类型的 PlaceRepresentation 可供选择 第一个是 address 字符串 就像你写在信封上的地址那样 提供的地址信息越详尽 MapKit 找到你的地点的 可靠性就越高 第二个是 coordinate 表示那些位置固定且明确的地点 比如一个已知的地标或营业地点 最后是 deviceLocation 可接受 CLLocation 类型的对象 这适用于处理接收到的 GPS 数据 并且可能包含额外信息 如精确度、时间戳、方向或速度 representations 数组 必须至少包含一个表示 并且按优先级降序排列 例如 如果 PlaceDescriptor 来自通讯录应用程序 坐标可能来自这个地点的地址 在这种情况下 地址会显示在最前面 因为它是原始信息来源 坐标将随后显示 最后 PlaceDescriptor 包含 supportingRepresentations 数组 这些表示可能 并非对所有应用程序都可用 而且也不是必需的 supportingRepresentations 数组可以为空 稍后 我会详细讨论可将哪些信息 添加到 supportingRepresentations 为了演示 PlaceDescriptor 以及即将推出的所有其他新 API 我将为大家演示一个示例 App 这款 App 旨在帮助喷泉迷们查找 世界各个角落的喷泉 我想先收集都柏林的一些 值得参观的喷泉 并将它们标注在地图上

    自从 SwiftUI 版 MapKit 推出以来 我已经可以在地图上用坐标 创建一个简单标记 但我希望这款 App 能够 结合所有其他 MapKit API 充分利用 Apple 地图 为这些喷泉提供的丰富数据 虽然我没有地点 ID 这就是使用 PlaceDescriptor 的绝佳机会 让我们创建一个 PlaceDescriptor 来引用这个喷泉 首先导入 GeoToolbox 我知道在这个坐标处有一个喷泉 因此在我创建 PlaceDescriptor 时 我将一并提供坐标表示 最后 我知道这个喷泉叫 Anna Livia Fountain 我也会提供这个名称 这就是创建有效的 PlaceDescriptor 需要执行的全部操作 然后我可以导入 MapKit 并使用我的 PlaceDescriptor 创建地图项请求 创建好请求后 我可以执行它 来获取这个地点的 MKMapItem 地图项是 MapKit 中的地点的 核心类型 我可以将它与各种 API 搭配使用

    例如 接下来我可以在地图上 使用地图项 你会注意到标记显示了名称、颜色 和 Apple 地图 为这个地点提供的图标

    让我们在地图上添加第二个地点 这次改为使用地址来创建我的描述符 我只需要提供就我所知 这个喷泉最完整的地址版本 然后我可以用这个地址和温泉的名称 创建 PlaceDescriptor 我按照之前的操作使用 MKMapItemRequest 然后将它和我的另一个喷泉 添加到地图上 就是这么简单 我已经展示了 PlaceDescriptor 的强大功能 通过名称 以及坐标和地址 PlaceRepresentation 查找地点 但还有一个 PlaceDescriptor 顶层属性可供你使用 这是一种补充表示方式: serviceIdentifiers serviceIdentifier 表示是一个词典 其中的键是给定地图服务的 套装标识符 值是这个地图服务用来 表示你的地点的标识符

    例如 如果我知道 某个地点的 MapKit 地点标识符 我可以创建一个词典 其中键是 com.apple.MapKit 值就是这个标识符 然后我创建一个 serviceIdentifiers 表示 并将这个表示传递给 PlaceDescriptor 构造器的 supportingRepresentations 参数 如果我从其他地图服务提供商处 得知了某个地点的标识符 我可以在这里提供 MapKit 并不会使用其他标识符 但提供这些标识符在 App Intents 等场景中非常有用 你可以将 PlaceDescriptor 提供给 另一个可能不使用 MapKit 的 App 你可以根据需要 提供任意数量的标识符 如果你使用的是 MapKit API 我们始终会正确处理 serviceIdentifiers 如果存在 MapKit 标识符 MKMapItemRequest 将使用它 从你的 PlaceDescriptor 获取地点信息 如果没有 MapKit 标识符 或者如果因任何原因 导致无法使用提供的标识符 则会使用 PlaceDescriptor 上的 其他表示来查找你的地点 同样 如果使用通过其他方式获得的 地图项创建 PlaceDescriptor 我们将确保 PlaceDescriptor 填充了 你需要的所有表示 包括标识符 我将使用 PlaceDescriptor 和 MKMapItemRequest 将我知道的其余都柏林喷泉 添加到 App 中 用 PlaceDescriptor 请求的地图项 可结合我们所有的 MapKit API 使用 以显示丰富的地图数据 就像通过标识符或 MKLocalSearch 获取的数据一样

    例如地点卡 为 PlaceDescriptor 请求的地点 显示地点卡时 我们可以显示最新的丰富数据 比如营业时间 以及指向 Apple 地图的链接 只需一行代码 当用户在我的 App 中选择喷泉时 我就能显示地点卡 地点卡可以在你的 App 中 轻松显示某个地点的 大量相关信息 请观看 WWDC 2024 讲座“使用 MapKit 充分优化位置相关功能” 进一步了解

    说到地点卡 今年 MapKit JS 中的地点卡 也提供指向 Apple 地图的通用链接 在安装了“地图”App 的设备上 链接会在“地图”中打开 对于没有安装“地图”App 的设备 地点卡会链接到 maps.apple.com 去年夏天 我们推出了 这个网站的公开 Beta 版 现在 当你的 App 和网站 链接到 Apple 地图时 即使非 Apple 平台上的用户也可以 用网页版“地图”进一步探索 iOS 18.4 推出后 我们更新了 “地图”处理 URL 的方式 让你可以放心创建类似的通用链接 例如这个用于执行搜索的 URL 我们让参数变得更一致、 更简单、更易于读取

    我们还添加了许多其他参数 以链接到“地图”App 中的更多功能 请务必观看视频相关材料中 提供了链接的 “采用统一的地图 URL” 这样你就能在自己的 App 中 采用通用地图链接

    我已经找到了我的地点 接下来 我将向大家展示如何使用 地理编码和地址表示 在 App 中显示更多 关于地点的信息

    如果你还不熟悉 正向地理编码是指 获取地址并找到 它所引用的坐标的过程 举例来说 轻点“通讯录”App 中的某个地址 可以跳转到某个地图

    反向地理编码则相反 是由你提供坐标 而我们给你一个地址 例如当你在“地图”App 中 放置图钉时 我们会显示这个地点的地址信息

    在 iOS 18 及更早版本中 你会使用 CoreLocation 来执行地理编码任务 今年 我们将弃用 CLGeocoder、 软弃用 CLPlacemark 并将地理编码引入 MapKit

    在我的 App 中 我还希望记录我已找到 并拍摄了出色构图美照的喷泉 这些照片包含地理标记 其中有拍摄照片的坐标 但我没有任何补充信息 比如名称 这意味着我无法使用 PlaceDescriptor 查找丰富地点数据 我只有坐标 因此我将在 MapKit 中 使用反向地理编码 来查找更多背景信息 并显示在我的照片旁边

    让我们对我的第一张喷泉照片 进行反向地理编码

    我会先输入所拍照片的坐标 然后使用这个位置发出 MKReverseGeocodingRequest 请求 不同于我之前展示的 使用 PlaceDescriptor 发出的 MKMapItemRequest MKReverseGeocodingRequest 的 构造器会返回一个可选值 如果你提供的 CLLocation 的 坐标无效 MapKit 将无法为你执行请求 当请求返回时 我得到一个地图项数组 对于大多数地理编码请求 这个数组应仅包含一个条目 所以我选择第一个 请注意 由于这个地图项来自 Geocoding API 它不会包含兴趣点的丰富信息 这个地图项仅包含 这个地址点的相关信息 获得了地图项后 可以显示地址了

    我将使用 MKReverseGeocodingRequest 以获取其余照片的地址 并以列表形式展示 我的 App 已初具雏形了 但我感觉在这个界面 显示完整地址可能过于冗余了 所以我会看看其他可选项 MKMapItem 提供了 两个处理地址信息的可选属性

    首先是 MKAddress 当你创建自己的 MKMapItem 时 可以实例化你的 MKAddress 在从 Geocoding、Local Search 和 PlaceDescriptor Resolution 等 API 返回 MapItem 时 MapKit 还会提供一个 MKAddress 其次是 MKAddressRepresentations 它没有构造器 地址表达仅适用于从 MapKit API 返回的地图项

    我先介绍 MKAddress 它有两个字符串属性 fullAddress 和 shortAddress

    fullAddress 是我们提供的 邮政地址或行政地址的最完整版本 而 shortAddress 只提供 最重要的部分

    在某些情况下 我们提供的地址可能非常简短 例如 海洋中坐标的 反向地理编码可能只有一行

    当你实例化自己的地图项时 地址属性会用于 MapKit 地点卡中 以便你显示自定地址信息

    虽然 MKAddress 提供 地址的简单版本 MKAddressRepresentations 提供了 许多在 App 中 显示地址信息的强大方式 例如 如果你想显示完整地址列表 但这些地址都在同一国家/地区 你可能需要 在 App 用户界面中省略地区 为此 你可以使用完整地址 将 includingRegion 设为 false 或者你也许想列出城市 以及关于城市所在地区的 一些额外背景信息 有时 你想提供一个州或省 比如加利福尼亚州的洛杉矶 而有时 你会希望添加国家/地区 如法国巴黎 MapKit 大大简化了这一过程 因为它能够根据提供的地址以及 地图项请求设备的语言与地区信息 匹配最适合的选项 深入了解我的 App 可用的不同地址表示之后 我将选择“cityWithContext” 让照片附带的地址信息 更加简洁 现在 App 展示信息的详细程度 恰到好处 视觉效果也很棒

    用于正向地理编码的 API 与反向地理编码非常相似 使用 MKGeocodingRequest 我可以 返回一个地图项 这次是针对地址的 这使得访问坐标或将它添加到地图 变得非常容易 它还包括我们刚讨论的 所有地址信息选项 这样 我就可以获得 在发出地理编码请求之前 无法获取的多种地址显示表示

    现在我已经找到了我的地点 并显示了关于这些地点的一些信息 接下来我将向大家展示 MapKit API 来帮助你导航到地点 MapKit 提供了 Directions API 可以查找 通过步行或驾车等多种交通方式 往返于出发地与目的地之间的路线 Directions 会提供 估算的行程时长和距离以及 详细的逐步导航信息

    回到我的都柏林地图视图 我想规划一下 前往精选喷泉的路线 我将通过在 Maps 构造器中 提供地图项绑定 在我的地图中启用选择 这样 当所选项发生变化时 我可以计算我的路线 有关如何处理地图选择的更多信息 请观看 WWDC 2023 的 “认识 SwiftUI 版 MapKit” 要获取我的路线 我首先要创建一个路线请求 然后将设备的当前位置 设置为出发地 并将所选地图项设置为目的地 接下来创建一个 directions 对象 最后计算路线 我会确保处理任何错误 然后会处理响应 但路线请求的响应中有哪些内容?

    我们会返回为你的路线 匹配的出发地和目的地 返回信息可能 与你在请求中提供的略有不同 例如 驾车路线可能会考虑停车地点 而步行路线可能会 将你直接带到建筑物门口

    我们还包含一个数组 其中包含 一条或多条满足你请求的路线

    路线包含许多有用的信息 包括可用作路线标题的本地化名称、 道路封闭等一系列沿途路况通知、 以米为单位的行程距离、 这条路线的预计用时 以及可在地图上绘制的路线几何形状

    很高兴告诉大家 今年我们为 MapKit 添加了 对骑行路线指引的支持 对于我的 App 而言 骑行是观赏都柏林喷泉的绝佳方式 只需在我的路线请求中 修改一个属性即可实现 我想为我的路线显示一条 可能的骑行路线 我将采用响应的第一条路线 然后使用 MapPolyline 将它添加到地图中 显示骑行路线指引就是这么简单

    MapKit 的骑行路线功能非常强大 这项功能会利用 驾车时无法通行的小径和小道 并忽略某些不适合骑自行车的道路 你还可以使用 MapKit JS 获取 骑行路线指引和预计到达时间 就像使用 Swift 一样 我只需在现有路线请求中 添加一行配置 将骑行指定为交通类型

    我还很高兴告诉大家 有史以来第一次 你可将 MapKit 的路线指引功能 带到自己的 watchOS App 了! 实际上 随着最新 watchOS SDK 推出 Apple Watch 上现已支持 超过 20 个 MapKit API

    现在我已经为我的喷泉之旅 规划了一条不错的骑行路线 如果能在出发前探探路 骑行时我就会感到更踏实了 通过启用“地图”的四处看看功能 我可以获得城市的 360 度交互式街景图 并能轻松预览道路、 自行车道、停车场和地标

    我们在 iOS 16 中将“四处看看” 引入了 MapKit App 包括用于查看图像 是否位于给定位置、 预览四处看看图像和全屏显示的 API 要了解详情 请观看 WWDC22 讲座 “MapKit 的新功能”

    今年我们在 MapKit JS 中引入 “四处看看”功能 以便你在自己的网站 或网页端应用程序中启用它 你可以添加两种类型的 “四处看看”视图

    首先是交互式“四处看看” 通过这个视图 你能在自己的 UI 中 嵌入用户可浏览的环视视图 其次是“四处看看”预览 这种视图会提供 所需位置图像的静态快照 点按预览会启动全屏交互式体验 要向网站添加交互式“四处看看” 我需要先添加 place 对象 我可以使用任何能够返回地点的 MapKit JS API 例如 PlaceLookup Search 或 Geocoding 在这个示例中 我有一个标识符 因此我将使用 PlaceLookup 然后我会创建 lookAround 对象 传入包含的 DOM 元素 以及 place 对象 最后是 options 词典 “四处看看”视图支持三个选项 第一个是 openDialog 如果这个选项为 true “四处看看”视图将覆盖 整个浏览器窗口 第二个是 showsDialogControl 如果为 true 则“四处看看”视图中 会显示一个按钮 允许你进入和退出全屏窗口体验 最后是 showsCloseControl 如果为 true 则会添加一个按钮 用于关闭“四处看看”视图 MapKit JS 会发送与 “四处看看”视图相关的各种事件 你可以添加事件侦听器 来响应或覆盖默认行为 例如 当用户轻点关闭按钮时 将发送 close 事件 你可以使用这个回调来执行动画 或在 App 中有意义的状态更改

    如果不取消这个事件的默认操作 lookAround 视图会从 DOM 中删除 你可能需要处理的其他事件包括: 视图完全载入时 发送的 load 事件 出现问题时发送的 error 事件 例如 当图像不可用时 或当浏览器无法显示视图时 MapKit JS 提供了一个错误 UI 但你可能希望自定错误或回退体验 最后 lookAround 还会发送 readystatechange 事件 你可将它用于监控视图的生命周期 readyState 会随着视图载入、 完成加载、出现错误 或从 DOM 中删除而发生变化 除了“四处看看”视图 你可以用 LookAroundPreview API 来实现更简洁的体验 “四处看看”预览不是交互式的 用户无法平移视图 点按“四处看看预览”会启动 全屏窗口环视体验 适用于 MapKit JS 的“四处看看” 定会将你的网站 提升到全新境界 以上就是本次讲座的全部内容 这可真是一次“知识的喷涌”! 我向你展示了如何使用 MapKit 和 MapKit JS 查找地点、显示地点信息 和导航到世界各地的地点

    结束之前 我给大家布置一些作业 使用 PlaceDescriptor 查找 具有和不具有标识符的地点 并将地点引用发送到其他 App 更新指向 Apple 地图的所有链接 以使用新的统一 URL 格式

    将 App 从 CoreLocation 迁移到 MapKit API 以进行地理编码 并利用我们出色的地址表示 最后 将骑行路线指引和 “四处看看”添加到你的 App 中 帮助用户去到要去的地方

    感谢大家今天抽出时间 了解 MapKit!

    • 4:49 - Putting Marker on the Map with a coordinate

      // 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
              )
          }
      }
    • 5:07 - Creating and resolving a PlaceDescriptor with coordinate PlaceRepresentation

      // 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)")
      }
    • 5:56 - Creating and resolving a PlaceDescriptor with address PlaceRepresentation

      // 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)")
      }
    • 6:45 - Creating a PlaceDescriptor with identifiers

      // 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)]
      )
    • 7:28 - Fetching a MapItem from a PlaceDescriptor

      // Fetching a MapItem from a PlaceDescriptor
      
      let request = MKMapItemRequest(placeDescriptor: descriptor)
      let mapitem = try await request.mapItem
    • 7:43 - Getting a PlaceDescriptor from a MapItem

      // Getting a PlaceDescriptor from a MapItem
      
      let descriptor = PlaceDescriptor(mapItem: mapitem)
    • 8:10 - Place Card

      // Place Card
      
      var body: some View {
          Map {
              ForEach(fountains, id:\.name) { fountain in
                  Marker(item: fountain)
                      .mapItemDetailSelectionAccessory(.callout)
              }
          }
      }
    • 10:45 - Reverse geocode with MapKit

      // 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)")
          }
      }
    • 13:50 - Forward geocoding with MapKit

      // Forward geocoding with MapKit
      
      var body: some View {
          Map {
              if let mapItem {
                  Marker(item: mapItem)
              }
          }
          .task {
              let request = MKGeocodingRequest(
                  addressString: "1 Ferry Building, San Francisco"
              )
              do {
                  mapItem = try await request?.mapItems.first
              } catch {
                  print("Error geocoding location: \(error)")
              }
          }
      }
    • 14:38 - Allowing Map Selection

      // Allowing Map Selection
      
      @State var selectedItem: MKMapItem?
      
      var body: some View {
          Map(selection: $selectedItem) {
             UserAnnotation()
             ForEach(fountains, id: \.self) { item in
                Marker(item: item)
             }
          }
          .onChange(of: selectedItem) {
             // Compute Route
          }
      }
    • 15:00 - Fetch a route

      // Fetch a route
      
      let request = MKDirections.Request()
      request.source = MKMapItem.forCurrentLocation()
      request.destination = selectedItem
      let directions = MKDirections(request: request)
      do {
          let response = try await directions.calculate()
          returnedRoutes = response.routes
      } catch {
          print("Error calculating directions: \(error)")
      }
    • 16:06 - Fetch a cycling route

      // 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)")
      }
    • 16:25 - Display a route on the Map

      // Display a route on the Map
      
      Map {
          if let mapRoute {
              UserAnnotation()
              MapPolyline(mapRoute)
                  .stroke(Color.blue, lineWidth: 5)
          }
      }
    • 16:40 - Cycling directions in MapKit JS

      // Cycling directions in MapKit JS
      
      let directions = new mapkit.Directions();
      directions.route ({
          origin: safariPlayground,
          destination: cherryHillFountain,
          transportType: mapkit.Directions.Transport.Cycling
      }, (error, { routes: [{ polyline }] }) => {
          polyline.style.lineWidth = 5;
          map.showItems([
              new mapkit.PlaceAnnotation(place),
              new mapkit.PlaceAnnotation(
                place2,
                { selected: true }
              ),
              polyline
          ]);
      });
    • 17:26 - Look Around

      // Look Around
      
      var body: some View {
          Map {
              ForEach(fountains, id:\.name) { fountain in
                  Marker(item: fountain)
             }
          }
          .overlay(alignment: .bottomLeading) {
              if (lookAroundScene != nil) {
                  LookAroundPreview(scene: $lookAroundScene)
                      .frame(width: 230, height: 140)
                      .cornerRadius(10)
                      .padding(8)
              }
          }
      }
    • 18:10 - Look Around View in MapKit JS

      // Look Around View in MapKit JS
      
      const placeLookup = new mapkit.PlaceLookup();
      const place = await new Promise(
          resolve => placeLookup.getPlace(
              "IBE1F65094A7A13B1",
              (error, result) => resolve(result)
          )
      );
      
      // Create an interactive look around view.
      const lookAround = new mapkit.LookAround(
          document.getElementById("container"),
          place,
          options
      );
    • 18:35 - Look Around Options

      // Look Around Options for MapKit JS
      
      const options = {
          // Enters a full window experience
          // immediately on load
          openDialog: true,
          
          // Provides a button to enter and
          // exit full window.
          showsDialogControl: true,
          
          // Provides a button to destroy
          // the look around view.
          showsCloseControl: true,
      };
    • 19:10 - Handle MapKit JS Look Around events

      // Handle MapKit JS Look Around events
      
      lookAround.addEventListener(
          "close",
          event => {
              app.closeView();
              event.preventDefault();
          }
      );
      
      lookAround.addEventListener(
          "load",
          event => app.fadeInView()
      );
      
      lookAround.addEventListener(
          "error",
          event => app.fadeOutView()
      );
      
      lookAround.addEventListener(
          "readystatechange",
          event => console.log(lookAround.readyState)
      );
    • 20:01 - MapKit JS Look Around Preview

      // MapKit JS Look Around Preview
      
      const lookAround = new mapkit.LookAroundPreview(
          document.getElementById("container"),
          place
      );
    • 0:00 - 简介
    • 用户可以使用 Apple 地图导航和探索全球各地的地点,包括地标、咖啡馆、商店和徒步路线。通过 MapKit 和 MapKit JS 平台,你可以将这些地图功能集成到你的 App 和网站中。最近的更新包括用于查找和引用地点的“PlaceDescriptor”、用于显示地点信息的增强地理编码,以及用于提供导航帮助的 Directions API 和 Look Around API。

    • 0:45 - 查找地点
    • 新的 GeoToolbox 框架提供“PlaceDescriptor”类型。使用“PlaceDescriptor”以结构化信息表示地点,例如,通用名称、地址、坐标或设备位置。当你没有某个地点的唯一 MapKit 地点 ID 时,这种类型非常有用,比如在处理来自外部 API 或 CRM 的数据时,或者将地点引用传递给不使用 MapKit 的代码时。 通过“PlaceDescriptor”,MapKit 或其他地图服务提供商能够查找有关指定地点的丰富数据。“PlaceDescriptor”中的 representations 数组按优先级降序排列,最准确的信息显示在最前面,从而帮助确保最精确的位置识别。可以通过多种方法创建“PlaceDescriptor”,例如,指定坐标、地址或服务标识符。 服务标识符是一个字典,它将捆绑标识符映射到特定地图服务中的唯一地点标识符。这能在不同地图服务之间实现灵活性和互操作性。 当你使用“PlaceDescriptor”创建“MKMapItemRequest”时,MapKit 会优先使用服务标识符中的 MapKit 标识符 (如有)。如果没有,它将回退到坐标或地址等其他表示形式来获取该地点。 借助“PlaceDescriptors”,你能够轻松地向地图添加地点,显示包含丰富信息的地点卡,并创建指向 Apple 地图的通用链接,从而在不同设备和平台上提供流畅的用户体验。

    • 9:34 - 显示地点
    • 在 iOS 18 中,地理编码过程已集成到 MapKit 中,取代了已弃用的 CoreLocation 类“CLGeocoder”和“CLPlacemark”。地理编码涉及两个主要过程:正向和反向。 正向地理编码将地址转换为坐标,而反向地理编码则相反,它接收坐标并提供地址。新的 MapKit API 允许你使用“MKReverseGeocodingRequest”发起反向地理编码请求,这个请求会返回地图项数组,通常只包含特定位置的一个条目。 使用“MKAddress”和“MKAddressRepresentations”来显示地址信息。“MKAddress”提供简单的完整和简短地址字符串,而“MKAddressRepresentations”提供更大的灵活性,允许你根据语言区设置和 App 的特定需求等因素自定地址显示,从而实现更简洁、对用户更友好的位置数据显示。

    • 14:14 - 畅行四方
    • MapKit 提供了一个 Directions API,使用户能够通过各种交通方式 (包括步行、驾车和现在新增的骑行) 查找不同地点之间的路线。这个 API 提供详细的路线信息,例如时间和距离的估算、分步说明以及在地图上绘制的路线几何形状。 你可以创建路线请求、设置出发地和目的地以及计算路线。响应包括匹配的出发地和目的地位置、一条或多条路线以及道路封闭等相关通知。 MapKit 还扩展为包括 watchOS 和 MapKit JS 上的骑行路线指引支持,让用户可以在手表和网站上规划骑行路线。此外,“地图”中可提供 360 度街道级图像的“四处看看”功能已引入 iOS 16 中的各款 MapKit App,而且现已在 MapKit JS 中提供,让你能够使用交互式街景来增强 App 的功能。

Developer Footer

  • 视频
  • WWDC25
  • 深入探索 MapKit
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习与 AI
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    获取 Apple Developer App。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则