VietMapCoreNavigation 3.0.0

VietMapCoreNavigation 3.0.0

nhatpvThanhdt 维护。



 
依赖
VietMapDirections.swift~> 2.0.1
VietMapTurf~> 1.0.2
 

  • 作者:
  • NhatPV
Flitsmeister Navigation iOS Splash

Flitsmeister iOS 导航 SDK 基于 Mapbox Navigation SDK v0.21 的分支 (v0.21.0) 构建,该 SDK 是基于 Mapbox Directions API(v0.23.0)构建的,并包含获取时间导航指令所需的所有逻辑。

使用此 SDK,您可以在自己的 iOS 应用程序中实现逐步导航功能,同时托管自己的地图瓦片和 Directions API。

我们为何要分叉

  1. Mapbox 决定在其导航 SDK 中添加一个闭源组件,并引入了非开源许可证。Flitsmeister 希望有一个开源解决方案。
  2. Mapbox 决定在其 SDK 中添加遥测功能。我们无法在不调整源代码的情况下将其关闭。
  3. 我们想在不付给 Mapbox 每个MAU费用的情况下使用 SDK,并且不使用 Mapbox API 密钥。

所有问题都通过此 SDK 得到解决。

我们做了什么变更

  • 移除了 EventManager 和所有相关引用,这个管理者收集了我们不希望发送的遥测数据
  • Mapbox SDK(版本 4.3)过渡到 Maplibre Maps SDK(版本 5.12.2)
  • 在 NavigationMapView 构造函数中添加了可选的配置参数,用于自定义某些属性,例如路线颜色

入门指南

如果您想在项目中包含此 SDK,您必须遵循以下步骤

  1. 安装 Carthage
    • 打开终端
    • [可选] 在 M1 Mac 上更改终端为 bash:chsh -s /bin/bash
    • 安装 Homebrew:/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    • 安装 Carthage:`brew install carthage`
  2. 创建一个新的 XCode 项目
  3. 创建 Cartfile
    • 打开终端
    • 更改到 XCode 项目的根目录:`cd path/to/Project`
    • 创建 Cartfile:`touch Cartfile`
    • 将新文件添加:`Cartfile`
  4. 通过转到您的应用程序的项目文件 -> 包依赖项 -> 按下 '+' -> https://github.com/maplibre/maplibre-gl-native-distribution -> 'Exact' 5.12.2 添加 Maplibre Maps SPM(Swift Package Manager)依赖项
  5. 将依赖项添加到 Cartfile
    github "flitsmeister/flitsmeister-navigation-ios" ~> 1.0.6
    
  6. 构建框架
    • 打开终端
    • 更改到 XCode 项目的根目录:`cd path/to/Project`
    • 运行:`carthage bootstrap --platform iOS --use-xcframeworks`
    • 将添加新文件
      • Cartfile.resolved = 指示哪些框架已被获取/构建
      • Carthage 文件夹 = 包含所有构建的框架
  7. 将框架拖放到项目中:`TARGETS -> General -> 框架、库..`
    • 所有 xcframeworks
  8. Info.plist 添加属性
    • MGLMapboxAccessToken / String / 留空 = 确保SDK不会崩溃
    • MGLMapboxAPIBaseURL / String / 添加 URL = 用于获取导航 JSON 的 URL
    • NSLocationWhenInUseUsageDescription / 字符串 / 添加描述 = 需要访问位置权限
  9. [可选] 当应用程序在设备上运行且有问题时:将 arm64 添加到 项目 -> <项目名称> -> 编译设置 -> 仅排除架构
  10. 以示例代码为灵感

获取帮助

  • 有错误报告吗? 创建问题。如果可能,包括 Flitsmeister 服务的版本、完整的日志以及显示问题的项目。
  • 有特性请求吗? 创建问题。告诉我们应该完成什么功能以及你为什么需要此功能。

示例代码

目前没有可用的演示应用程序。请检查 Mapbox 存储库或文档中的示例,特别是分叉版本。您可以尝试提供的演示应用程序,您需要首先在该项目根目录中运行 carthage update --platform iOS --use-xc-frameworks

