1. 前言

Mapbox 是一个面向开发者的地图平台。它提供易于使用、功能强大的 API,支持 iOS、Android 和 Web 等平台。具体介绍可以到 Mapbox 的 官网 查看。

本文主要以 iOS 平台为例,针对 Mapbox 提供的离线地图功能来介绍。关于前期的如何接入 Mapbox 以及其它功能的说明,请移步到 Mapbox-iOS-SDK 文档 查看。

2. Mapbox 离线地图

2.1 下载地图

2.1.1 准备地图

在下载地图前,我们应该建立了地图实例 MGLMapView 并且做好必要的配置:

  1. let url = URL(string: "mapbox://styles/mapbox/streets-v10")
  2. let sampleLoaction = CLLocationCoordinate2D(latitude: 22.54, longitude: 113.93)
  3. var mapView = MGLMapView(frame: view.bounds, styleURL: url)
  4. mapView.setCenter(sampleLoaction, zoomLevel: 16, animated: false)

2.1.2 确定下载区域

利用 MGLTilePyramidOfflineRegion 对象来确定需要下载的区域。初始化 MGLTilePyramidOfflineRegion 对象需要以下参数:

  • styleURL:地图的样式URL

  • bounds:地理区域 MGLCoordinateBounds

  • minimumZoomLevel:最小的地图层级

  • maximumZoomLevel:最大的地图层级

  1. let region = MGLTilePyramidOfflineRegion(
  2. styleURL: mapView.styleURL,
  3. bounds: mapView.visibleCoordinateBounds,
  4. fromZoomLevel: mapView.zoomLevel,
  5. toZoomLevel: 16)

2.1.3 开始下载

在 Mapbox 中,一块区域的离线地图抽象为 MGLOfflinePack 对象,利用 MGLOfflineStorage 单例创建一个 MGLOfflinePack 的方法来达到下载地图的目的。该方法还接收一个附加信息的 Data 实例,我们可以利用它来给每一块我们下载的地图附带上必要的信息,比如标记这块离线地图的名字等。

  1. do {
  2. // 附加信息:这块离线地图的名字
  3. let userInfo = ["name": "My Offline Pack"]
  4. let context = try NSKeyedArchiver.archivedData(withRootObject: userInfo, requiringSecureCoding: false)
  5. // 传入下载区域,即上一步创建的 MGLTilePyramidOfflineRegion 实例,以及附加信息
  6. MGLOfflineStorage.shared.addPack(for: region, withContext: context) { (pack, error) in
  7. guard error == nil else { return }
  8. // 开始下载
  9. pack!.resume()
  10. }
  11. } catch let error {
  12. print("Error: \(error.localizedDescription)")
  13. }

2.1.4 监听下载状态

有些情况下,我们需要在前台展示离线地图的下载进度,所以我们需要知道地图下载的状态,这时候我们需要监听 Mapbox 提供的几个通知:

  • 下载进度的变化:MGLOfflinePackProgressChanged

  • 下载发生错误:MGLOfflinePackError

  • 下载达到最大限额:MGLOfflinePackMaximumMapboxTilesReached

  1. NotificationCenter.default.addObserver(self, selector: #selector(offlinePackProgressDidChange), name: .MGLOfflinePackProgressChanged, object: nil)
  2. NotificationCenter.default.addObserver(self, selector: #selector(offlinePackDidReceiveError), name: .MGLOfflinePackError, object: nil)
  3. NotificationCenter.default.addObserver(self, selector: #selector(offlinePackDidReceiveMaximumAllowedMapboxTiles), name: .MGLOfflinePackMaximumMapboxTilesReached, object: nil)

2.2 查看和管理离线地图

离线地图是由 MGLOfflineStorage 这个单例来管理的。

  1. 查看

通过 MGLOfflineStorage.shared.packs 获得所有离线地图的一个数组。如上面所说的,一块区域的离线地图抽象为 MGLOfflinePack 对象,所以这是一个 MGLOfflinePack 对象的数组。

通过 MGLOfflinePack 对象,我们可以获得当初下载这块地图的区域信息, 通过该区域信息,我们可以在需要查看离线地图的时候,将地图显示的区域移动到该区域:

  1. let offlineRegion = MGLOfflineStorage.shared.packs?[0].region as? MGLTilePyramidOfflineRegion
  2. mapView.styleURL = offlineRegion.styleURL
  3. mapView.setVisibleCoordinateBounds(offlineRegion.bounds, animated: false)
  4. mapView.setZoomLevel(offlineRegion.minimumZoomLevel, animated: true)
  1. 移除

移除一块离线地图则可以用 removePack 的方法,它接收一个 MGLOfflinePack 的参数。

  1. let pack: MGLOfflinePack = ...
  2. MGLOfflineStorage.shared.removePack(pack) { (error) in
  3. print(error)
  4. }
  1. 更新

当有网络连接的情况下,Mapbox 会周期性的请求网络来重新验证缓存的地图信息,如果有新的地图信息,会更新这部分缓存的地图信息。

3. Mapbox 离线地图限额与定价

Mapbox 下载离线地图是有一定的限额的,如果默认提供的限额达不到你的业务需求,可以通过加入 enterprise plan 来提升限额。

  1. 计量单位 Tile
    Mapbox 离线地图下载量是以 Tile 作为计量单位的。

  2. 最大限额
    Mapbox 默认最大的限额为 6000 tiles

  3. 计算方式
    这个限额的计算方式并不仅仅是以区域计算,还以地图的展示样式计算,比如我们下载一块区域的地图,它有 10 个 tile,但是同时我们还下载了这个区域的卫星地图和街道地图,那么这里 Mapbox 是算你 10 x 2 = 20 个 Tile。
    一个区域地图的 Tile 数目,会根据所选择的 zoom level 范围而不同。比如 6000个Tile 大约是 伦敦M25环线公路所包围的区域(zoom level 范围0–15),又或者是美国本土区域(zoom levels 范围0–9)。zoom level 范围越大,代表地图能缩放的范围越大,细节也就越多。最大的 zoom level 是25.5,而 MGLMapView 对象默认设置最大为22。
    这里圈了一下 伦敦M25环线公路 所包围的区域,给大家做个参考:
    Mapbox 离线地图使用介绍 - 图1
    Mapbox 还提供了一个计算工具给我们: offline-estimator,你可以在地图上圈一块区域,并且设置 zoom level 范围,它就可以计算出 Tile 的数目:Mapbox 离线地图使用介绍 - 图2

  4. 价格
    Mapbox 提供了三种收费计划:

    • Pay-as-you-go:
      比如每个月基础 50,000 active users是免费的,超过 50,000后,以每 500 个收 0.5美元 的价格计算。

    • Commercial:
      这个则在 Pay-as-you-go 的基础上,再加499美元一个月,可以享受更多的特权。

    • Enterprise:
      如果上面的计划都不能满足你,那么则需要 联系他们

注意:Pay-as-you-go 和 Commercial 这两种计划所提供的都是 6000 Tile 的限额,要想进一步提升限额,则需要加入 Enterprise 计划,来进行具体沟通。