You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter集成CarPlay后无法从POI界面启动导航地图求助

Flutter应用集成CarPlay后实现POI条目触发CarPlay内导航

需求

  • 基于flutter_carplay插件开发的Flutter应用,点击CarPlay中POI界面的条目时,需在CarPlay内打开地图并导航至该条目对应的地点

复现步骤

  • 创建Flutter应用并添加flutter_carplay插件
  • 替换插件中的FCPPointOfInterest.swift代码为下方修改后的版本
  • 使用POI模板后尝试从CarPlay发起导航

修改后的FCPPointOfInterest.swift代码

//
//  FCPPointOfInterest.swift
//  Runner
//
//  Created by Olaf Schneider on 15.02.22.
//

import CarPlay

@available(iOS 14.0, *)
class FCPPointOfInterest {
    private(set) var _super: CPPointOfInterest?
    private(set) var elementId: String
    private var latitude: Double
    private var longitude: Double
    private var title: String
    private var subtitle: String?
    private var summary: String?
    private var detailTitle: String?
    private var detailSubtitle: String?
    private var detailSummary: String?
    private var image: String?

    private var primaryButton: CPTextButton?
    private var objcPrimaryButton: FCPTextButton?

    private var secondaryButton: CPTextButton?
    private var objcSecondaryButton: FCPTextButton?

    static let maxPinImageSize: CGFloat = 40

    init(obj: [String: Any]) {
        self.elementId = obj["_elementId"] as! String

        let lat = obj["latitude"] as! NSNumber
        self.latitude = lat.doubleValue

        let lng = obj["longitude"] as! NSNumber
        self.longitude = lng.doubleValue
        self.title = obj["title"] as! String
        self.subtitle = obj["subtitle"] as? String
        self.summary = obj["summary"] as? String
        self.detailTitle = obj["detailTitle"] as? String
        self.detailSubtitle = obj["detailSubtitle"] as? String
        self.detailSummary = obj["detailSummary"] as? String
        self.image = obj["image"] as? String

        let primaryButtonData = obj["primaryButton"] as? [String: Any]
        if primaryButtonData != nil {
            self.objcPrimaryButton = FCPTextButton(obj: primaryButtonData!)

            // 创建带所有必要参数的CPTextButton
            let button = CPTextButton(
                title: self.objcPrimaryButton?.get.title ?? "",
                textStyle: .normal,  // 可根据需要改为.confirm
                handler: { [weak self] _ in
                    self?.launchGoogleMapsWithCarPlay()
                }
            )

            self.primaryButton = button
        }
        let secondaryButtonData = obj["secondaryButton"] as? [String: Any]
        if secondaryButtonData != nil {
            self.objcSecondaryButton = FCPTextButton(obj: secondaryButtonData!)
            self.secondaryButton = self.objcSecondaryButton?.get
        }
    }
    func launchGoogleMapsWithCarPlaytry() {
        // 生成带目标坐标的Google Maps链接
        let urlString = "comgooglemaps://?daddr=\(latitude),\(longitude)&directionsmode=driving"

        // 检查Google Maps是否已安装
        if let url = URL(string: urlString), UIApplication.shared.canOpenURL(url) {
            // 打开Google Maps
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        } else {
            // 如果未安装Google Maps,降级使用Apple Maps
            let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
            let placemark = MKPlacemark(coordinate: coordinate)
            let mapItem = MKMapItem(placemark: placemark)

            let launchOptions: [String: Any] = [
                MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,
                MKLaunchOptionsShowsTrafficKey: true,
                MKLaunchOptionsMapTypeKey: MKMapType.standard.rawValue,
            ]

            mapItem.openInMaps(launchOptions: launchOptions)
        }
    }

  

    
    func launchGoogleMapsWithCarPlay() {
        // 检查应用是否处于CarPlay模式
        guard let carPlayScene = UIApplication.shared.connectedScenes.first(where: { $0 is CPTemplateApplicationScene }) as? CPTemplateApplicationScene,
              let interfaceController = carPlayScene.delegate as? CPTemplateApplicationSceneDelegate else {
            // 如果未连接CarPlay,降级使用移动端导航
//            launchMobileNavigation()
            return
        }
        
        // 生成针对CarPlay的Google Maps链接
        let urlString = "comgooglemaps://?daddr=\(latitude),\(longitude)&directionsmode=driving"
        
        if let url = URL(string: urlString), UIApplication.shared.canOpenURL(url) {
            // 打开Google Maps
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        } else {
            // 如果未安装Google Maps,降级使用Apple Maps
            let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
            let placemark = MKPlacemark(coordinate: coordinate)
            let mapItem = MKMapItem(placemark: placemark)
            
            let launchOptions: [String: Any] = [
                MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,
                MKLaunchOptionsShowsTrafficKey: true,
                MKLaunchOptionsMapTypeKey: MKMapType.standard.rawValue
            ]
            
            mapItem.openInMaps(launchOptions: launchOptions)
        }
    }


    // 移动端导航降级函数
    private func launchMobileNavigation() {
        let urlString = "comgooglemaps://?daddr=\(latitude),\(longitude)&directionsmode=driving"
        
        if let url = URL(string: urlString), UIApplication.shared.canOpenURL(url) {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        } else {
            let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
            let placemark = MKPlacemark(coordinate: coordinate)
            let mapItem = MKMapItem(placemark: placemark)
            
            let launchOptions: [String: Any] = [
                MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,
                MKLaunchOptionsShowsTrafficKey: true,
                MKLaunchOptionsMapTypeKey: MKMapType.standard.rawValue
            ]
            
            mapItem.openInMaps(launchOptions: launchOptions)
        }
    }

    
    private func launchMapsApp() {
        if UIApplication.shared.canOpenURL(URL(string: "comgooglemaps://")!) {
            if let url = URL(
                string: "comgooglemaps://?daddr=\(latitude),\(longitude)&directionsmode=driving")
            {
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            }
        } else {
            if let url = URL(
                string:
                    "https://www.google.com/maps/dir/?api=1&destination=\(latitude),\(longitude)&travelmode=driving"
            ) {
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
            }
        }
    }

    var get: CPPointOfInterest {

        let location = MKMapItem(
            placemark: MKPlacemark(
                coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude)))
        var pinImage: UIImage? = nil

        if let image = self.image {
            let key = SwiftFlutterCarplayPlugin.registrar?.lookupKey(forAsset: image)

            pinImage = UIImage(named: key!)
            if let pImage = pinImage {
                if pImage.size.height > FCPPointOfInterest.maxPinImageSize
                    || pImage.size.width > FCPPointOfInterest.maxPinImageSize
                {
                    pinImage = pImage.resizeImageTo(
                        size: CGSize(
                            width: FCPPointOfInterest.maxPinImageSize,
                            height: FCPPointOfInterest.maxPinImageSize))
                }
            }
        }
        let poi = CPPointOfInterest(
            location: location, title: title, subtitle: subtitle, summary: summary,
            detailTitle: detailTitle, detailSubtitle: detailSubtitle,
            detailSummary: detailSummary, pinImage: pinImage)

        if let primaryButton = self.primaryButton {
            poi.primaryButton = primaryButton

        }
        if let secondaryButton = self.secondaryButton {
            poi.secondaryButton = secondaryButton
        }

        self._super = poi
        return poi
    }
}

内容的提问来源于stack exchange,提问作者Ragul PR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:39:55