소스 검색

add mapkit ios plugin

Groot 8 달 전
부모
커밋
db81e064a5

+ 1 - 1
ios/Podfile

@@ -1,5 +1,5 @@
 # Uncomment this line to define a global platform for your project
-# platform :ios, '12.0'
+platform :ios, '13.0'
 
 # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
 ENV['COCOAPODS_DISABLE_STATS'] = 'true'

+ 7 - 1
ios/Podfile.lock

@@ -24,6 +24,8 @@ PODS:
   - in_app_purchase_storekit (0.0.1):
     - Flutter
     - FlutterMacOS
+  - map_mapkit_ios (0.0.1):
+    - Flutter
   - MMKV (2.0.2):
     - MMKVCore (~> 2.0.2)
   - mmkv_ios (2.0.0):
@@ -59,6 +61,7 @@ DEPENDENCIES:
   - flutter_umeng (from `.symlinks/plugins/flutter_umeng/ios`)
   - gravity_engine (from `.symlinks/plugins/gravity_engine/ios`)
   - in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`)
+  - map_mapkit_ios (from `.symlinks/plugins/map_mapkit_ios/ios`)
   - mmkv_ios (from `.symlinks/plugins/mmkv_ios/ios`)
   - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
   - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
@@ -92,6 +95,8 @@ EXTERNAL SOURCES:
     :path: ".symlinks/plugins/gravity_engine/ios"
   in_app_purchase_storekit:
     :path: ".symlinks/plugins/in_app_purchase_storekit/darwin"
+  map_mapkit_ios:
+    :path: ".symlinks/plugins/map_mapkit_ios/ios"
   mmkv_ios:
     :path: ".symlinks/plugins/mmkv_ios/ios"
   package_info_plus:
@@ -116,6 +121,7 @@ SPEC CHECKSUMS:
   flutter_umeng: c1bb7f26be0aea78e454fed645eb146a5d26d182
   gravity_engine: 9075091c4adcd0169506f97688ebac7f5454c4ac
   in_app_purchase_storekit: d1a48cb0f8b29dbf5f85f782f5dd79b21b90a5e6
+  map_mapkit_ios: fe3a12a53d3f398815c9973cd82bb0a9679bde43
   MMKV: 3eacda84cd1c4fc95cf848d3ecb69d85ed56006c
   mmkv_ios: ea225e1659b4769b29f7ee110380de01b40a4baf
   MMKVCore: 508b4d3a8ce031f1b5c8bd235f0517fb3f4c73a9
@@ -126,6 +132,6 @@ SPEC CHECKSUMS:
   url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
   wechat_kit: b50b40a52ad88cb9e378a32e300a2d8bdc0e4726
 
-PODFILE CHECKSUM: 4305caec6b40dde0ae97be1573c53de1882a07e5
+PODFILE CHECKSUM: 251cb053df7158f337c0712f2ab29f4e0fa474ce
 
 COCOAPODS: 1.16.2

+ 3 - 8
ios/Runner.xcodeproj/project.pbxproj

@@ -316,14 +316,10 @@
 			inputFileListPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
 			);
-			inputPaths = (
-			);
 			name = "[CP] Copy Pods Resources";
 			outputFileListPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
 			);
-			outputPaths = (
-			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
@@ -337,14 +333,10 @@
 			inputFileListPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 			);
-			inputPaths = (
-			);
 			name = "[CP] Embed Pods Frameworks";
 			outputFileListPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
 			);
-			outputPaths = (
-			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
@@ -499,6 +491,7 @@
 				DEVELOPMENT_TEAM = U382G987BX;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = Runner/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
@@ -682,6 +675,7 @@
 				DEVELOPMENT_TEAM = U382G987BX;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = Runner/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
@@ -705,6 +699,7 @@
 				DEVELOPMENT_TEAM = U382G987BX;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = Runner/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",

+ 33 - 0
plugins/map_mapkit_ios/.gitignore

@@ -0,0 +1,33 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.build/
+.buildlog/
+.history
+.svn/
+.swiftpm/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
+/pubspec.lock
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+build/

+ 30 - 0
plugins/map_mapkit_ios/.metadata

@@ -0,0 +1,30 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: "ea121f8859e4b13e47a8f845e4586164519588bc"
+  channel: "stable"
+
+project_type: plugin
+
+# Tracks metadata for the flutter migrate command
+migration:
+  platforms:
+    - platform: root
+      create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
+      base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
+    - platform: ios
+      create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
+      base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
+
+  # User provided section
+
+  # List of Local paths (relative to this file) that should be
+  # ignored by the migrate tool.
+  #
+  # Files that are not part of the templates will be ignored by default.
+  unmanaged_files:
+    - 'lib/main.dart'
+    - 'ios/Runner.xcodeproj/project.pbxproj'

+ 3 - 0
plugins/map_mapkit_ios/CHANGELOG.md

@@ -0,0 +1,3 @@
+## 0.0.1
+
+* TODO: Describe initial release.

+ 1 - 0
plugins/map_mapkit_ios/LICENSE

@@ -0,0 +1 @@
+TODO: Add your license here.

+ 15 - 0
plugins/map_mapkit_ios/README.md

@@ -0,0 +1,15 @@
+# map_mapkit_ios
+
+A new Flutter plugin project.
+
+## Getting Started
+
+This project is a starting point for a Flutter
+[plug-in package](https://flutter.dev/to/develop-plugins),
+a specialized package that includes platform-specific implementation code for
+Android and/or iOS.
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
+

+ 4 - 0
plugins/map_mapkit_ios/analysis_options.yaml

@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options

+ 38 - 0
plugins/map_mapkit_ios/ios/.gitignore

@@ -0,0 +1,38 @@
+.idea/
+.vagrant/
+.sconsign.dblite
+.svn/
+
+.DS_Store
+*.swp
+profile
+
+DerivedData/
+build/
+GeneratedPluginRegistrant.h
+GeneratedPluginRegistrant.m
+
+.generated/
+
+*.pbxuser
+*.mode1v3
+*.mode2v3
+*.perspectivev3
+
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+xcuserdata
+
+*.moved-aside
+
+*.pyc
+*sync/
+Icon?
+.tags*
+
+/Flutter/Generated.xcconfig
+/Flutter/ephemeral/
+/Flutter/flutter_export_environment.sh

+ 0 - 0
plugins/map_mapkit_ios/ios/Assets/.gitkeep


+ 9 - 0
plugins/map_mapkit_ios/ios/Classes/MapMapkitIosPlugin.swift

@@ -0,0 +1,9 @@
+import Flutter
+import UIKit
+
+public class MapMapkitIosPlugin: NSObject, FlutterPlugin {
+    public static func register(with registrar: FlutterPluginRegistrar) {
+        let factory = MapFlutterViewFactory(messenger: registrar.messenger())
+        registrar.register(factory, withId: MapKitConstans.mapViewId, gestureRecognizersBlockingPolicy: FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded)
+    }
+}

+ 76 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/MapFlutterView.swift

@@ -0,0 +1,76 @@
+//
+//  MapFlutterView.swift
+//  Runner
+//
+//  Created by Groot on 2025/5/7.
+//
+
+import Flutter
+import UIKit
+import SwiftUI
+
+class MapFlutterViewFactory: NSObject, FlutterPlatformViewFactory {
+    private var messenger: FlutterBinaryMessenger
+
+    init(messenger: FlutterBinaryMessenger) {
+        self.messenger = messenger
+    }
+
+    func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
+        return MapFlutterView(withFrame: frame, viewIdentifier: viewId, arguments: args, binaryMessenger: messenger)
+    }
+
+    func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
+        return FlutterStandardMessageCodec.sharedInstance()
+    }
+}
+
+class MapFlutterView: NSObject, FlutterPlatformView {
+
+    var contentView: UIView
+
+    var methodChannel: FlutterMethodChannel
+    
+    var viewModel: MapViewModel = .init()
+
+    init(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger messenger: FlutterBinaryMessenger) {
+        contentView = UIView()
+        methodChannel = FlutterMethodChannel(name: MapKitConstans.methodChannelName, binaryMessenger: messenger)
+        super.init()
+        createMapView()
+        setupMethodChannel()
+    }
+
+    func view() -> UIView {
+        return contentView
+    }
+
+    func createMapView() {
+        let keyWindows = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first(where: { $0.isKeyWindow })
+        let topController = keyWindows?.rootViewController
+        
+        viewModel.methodChannel = methodChannel
+        let vc = MapViewController(viewModel: viewModel)
+        let mapView = vc.view!
+        mapView.translatesAutoresizingMaskIntoConstraints = false
+        
+        topController?.addChild(vc)
+        contentView.addSubview(mapView)
+        
+        NSLayoutConstraint.activate(
+            [
+                mapView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
+                mapView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
+                mapView.topAnchor.constraint(equalTo: contentView.topAnchor),
+                mapView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
+            ])
+        
+        vc.didMove(toParent: topController)
+    }
+
+    func setupMethodChannel() {
+        methodChannel.setMethodCallHandler({ [weak self] (call, result) in
+            self?.viewModel.handleMethodCall(call, result: result)
+        })
+    }
+} 

+ 108 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/MapViewController.swift

@@ -0,0 +1,108 @@
+//
+//  MapViewController.swift
+//  Runner
+//
+//  Created by Groot on 2025/5/7.
+//
+
+import UIKit
+import MapKit
+import Combine
+
+class MapViewController: UIViewController {
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    let viewModel: MapViewModel
+    let mapView = MKMapView()
+    private var cancellables = Set<AnyCancellable>()
+    
+    init(viewModel: MapViewModel) {
+        self.viewModel = viewModel
+        super.init(nibName: nil, bundle: nil)
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        setupView()
+        setupMap()
+        bindViewModel()
+    }
+
+    private func setupView() {
+        mapView.translatesAutoresizingMaskIntoConstraints = false
+        view.addSubview(mapView)
+        NSLayoutConstraint.activate([
+            mapView.topAnchor.constraint(equalTo: view.topAnchor),
+            mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
+            mapView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+            mapView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
+        ])
+    }
+
+    private func setupMap() {
+        mapView.delegate = self
+        mapView.showsUserLocation = true
+        mapView.setUserTrackingMode(.follow, animated: true)
+    }
+    
+    private func bindViewModel() {
+        // 监听区域变化并更新地图
+        viewModel.$currentRegion
+            .compactMap { $0 }
+            .sink { [weak self] region in
+                self?.mapView.setRegion(region, animated: true)
+            }
+            .store(in: &cancellables)
+
+        viewModel.$markers
+            .sink { [weak self] markers in
+                self?.mapView.removeAnnotations(self?.mapView.annotations ?? [])
+                self?.mapView.addAnnotations(markers)
+            }
+            .store(in: &cancellables)
+
+        viewModel.$polylines
+            .sink { [weak self] polylines in
+                self?.mapView.removeOverlays(self?.mapView.overlays ?? [])
+                self?.mapView.addOverlays(polylines.map({ $0.polyline }))
+            }
+            .store(in: &cancellables)
+    }
+}
+
+extension MapViewController: MKMapViewDelegate {
+    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
+        var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MapAnnotationView.identifier) as? MapAnnotationView
+        
+        // 如果没有可复用的视图,创建新的自定义标注视图
+        if annotationView == nil {
+            annotationView = MapAnnotationView(annotation: annotation, reuseIdentifier: MapAnnotationView.identifier)
+        } else {
+            // 更新现有视图的标注
+            annotationView?.annotation = annotation
+        }
+        
+        return annotationView
+    }
+
+    func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
+        guard var marker = view.annotation as? ATMapMarker else {
+            return
+        }
+        
+        viewModel.handleMarkerTap(marker: &marker)
+    }
+
+    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
+        let renderer = MKPolylineRenderer(overlay: overlay)
+        renderer.lineWidth = 5
+        renderer.strokeColor = .blue
+        renderer.alpha = 1
+        renderer.lineCap = .round
+        renderer.lineJoin = .round
+        return renderer
+    }
+} 

+ 30 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/Model/ChannelMethods.swift

@@ -0,0 +1,30 @@
+//
+//  ChannelMethods.swift
+//  Runner
+//
+//  Created by Groot on 2025/5/9.
+//
+
+import Foundation
+
+enum ChannelMethods: String, CaseIterable {
+    case `init` = "init"
+    case getPlatformMapName = "getPlatformMapName"
+    case startLocation = "startLocation"
+    
+    // 地图相关方法名称
+    case methodMapMoveCamera = "map#moveCamera"
+    case methodMapAnimateCamera = "map#animateCamera" 
+    case methodMapClear = "map#clear"
+    
+    // 标记物相关方法名称
+    case methodUpdateOrAddMarkers = "marker#updateOrAddMarkers"
+    case methodReplaceAllMarkers = "marker#replaceAllMarkers"
+    case methodMarkerOnTap = "marker#onTap"
+    
+    // 轨迹纠偏
+    case methodQueryProcessedTrace = "trace#queryProcessedTrace"
+    
+    // polyline
+    case methodAddPolyline = "polyline#addPolyline"
+}

+ 14 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/Model/Constans.swift

@@ -0,0 +1,14 @@
+//
+//  Constans.swift
+//  Runner
+//
+//  Created by Groot on 2025/5/13.
+//
+
+import Foundation
+
+struct MapKitConstans {
+    static let methodChannelName: String = "atmob_map_method_channel"
+    
+    static let mapViewId: String = "com.atmob.flutter.map"
+}

+ 69 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/Model/MapProtocol.swift

@@ -0,0 +1,69 @@
+//
+//  MapProtocol.swift
+//  Runner
+//
+//  Created by Groot on 2025/5/8.
+//
+
+import Foundation
+import Flutter
+import MapKit
+
+// 地图功能接口定义
+protocol MapCapability {
+    var paramsDecodeError: FlutterError? { get set }
+
+    var methodChannel: FlutterMethodChannel? { get set }
+    
+    var currentRegion: MKCoordinateRegion? { get set }
+
+    var userLocation: CLLocationCoordinate2D? { get set }
+
+    var markers: [ATMapMarker] { get set }
+
+    var polylines: [ATMapPolyline] { get set }
+
+    // 处理地图添加Marker
+    func handleMapAddMarker(args: [String: Any]?, result: @escaping FlutterResult)
+    
+    // 处理地图添加Polyline
+    func handleMapAddPolyline(args: [String: Any]?, result: @escaping FlutterResult)
+    
+    // 处理地图移动
+    func handleMapMoveCamera(args: [String: Any]?, result: @escaping FlutterResult)
+    
+    // 处理地图清除Marker
+    func handleMapClearMarkers(result: @escaping FlutterResult)
+    
+    // 处理地图替换所有Marker
+    func handleMapReplaceAllMarkers(args: [String: Any]?, result: @escaping FlutterResult)
+    
+    // 处理Marker点击事件
+    func handleMarkerTap(marker: inout ATMapMarker)
+
+    func handleMethodCall(_ call: FlutterMethodCall, result: @escaping FlutterResult)
+}
+
+extension MapCapability {
+    func handleMethodCall(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+        guard let callMethod = ChannelMethods(rawValue: call.method) else {
+            result(FlutterMethodNotImplemented)
+            return
+        }
+        
+        switch callMethod {
+        case .methodMapMoveCamera, .methodMapAnimateCamera:
+            handleMapMoveCamera(args: call.arguments as? [String: Any], result: result)
+        case .methodUpdateOrAddMarkers:
+            handleMapAddMarker(args: call.arguments as? [String: Any], result: result)
+        case .methodMapClear:
+            handleMapClearMarkers(result: result)
+        case .methodReplaceAllMarkers:
+            handleMapReplaceAllMarkers(args: call.arguments as? [String: Any], result: result)
+        case .methodAddPolyline:
+            handleMapAddPolyline(args: call.arguments as? [String: Any], result: result)
+        default:
+            result(FlutterMethodNotImplemented)
+        }
+    }
+}

+ 89 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/Model/Models.swift

@@ -0,0 +1,89 @@
+//
+//  Models.swift
+//  Runner
+//
+//  Created by Groot on 2025/5/9.
+//
+
+import Foundation
+import MapKit
+
+extension Decodable {
+    static func fromJson(json: [String: Any]) -> Self? {
+        guard let data = try? JSONSerialization.data(withJSONObject: json, options: []) else {
+            return nil
+        }
+        return try? JSONDecoder().decode(Self.self, from: data)
+    }
+}
+
+extension Encodable {
+    func toJson() -> [String: Any] {
+        guard let data = try? JSONEncoder().encode(self) else {
+            return [:]
+        }
+        return try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
+    }
+}
+
+enum ATMapMarkerType: Int, CaseIterable {
+    case mine = 1
+    case friend = 2
+    case traceStartPoint = 3
+    case traceEndFriendPoint = 4
+    case traceEndMinePoint = 5
+}
+
+struct ATMapCameraPosition: Codable {
+    var latitude: CGFloat
+    var longitude: CGFloat
+    // 地图缩放比例,对应span
+    var zoom: CGFloat
+}
+
+class ATMapPolyline: NSObject, Codable {
+    var id: String = UUID().uuidString
+    var points: [CLLocationCoordinate2D]
+
+    var polyline: MKPolyline {
+        return MKPolyline(coordinates: points, count: points.count)
+    }
+
+    init(points: [CLLocationCoordinate2D]) {
+        self.points = points
+    }
+}
+
+class ATMapMarker: NSObject, Codable {
+    var id: String
+    var markerName: String
+    var latitude: CGFloat
+    var longitude: CGFloat
+    var isSelected: Bool
+}
+
+extension ATMapMarker: MKAnnotation {
+    var coordinate: CLLocationCoordinate2D {
+        return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
+    }
+}
+
+extension CLLocationCoordinate2D: Codable {
+    enum CodingKeys: String, CodingKey {
+        case latitude
+        case longitude
+    }
+    
+    public init(from decoder: Decoder) throws {
+        let container = try decoder.container(keyedBy: CodingKeys.self)
+        let latitude = try container.decode(Double.self, forKey: .latitude)
+        let longitude = try container.decode(Double.self, forKey: .longitude)
+        self.init(latitude: latitude, longitude: longitude)
+    }
+    
+    public func encode(to encoder: Encoder) throws {
+        var container = encoder.container(keyedBy: CodingKeys.self)
+        try container.encode(latitude, forKey: .latitude)
+        try container.encode(longitude, forKey: .longitude)
+    }
+}

+ 112 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/ViewModel/MapViewModel.swift

@@ -0,0 +1,112 @@
+//
+//  MapViewModel.swift
+//  Runner
+//
+//  Created by Groot on 2025/5/7.
+//
+
+import Flutter
+import Foundation
+import MapKit
+import CoreLocation
+import SwiftUI
+import Combine
+
+private let coordinates: [CLLocationCoordinate2D] = [
+    CLLocationCoordinate2D(latitude: 39.90333, longitude: 116.39167), // 北京
+    CLLocationCoordinate2D(latitude: 31.23170, longitude: 121.47264), // 上海
+    CLLocationCoordinate2D(latitude: 22.54554, longitude: 114.05786), // 深圳
+    CLLocationCoordinate2D(latitude: 23.12911, longitude: 113.26437), // 广州
+    CLLocationCoordinate2D(latitude: 30.59276, longitude: 114.30525), // 武汉
+]
+
+class MapViewModel: NSObject, ObservableObject, MapCapability {
+
+    var paramsDecodeError: FlutterError? = FlutterError(code: "InvalidArguments", message: "Invalid arguments", details: nil)
+
+    var methodChannel: FlutterMethodChannel?
+
+    @Published var currentRegion: MKCoordinateRegion?
+    
+    // 记录用户位置
+    @Published var userLocation: CLLocationCoordinate2D?
+
+    // 地图Marker
+    @Published var markers: [ATMapMarker] = []
+    
+    // 地图Polyline
+    @Published var polylines: [ATMapPolyline] = []
+
+    // 处理地图移动
+    func handleMapMoveCamera(args: [String: Any]?, result: @escaping FlutterResult) {
+        guard let args = args, let cameraPosition = ATMapCameraPosition.fromJson(json: args) else {
+            result(paramsDecodeError)
+            return
+        }
+        
+        let center = CLLocationCoordinate2D(latitude: cameraPosition.latitude, longitude: cameraPosition.longitude)
+        let span = MKCoordinateSpan(latitudeDelta: cameraPosition.zoom, longitudeDelta: cameraPosition.zoom)
+        
+        currentRegion = MKCoordinateRegion(center: center, span: span)
+        result(nil)
+    }
+
+    // 处理地图添加Marker
+    func handleMapAddMarker(args: [String: Any]?, result: @escaping FlutterResult) {
+        guard let args = args, let marker = ATMapMarker.fromJson(json: args) else {
+            result(paramsDecodeError)
+            return
+        }
+
+        markers.append(marker)
+        result(nil)
+    }
+
+    // 处理地图清除Marker
+    func handleMapClearMarkers(result: @escaping FlutterResult) {
+        markers = []
+        result(nil)
+    }
+
+    // 处理地图替换所有Marker
+    // Combine 执行替换前的清除操作
+    func handleMapReplaceAllMarkers(args: [String: Any]?, result: @escaping FlutterResult) {
+        defer {
+            result(nil)
+        }
+        guard let args = args, let markers = args["markers"] as? [[String: Any]] else {
+            result(paramsDecodeError)
+            return
+        }
+
+        let mapMarkers = markers.compactMap({ ATMapMarker.fromJson(json: $0) })
+
+        self.markers = mapMarkers
+    }
+
+    // 处理Marker点击事件
+    func handleMarkerTap(marker: inout ATMapMarker) {
+        toggleMarkerSelected(marker: &marker)
+        methodChannel?.invokeMethod(ChannelMethods.methodMarkerOnTap.rawValue, arguments: marker.toJson())
+    }
+
+    // 处理地图添加Polyline
+    func handleMapAddPolyline(args: [String: Any]?, result: @escaping FlutterResult) {
+        guard let args = args, let pointsArray = args["points"] as? [[String: Any]] else {
+            result(paramsDecodeError)
+            return
+        }
+        let coordinates = pointsArray.compactMap({ CLLocationCoordinate2D.fromJson(json: $0) })
+        let polyline = ATMapPolyline(points: coordinates)
+        polylines.append(polyline)
+
+        result(nil)
+    }
+}   
+
+// Propertie Action
+extension MapViewModel {
+    func toggleMarkerSelected(marker: inout ATMapMarker) {
+        marker.isSelected = !marker.isSelected
+    }
+}

+ 86 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/Views/MapAnnotationView.swift

@@ -0,0 +1,86 @@
+//
+//  MapAnnotationView.swift
+//  Runner
+//
+//  Created by Groot on 2025/5/9.
+//
+
+import UIKit
+import MapKit
+
+class MapAnnotationView: MKAnnotationView {
+    
+    static let identifier: String = "MapAnnotationView"
+
+    var marker: ATMapMarker?
+    private let imageView = UIImageView()
+    
+    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
+        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
+        self.marker = annotation as? ATMapMarker
+        
+        // 确保视图可见
+        self.canShowCallout = false
+        self.isEnabled = true
+        self.isHidden = false
+        
+        setupImageView()
+    }
+
+    required init?(coder aDecoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    private func setupImageView() {
+        // 设置默认图像
+        let defaultImage = UIImage()
+        imageView.image = defaultImage
+        imageView.contentMode = .scaleAspectFit
+        
+        // 添加图像视图到注释视图
+        addSubview(imageView)
+        
+        // 设置图像视图的大小和位置
+        imageView.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
+        
+        // 设置注释视图的大小
+        self.frame = imageView.frame
+        
+        // 设置注释视图的中心点偏移
+        self.centerOffset = CGPoint(x: 0, y: -imageView.frame.height / 2)
+    }
+    
+    override func prepareForDisplay() {
+        super.prepareForDisplay()
+        
+        // 根据标记状态更新图像
+        updateImage()
+    }
+    
+    private func updateImage() {
+        // 使用已有的图像资源,而不是不存在的 marker_selected 和 marker_default
+        let defaultImage = UIImage()
+        imageView.image = defaultImage
+        
+        // 如果被选中,可以修改图像视图的外观
+        if let isSelected = marker?.isSelected, isSelected {
+            imageView.layer.borderWidth = 2.0
+            imageView.layer.borderColor = UIColor.blue.cgColor
+            imageView.layer.cornerRadius = imageView.frame.width / 2
+        } else {
+            imageView.layer.borderWidth = 0
+        }
+    }
+
+    override func setSelected(_ selected: Bool, animated: Bool) {
+        super.setSelected(selected, animated: animated)
+        if selected {
+            self.marker?.isSelected = true
+        } else {
+            self.marker?.isSelected = false
+        }
+        
+        // 更新图像以反映选中状态
+        updateImage()
+    }
+} 

+ 14 - 0
plugins/map_mapkit_ios/ios/Resources/PrivacyInfo.xcprivacy

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>NSPrivacyTrackingDomains</key>
+	<array/>
+	<key>NSPrivacyAccessedAPITypes</key>
+	<array/>
+	<key>NSPrivacyCollectedDataTypes</key>
+	<array/>
+	<key>NSPrivacyTracking</key>
+	<false/>
+</dict>
+</plist>

+ 29 - 0
plugins/map_mapkit_ios/ios/map_mapkit_ios.podspec

@@ -0,0 +1,29 @@
+#
+# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
+# Run `pod lib lint map_mapkit_ios.podspec` to validate before publishing.
+#
+Pod::Spec.new do |s|
+  s.name             = 'map_mapkit_ios'
+  s.version          = '0.0.1'
+  s.summary          = 'A new Flutter plugin project.'
+  s.description      = <<-DESC
+A new Flutter plugin project.
+                       DESC
+  s.homepage         = 'http://example.com'
+  s.license          = { :file => '../LICENSE' }
+  s.author           = { 'Your Company' => 'email@example.com' }
+  s.source           = { :path => '.' }
+  s.source_files = 'Classes/**/*'
+  s.dependency 'Flutter'
+  s.platform = :ios, '13.0'
+
+  # Flutter.framework does not contain a i386 slice.
+  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
+  s.swift_version = '5.0'
+
+  # If your plugin requires a privacy manifest, for example if it uses any
+  # required reason APIs, update the PrivacyInfo.xcprivacy file to describe your
+  # plugin's privacy impact, and then uncomment this line. For more information,
+  # see https://developer.apple.com/documentation/bundleresources/privacy_manifest_files
+  # s.resource_bundles = {'map_mapkit_ios_privacy' => ['Resources/PrivacyInfo.xcprivacy']}
+end

+ 69 - 0
plugins/map_mapkit_ios/pubspec.yaml

@@ -0,0 +1,69 @@
+name: map_mapkit_ios
+description: "A new Flutter plugin project."
+version: 0.0.1
+homepage:
+
+environment:
+  sdk: ^3.7.2
+  flutter: '>=3.3.0'
+
+dependencies:
+  flutter:
+    sdk: flutter
+  plugin_platform_interface: ^2.0.2
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
+  flutter_lints: ^5.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+  # This section identifies this Flutter project as a plugin project.
+  # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.)
+  # which should be registered in the plugin registry. This is required for
+  # using method channels.
+  # The Android 'package' specifies package in which the registered class is.
+  # This is required for using method channels on Android.
+  # The 'ffiPlugin' specifies that native code should be built and bundled.
+  # This is required for using `dart:ffi`.
+  # All these are used by the tooling to maintain consistency when
+  # adding or updating assets for this project.
+  plugin:
+    platforms:
+      ios:
+        pluginClass: MapMapkitIosPlugin
+        minimumOsVersion: 13.0
+  # To add assets to your plugin package, add an assets section, like this:
+  # assets:
+  #   - images/a_dot_burr.jpeg
+  #   - images/a_dot_ham.jpeg
+  #
+  # For details regarding assets in packages, see
+  # https://flutter.dev/to/asset-from-package
+  #
+  # An image asset can refer to one or more resolution-specific "variants", see
+  # https://flutter.dev/to/resolution-aware-images
+
+  # To add custom fonts to your plugin package, add a fonts section here,
+  # in this "flutter" section. Each entry in this list should have a
+  # "family" key with the font family name, and a "fonts" key with a
+  # list giving the asset and other descriptors for the font. For
+  # example:
+  # fonts:
+  #   - family: Schyler
+  #     fonts:
+  #       - asset: fonts/Schyler-Regular.ttf
+  #       - asset: fonts/Schyler-Italic.ttf
+  #         style: italic
+  #   - family: Trajan Pro
+  #     fonts:
+  #       - asset: fonts/TrajanPro.ttf
+  #       - asset: fonts/TrajanPro_Bold.ttf
+  #         weight: 700
+  #
+  # For details regarding fonts in packages, see
+  # https://flutter.dev/to/font-from-package

+ 2 - 3
pubspec.yaml

@@ -129,9 +129,8 @@ dependencies:
   map_amap_android:
     path: plugins/map_amap_android
 
-  ##iOS端
-  #  map_amap_ios:
-  #    path: plugins/map_amap_ios
+  map_mapkit_ios:
+    path: plugins/map_mapkit_ios
   ######################地图########################
 
   #日志打印