要查看地图或计算路线,您需要您自己的地图瓦片和方向服务。

请以下代码为灵感

import Mapbox
import VietMapDirections
import VietMapCoreNavigation
import VietMapNavigation

class ViewController: UIViewController {
    var navigationView: NavigationMapView?
    
    // Keep `RouteController` in memory (class scope),
    // otherwise location updates won't be triggered
    public var mapboxRouteController: RouteController?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let navigationView = NavigationMapView(
            frame: .zero,
            // Tile loading can take a while
            styleURL: URL(string: "your style URL here"),
            config: MNConfig())
        self.navigationView = navigationView
        view.addSubview(navigationView)
        navigationView.translatesAutoresizingMaskIntoConstraints = false
        navigationView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        navigationView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        navigationView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        navigationView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        
        let waypoints = [
            CLLocation(latitude: 52.032407, longitude: 5.580310),
            CLLocation(latitude: 51.768686, longitude: 4.6827956)
        ].map { Waypoint(location: $0) }
        
        let options = NavigationRouteOptions(waypoints: waypoints, profileIdentifier: .automobileAvoidingTraffic)
        options.shapeFormat = .polyline6
        options.distanceMeasurementSystem = .metric
        options.attributeOptions = []
        
        print("[\(type(of:self))] Calculating routes with URL: \(Directions.shared.url(forCalculating: options))")
        
        /// URL is based on the base URL in the Info.plist called `MGLMapboxAPIBaseURL`
        /// - Note: Your routing provider could be strict about the user-agent of this app before allowing the call to work
        Directions.shared.calculate(options) { (waypoints, routes, error) in
            guard let route = routes?.first else { return }
            
            let simulatedLocationManager = SimulatedLocationManager(route: route)
            simulatedLocationManager.speedMultiplier = 20
            
            let mapboxRouteController = RouteController(
                along: route,
                directions: Directions.shared,
                locationManager: simulatedLocationManager)
            self.mapboxRouteController = mapboxRouteController
            mapboxRouteController.delegate = self
            mapboxRouteController.resume()
            
            NotificationCenter.default.addObserver(self, selector: #selector(self.didPassVisualInstructionPoint(notification:)), name: .routeControllerDidPassVisualInstructionPoint, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(self.didPassSpokenInstructionPoint(notification:)), name: .routeControllerDidPassSpokenInstructionPoint, object: nil)
            
            navigationView.showRoutes([route], legIndex: 0)
        }
    }
}

// MARK: - RouteControllerDelegate

extension ViewController: RouteControllerDelegate {
    @objc public func routeController(_ routeController: RouteController, didUpdate locations: [CLLocation]) {
        let camera = MGLMapCamera(
            lookingAtCenter: locations.first!.coordinate,
            acrossDistance: 500,
            pitch: 0,
            heading: 0
        )
        
        navigationView?.setCamera(camera, animated: true)
    }
    
    @objc func didPassVisualInstructionPoint(notification: NSNotification) {
        guard let currentVisualInstruction = currentStepProgress(from: notification)?.currentVisualInstruction else { return }
        
        print(String(
            format: "didPassVisualInstructionPoint primary text: %@ and secondary text: %@",
            String(describing: currentVisualInstruction.primaryInstruction.text),
            String(describing: currentVisualInstruction.secondaryInstruction?.text)))
    }
    
    @objc func didPassSpokenInstructionPoint(notification: NSNotification) {
        guard let currentSpokenInstruction = currentStepProgress(from: notification)?.currentSpokenInstruction else { return }
        
        print("didPassSpokenInstructionPoint text: \(currentSpokenInstruction.text)")
    }
    
    private func currentStepProgress(from notification: NSNotification) -> RouteStepProgress? {
        let routeProgress = notification.userInfo?[RouteControllerNotificationUserInfoKey.routeProgressKey] as? RouteProgress
        return routeProgress?.currentLegProgress.currentStepProgress
    }
}

许可

代码根据 MIT 和 ISC 许可证许可。ISC 意在功能上与 MIT 许可证等效。