1. 前言
Mapbox 是一个面向开发者的地图平台。它提供易于使用、功能强大的 API,支持 iOS、Android 和 Web 等平台。具体介绍可以到 Mapbox 的 官网 查看。
本文主要以 iOS 平台为例,针对 Mapbox 提供的离线地图功能来介绍。关于前期的如何接入 Mapbox 以及其它功能的说明,请移步到 Mapbox-iOS-SDK 文档 查看。
2. Mapbox 离线地图
2.1 下载地图
2.1.1 准备地图
在下载地图前,我们应该建立了地图实例 MGLMapView
并且做好必要的配置:
let url = URL(string: "mapbox://styles/mapbox/streets-v10")
let sampleLoaction = CLLocationCoordinate2D(latitude: 22.54, longitude: 113.93)
var mapView = MGLMapView(frame: view.bounds, styleURL: url)
mapView.setCenter(sampleLoaction, zoomLevel: 16, animated: false)
2.1.2 确定下载区域
利用 MGLTilePyramidOfflineRegion
对象来确定需要下载的区域。初始化 MGLTilePyramidOfflineRegion
对象需要以下参数:
styleURL:地图的样式URL
bounds:地理区域
MGLCoordinateBounds
minimumZoomLevel:最小的地图层级
maximumZoomLevel:最大的地图层级
let region = MGLTilePyramidOfflineRegion(
styleURL: mapView.styleURL,
bounds: mapView.visibleCoordinateBounds,
fromZoomLevel: mapView.zoomLevel,
toZoomLevel: 16)
2.1.3 开始下载
在 Mapbox 中,一块区域的离线地图抽象为 MGLOfflinePack
对象,利用 MGLOfflineStorage
单例创建一个 MGLOfflinePack
的方法来达到下载地图的目的。该方法还接收一个附加信息的 Data
实例,我们可以利用它来给每一块我们下载的地图附带上必要的信息,比如标记这块离线地图的名字等。
do {
// 附加信息:这块离线地图的名字
let userInfo = ["name": "My Offline Pack"]
let context = try NSKeyedArchiver.archivedData(withRootObject: userInfo, requiringSecureCoding: false)
// 传入下载区域,即上一步创建的 MGLTilePyramidOfflineRegion 实例,以及附加信息
MGLOfflineStorage.shared.addPack(for: region, withContext: context) { (pack, error) in
guard error == nil else { return }
// 开始下载
pack!.resume()
}
} catch let error {
print("Error: \(error.localizedDescription)")
}
2.1.4 监听下载状态
有些情况下,我们需要在前台展示离线地图的下载进度,所以我们需要知道地图下载的状态,这时候我们需要监听 Mapbox 提供的几个通知:
下载进度的变化:MGLOfflinePackProgressChanged
下载发生错误:MGLOfflinePackError
下载达到最大限额:MGLOfflinePackMaximumMapboxTilesReached
NotificationCenter.default.addObserver(self, selector: #selector(offlinePackProgressDidChange), name: .MGLOfflinePackProgressChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(offlinePackDidReceiveError), name: .MGLOfflinePackError, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(offlinePackDidReceiveMaximumAllowedMapboxTiles), name: .MGLOfflinePackMaximumMapboxTilesReached, object: nil)
2.2 查看和管理离线地图
离线地图是由 MGLOfflineStorage
这个单例来管理的。
- 查看
通过 MGLOfflineStorage.shared.packs
获得所有离线地图的一个数组。如上面所说的,一块区域的离线地图抽象为 MGLOfflinePack
对象,所以这是一个 MGLOfflinePack
对象的数组。
通过 MGLOfflinePack
对象,我们可以获得当初下载这块地图的区域信息, 通过该区域信息,我们可以在需要查看离线地图的时候,将地图显示的区域移动到该区域:
let offlineRegion = MGLOfflineStorage.shared.packs?[0].region as? MGLTilePyramidOfflineRegion
mapView.styleURL = offlineRegion.styleURL
mapView.setVisibleCoordinateBounds(offlineRegion.bounds, animated: false)
mapView.setZoomLevel(offlineRegion.minimumZoomLevel, animated: true)
- 移除
移除一块离线地图则可以用 removePack
的方法,它接收一个 MGLOfflinePack
的参数。
let pack: MGLOfflinePack = ...
MGLOfflineStorage.shared.removePack(pack) { (error) in
print(error)
}
- 更新
当有网络连接的情况下,Mapbox 会周期性的请求网络来重新验证缓存的地图信息,如果有新的地图信息,会更新这部分缓存的地图信息。
3. Mapbox 离线地图限额与定价
Mapbox 下载离线地图是有一定的限额的,如果默认提供的限额达不到你的业务需求,可以通过加入 enterprise plan 来提升限额。
计量单位 Tile
Mapbox 离线地图下载量是以Tile
作为计量单位的。最大限额
Mapbox 默认最大的限额为 6000 tiles计算方式
这个限额的计算方式并不仅仅是以区域计算,还以地图的展示样式计算,比如我们下载一块区域的地图,它有 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 还提供了一个计算工具给我们: offline-estimator,你可以在地图上圈一块区域,并且设置 zoom level 范围,它就可以计算出 Tile 的数目:价格
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 计划,来进行具体沟通。