init project

This commit is contained in:
Kuloud
2023-12-22 21:23:24 +08:00
commit 1fb3d91106
461 changed files with 58770 additions and 0 deletions

View File

@ -0,0 +1,19 @@
//
// AMapFlutterFactory.h
// amap_map
//
// Created by lly on 2020/10/29.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapFlutterFactory : NSObject<FlutterPlatformViewFactory>
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,36 @@
//
// AMapFlutterFactory.m
// amap_map
//
// Created by lly on 2020/10/29.
//
#import "AMapFlutterFactory.h"
#import <MAMapKit/MAMapKit.h>
#import "AMapViewController.h"
@implementation AMapFlutterFactory {
NSObject<FlutterPluginRegistrar>* _registrar;
}
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
self = [super init];
if (self) {
_registrar = registrar;
}
return self;
}
- (NSObject<FlutterMessageCodec>*)createArgsCodec {
return [FlutterStandardMessageCodec sharedInstance];
}
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args {
return [[AMapViewController alloc] initWithFrame:frame
viewIdentifier:viewId
arguments:args
registrar:_registrar];
}
@end

View File

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
@interface AMapFlutterMapPlugin : NSObject<FlutterPlugin>
@end

View File

@ -0,0 +1,18 @@
#import "AMapFlutterMapPlugin.h"
#import "AMapFlutterFactory.h"
@implementation AMapFlutterMapPlugin{
NSObject<FlutterPluginRegistrar>* _registrar;
FlutterMethodChannel* _channel;
NSMutableDictionary* _mapControllers;
}
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
AMapFlutterFactory* aMapFactory = [[AMapFlutterFactory alloc] initWithRegistrar:registrar];
[registrar registerViewFactory:aMapFactory
withId:@"com.amap.flutter.map"
gestureRecognizersBlockingPolicy:
FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded];
}
@end

View File

@ -0,0 +1,23 @@
//
// AMapViewController.h
// amap_map
//
// Created by lly on 2020/10/29.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapViewController : NSObject<FlutterPlatformView>
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args
registrar:(NSObject<FlutterPluginRegistrar>*)registrar;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,499 @@
//
// AMapViewController.m
// amap_map
//
// Created by lly on 2020/10/29.
//
#import "AMapViewController.h"
#import "AMapJsonUtils.h"
#import "AMapCameraPosition.h"
#import "MAMapView+Flutter.h"
#import "MAAnnotationView+Flutter.h"
#import "AMapMarkerController.h"
#import "MAPointAnnotation+Flutter.h"
#import "AMapPolylineController.h"
#import "MAPolyline+Flutter.h"
#import "AMapPolyline.h"
#import "MAPolylineRenderer+Flutter.h"
#import <CoreLocation/CoreLocation.h>
#import "AMapPolygonController.h"
#import "MAPolygon+Flutter.h"
#import "MAPolygonRenderer+Flutter.h"
#import "AMapPolygon.h"
#import <AMapFoundationKit/AMapFoundationKit.h>
#import "AMapLocation.h"
#import "AMapJsonUtils.h"
#import "AMapConvertUtil.h"
#import "FlutterMethodChannel+MethodCallDispatch.h"
@interface AMapViewController ()<MAMapViewDelegate>
@property (nonatomic,strong) MAMapView *mapView;
@property (nonatomic,strong) FlutterMethodChannel *channel;
@property (nonatomic,assign) int64_t viewId;
@property (nonatomic,strong) NSObject<FlutterPluginRegistrar>* registrar;
@property (nonatomic,strong) AMapMarkerController *markerController;
@property (nonatomic,strong) AMapPolylineController *polylinesController;
@property (nonatomic,strong) AMapPolygonController *polygonsController;
@property (nonatomic,copy) FlutterResult waitForMapCallBack;//waitForMap使
@property (nonatomic,assign) BOOL mapInitCompleted;//
@property (nonatomic,assign) MAMapRect initLimitMapRect;//{0,0,0,0},
@end
@implementation AMapViewController
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
if (self = [super init]) {
NSAssert([args isKindOfClass:[NSDictionary class]], @"传参错误");
//methedChannel
NSString* channelName =
[NSString stringWithFormat:@"amap_map_%lld", viewId];
_channel = [FlutterMethodChannel methodChannelWithName:channelName
binaryMessenger:registrar.messenger];
NSDictionary *dict = args;
NSDictionary *apiKey = dict[@"apiKey"];
if (apiKey && [apiKey isKindOfClass:[NSDictionary class]]) {
NSString *iosKey = apiKey[@"iosKey"];
if (iosKey && iosKey.length > 0) {//flutterkeykey
[AMapServices sharedServices].apiKey = iosKey;
}
}
//key
NSAssert(([AMapServices sharedServices].apiKey != nil), @"没有设置APIKey请先设置key");
NSDictionary *cameraDict = [dict objectForKey:@"initialCameraPosition"];
AMapCameraPosition *cameraPosition = [AMapJsonUtils modelFromDict:cameraDict modelClass:[AMapCameraPosition class]];
_viewId = viewId;
if ([dict objectForKey:@"privacyStatement"] != nil) {
[self updatePrivacyStateWithDict:[dict objectForKey:@"privacyStatement"]];
}
self.mapInitCompleted = NO;
_mapView = [[MAMapView alloc] initWithFrame:frame];
if (_mapView == nil && (MAMapVersionNumber) >= 80100) {
NSAssert(_mapView,@"MAMapView初始化失败地图SDK8.1.0及以上请务必确保调用SDK任何接口前先调用更新隐私合规updatePrivacyShow:privacyInfo、updatePrivacyAgree两个接口");
}
_mapView.delegate = self;
_mapView.accessibilityElementsHidden = NO;
[_mapView setCameraPosition:cameraPosition animated:NO duration:0];
_registrar = registrar;
[self.mapView updateMapViewOption:[dict objectForKey:@"options"] withRegistrar:_registrar];
self.initLimitMapRect = [self getLimitMapRectFromOption:[dict objectForKey:@"options"]];
if (MAMapRectIsEmpty(self.initLimitMapRect) == NO) {//KVO
[_mapView addObserver:self forKeyPath:@"frame" options:0 context:nil];
}
_markerController = [[AMapMarkerController alloc] init:_channel
mapView:_mapView
registrar:registrar];
_polylinesController = [[AMapPolylineController alloc] init:_channel
mapView:_mapView
registrar:registrar];
_polygonsController = [[AMapPolygonController alloc] init:_channel
mapView:_mapView
registrar:registrar];
id markersToAdd = args[@"markersToAdd"];
if ([markersToAdd isKindOfClass:[NSArray class]]) {
[_markerController addMarkers:markersToAdd];
}
id polylinesToAdd = args[@"polylinesToAdd"];
if ([polylinesToAdd isKindOfClass:[NSArray class]]) {
[_polylinesController addPolylines:polylinesToAdd];
}
id polygonsToAdd = args[@"polygonsToAdd"];
if ([polygonsToAdd isKindOfClass:[NSArray class]]) {
[_polygonsController addPolygons:polygonsToAdd];
}
[self setMethodCallHandler];
}
return self;
}
- (UIView*)view {
return _mapView;
}
- (void)dealloc {
if (MAMapRectIsEmpty(_initLimitMapRect) == NO) {//frame
[_mapView removeObserver:self forKeyPath:@"frame"];
}
}
- (void)updatePrivacyStateWithDict:(NSDictionary *)dict {
if ((MAMapVersionNumber) < 80100) {
NSLog(@"当前地图SDK版本没有隐私合规接口请升级地图SDK到8.1.0及以上版本");
return;
}
if (dict == nil || [dict isKindOfClass:[NSDictionary class]] == NO) {
return;
}
if (dict[@"hasContains"] != nil && dict[@"hasShow"] != nil) {
[MAMapView updatePrivacyShow:[dict[@"hasShow"] integerValue] privacyInfo:[dict[@"hasContains"] integerValue]];
}
if (dict[@"hasAgree"] != nil) {
[MAMapView updatePrivacyAgree:[dict[@"hasAgree"] integerValue]];
}
}
- (MAMapRect)getLimitMapRectFromOption:(NSDictionary *)dict {
NSArray *limitBounds = dict[@"limitBounds"];
if (limitBounds) {
return [AMapConvertUtil mapRectFromArray:limitBounds];
} else {
return MAMapRectMake(0, 0, 0, 0);
}
}
- (void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context {
if (MAMapRectIsEmpty(self.initLimitMapRect) == YES ) {//frame
[_mapView removeObserver:self forKeyPath:@"frame"];
return;
}
if (object == _mapView && [keyPath isEqualToString:@"frame"]) {
CGRect bounds = _mapView.bounds;
if (CGRectEqualToRect(bounds, CGRectZero)) {
// frame0frame0limitRect
return;
}
//KVO
[_mapView removeObserver:self forKeyPath:@"frame"];
if (MAMapRectIsEmpty(self.initLimitMapRect) == NO) {
//0.1sframe
MAMapRect tempLimitMapRect = self.initLimitMapRect;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.mapView.limitMapRect = tempLimitMapRect;
});
//KVO
self.initLimitMapRect = MAMapRectMake(0, 0, 0, 0);
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)setMethodCallHandler {
__weak __typeof__(self) weakSelf = self;
[self.channel addMethodName:@"map#update" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
[weakSelf.mapView updateMapViewOption:call.arguments[@"options"] withRegistrar:weakSelf.registrar];
result(nil);
}];
[self.channel addMethodName:@"map#waitForMap" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
if (weakSelf.mapInitCompleted) {
result(nil);
} else {
weakSelf.waitForMapCallBack = result;
}
}];
[self.channel addMethodName:@"camera#move" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
[weakSelf.mapView setCameraUpdateDict:call.arguments];
result(nil);
}];
[self.channel addMethodName:@"map#takeSnapshot" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
[weakSelf.mapView takeSnapshotInRect:weakSelf.mapView.frame withCompletionBlock:^(UIImage *resultImage, NSInteger state) {
if (state == 1 && resultImage) {
NSData *data = UIImagePNGRepresentation(resultImage);
result([FlutterStandardTypedData typedDataWithBytes:data]);
} else if (state == 0) {
NSLog(@"takeSnapsShot 载入不完整");
}
}];
}];
[self.channel addMethodName:@"map#setRenderFps" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSInteger fps = [call.arguments[@"fps"] integerValue];
[weakSelf.mapView setMaxRenderFrame:fps];
result(nil);
}];
[self.channel addMethodName:@"map#contentApprovalNumber" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSString *approvalNumber = [weakSelf.mapView mapContentApprovalNumber];
result(approvalNumber);
}];
[self.channel addMethodName:@"map#satelliteImageApprovalNumber" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSString *sateApprovalNumber = [weakSelf.mapView satelliteImageApprovalNumber];
result(sateApprovalNumber);
}];
[self.channel addMethodName:@"map#clearDisk" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
[weakSelf.mapView clearDisk];
result(nil);
}];
}
//MARK: MAMapViewDelegate
//MARK:
- (void)mapView:(MAMapView *)mapView didChangeUserTrackingMode:(MAUserTrackingMode)mode animated:(BOOL)animated {
NSLog(@"%s,mapView:%@ mode:%ld",__func__,mapView,(long)mode);
}
/**
* @brief View
* @param mapView View
*/
- (void)mapViewWillStartLocatingUser:(MAMapView *)mapView {
NSLog(@"%s,mapView:%@",__func__,mapView);
}
/**
* @brief View
* @param mapView View
*/
- (void)mapViewDidStopLocatingUser:(MAMapView *)mapView {
NSLog(@"%s,mapView:%@",__func__,mapView);
}
/**
* @brief
* @param mapView View
* @param userLocation ()
* @param updatingLocation location, YES:location NO:heading
*/
- (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation {
if (updatingLocation && userLocation.location) {
AMapLocation *location = [[AMapLocation alloc] init];
[location updateWithUserLocation:userLocation.location];
NSDictionary *jsonObjc = [AMapJsonUtils jsonObjectFromModel:location];
NSArray *latlng = [AMapConvertUtil jsonArrayFromCoordinate:location.latLng];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:jsonObjc];
[dict setValue:latlng forKey:@"latLng"];
[_channel invokeMethod:@"location#changed" arguments:@{@"location" : dict}];
}
}
/**
* @brief plistNSLocationAlwaysUsageDescriptionNSLocationAlwaysAndWhenInUseUsageDescription[CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined
API [locationManager requestAlwaysAuthorization] ; since 6.8.0
* @param locationManager CLLocationManager
*/
- (void)mapViewRequireLocationAuth:(CLLocationManager *)locationManager {
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
[locationManager requestAlwaysAuthorization];
}
}
/**
* @brief
* @param mapView View
* @param error CLError.h
*/
- (void)mapView:(MAMapView *)mapView didFailToLocateUserWithError:(NSError *)error {
NSLog(@"%s,mapView:%@ error:%@",__func__,mapView,error);
}
/**
* @brief
* @param mapView View
*/
- (void)mapViewDidFinishLoadingMap:(MAMapView *)mapView {
NSLog(@"%s,mapView:%@",__func__,mapView);
}
- (void)mapInitComplete:(MAMapView *)mapView {
NSLog(@"%s,mapView:%@",__func__,mapView);
self.mapInitCompleted = YES;
if (self.waitForMapCallBack) {
self.waitForMapCallBack(nil);
self.waitForMapCallBack = nil;
}
}
//MARK: Annotation
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation {
if ([annotation isKindOfClass:[MAPointAnnotation class]] == NO) {
return nil;
}
MAPointAnnotation *fAnno = annotation;
if (fAnno.markerId == nil) {
return nil;
}
AMapMarker *marker = [_markerController markerForId:fAnno.markerId];
// TODO: AnnotationViewmarkerannotationViewpinAnnotationView
MAAnnotationView *view = [mapView dequeueReusableAnnotationViewWithIdentifier:AMapFlutterAnnotationViewIdentifier];
if (view == nil) {
view = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AMapFlutterAnnotationViewIdentifier];
}
[view updateViewWithMarker:marker];
return view;
}
/**
* @brief mapViewannotation views
* @param mapView View
* @param views annotation views
*/
- (void)mapView:(MAMapView *)mapView didAddAnnotationViews:(NSArray *)views {
for (MAAnnotationView *view in views) {
if ([view.annotation isKindOfClass:[MAAnnotationView class]] == NO) {
return;
}
MAPointAnnotation *fAnno = view.annotation;
if (fAnno.markerId == nil) {
return;
}
AMapMarker *marker = [_markerController markerForId:fAnno.markerId];
[view updateViewWithMarker:marker];
}
}
/**
* @brief viewcalloutview使calloutview
* @param mapView view
* @param view calloutViewannotationView
*/
//- (void)mapView:(MAMapView *)mapView didAnnotationViewCalloutTapped:(MAAnnotationView *)view {
// MAPointAnnotation *fAnno = view.annotation;
// if (fAnno.markerId == nil) {
// return;
// }
// [_markerController onInfoWindowTap:fAnno.markerId];
//}
/**
* @brief viewsince 5.7.0
* @param mapView view
* @param view annotationView
*/
- (void)mapView:(MAMapView *)mapView didAnnotationViewTapped:(MAAnnotationView *)view {
MAPointAnnotation *fAnno = view.annotation;
if (fAnno.markerId == nil) {
return;
}
[_markerController onMarkerTap:fAnno.markerId];
}
/**
* @brief annotation viewview
* @param mapView View
* @param view annotation view
* @param newState
* @param oldState
*/
- (void)mapView:(MAMapView *)mapView annotationView:(MAAnnotationView *)view didChangeDragState:(MAAnnotationViewDragState)newState
fromOldState:(MAAnnotationViewDragState)oldState {
if (newState == MAAnnotationViewDragStateEnding) {
MAPointAnnotation *fAnno = view.annotation;
if (fAnno.markerId == nil) {
return;
}
[_markerController onMarker:fAnno.markerId endPostion:fAnno.coordinate];
}
}
/**
* @brief overlayRenderer
* @param mapView View
* @param overlay overlay
* @return Renderer
*/
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id <MAOverlay>)overlay {
if ([overlay isKindOfClass:[MAPolyline class]]) {
MAPolyline *polyline = overlay;
if (polyline.polylineId == nil) {
return nil;
}
AMapPolyline *fPolyline = [_polylinesController polylineForId:polyline.polylineId];
MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:overlay];
[polylineRenderer updateRenderWithPolyline:fPolyline];
return polylineRenderer;
} else if ([overlay isKindOfClass:[MAPolygon class]]) {
MAPolygon *polygon = overlay;
if (polygon.polygonId == nil) {
return nil;
}
AMapPolygon *fPolygon = [_polygonsController polygonForId:polygon.polygonId];
MAPolygonRenderer *polygonRenderer = [[MAPolygonRenderer alloc] initWithPolygon:polygon];
[polygonRenderer updateRenderWithPolygon:fPolygon];
return polygonRenderer;
} else {
return nil;
}
}
/**
* @brief
* @param mapView View
* @param coordinate
*/
- (void)mapView:(MAMapView *)mapView didSingleTappedAtCoordinate:(CLLocationCoordinate2D)coordinate {
NSArray *latLng = [AMapConvertUtil jsonArrayFromCoordinate:coordinate];
[_channel invokeMethod:@"map#onTap" arguments:@{@"latLng":latLng}];
NSArray *polylineRenderArray = [mapView getHittedPolylinesWith:coordinate traverseAll:NO];
if (polylineRenderArray && polylineRenderArray.count > 0) {
MAOverlayRenderer *render = polylineRenderArray.firstObject;
MAPolyline *polyline = render.overlay;
if (polyline.polylineId) {
[_polylinesController onPolylineTap:polyline.polylineId];
}
}
}
/**
* @brief
* @param mapView View
* @param coordinate
*/
- (void)mapView:(MAMapView *)mapView didLongPressedAtCoordinate:(CLLocationCoordinate2D)coordinate {
NSArray *latLng = [AMapConvertUtil jsonArrayFromCoordinate:coordinate];
[_channel invokeMethod:@"map#onLongPress" arguments:@{@"latLng":latLng}];
}
/**
* @brief touchPOIEnabled == YES使POI
* @param mapView View
* @param pois poi(MATouchPoi)
*/
- (void)mapView:(MAMapView *)mapView didTouchPois:(NSArray *)pois {
MATouchPoi *poi = pois.firstObject;
NSDictionary *dict = [AMapConvertUtil dictFromTouchPOI:poi];
if (dict) {
[_channel invokeMethod:@"map#onPoiTouched" arguments:@{@"poi":dict}];
}
}
/**
* @brief since 4.6.0
* @param mapView View
*/
- (void)mapViewRegionChanged:(MAMapView *)mapView {
// TODO: channel
AMapCameraPosition *cameraPos = [mapView getCurrentCameraPosition];
NSDictionary *dict = [cameraPos toDictionary];
if (dict) {
[_channel invokeMethod:@"camera#onMove" arguments:@{@"position":dict}];
}
}
/**
* @brief
* @param mapView View
* @param animated
*/
- (void)mapView:(MAMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
AMapCameraPosition *cameraPos = [mapView getCurrentCameraPosition];
NSDictionary *dict = [cameraPos toDictionary];
if (dict) {
[_channel invokeMethod:@"camera#onMoveEnd" arguments:@{@"position":dict}];
}
}
@end

View File

@ -0,0 +1,32 @@
//
// FlutterMethodChannel+MethodCallDispatch.h
// amap_map
//
// Created by lly on 2020/11/16.
//
#import <Flutter/Flutter.h>
#import "AMapMethodCallDispatcher.h"
NS_ASSUME_NONNULL_BEGIN
@interface FlutterMethodChannel (MethodCallDispatch)
@property (nonatomic,strong,readonly) AMapMethodCallDispatcher* methodCallDispatcher;
/// 添加methodCall的回调注意使用该方法之后就不能再调用setMethodCallHandler: 方法了)
/// @param methodName methodName对应call的唯一方法名
/// @param handler 回调处理
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler;
/// 移除methodCall对应的回调
/// @param methodName 唯一的方法名
- (void)removeHandlerWithMethodName:(NSString *)methodName;
/// 清空所有的handler
- (void)clearAllHandler;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,42 @@
//
// FlutterMethodChannel+MethodCallDispatch.m
// amap_map
//
// Created by lly on 2020/11/16.
//
#import "FlutterMethodChannel+MethodCallDispatch.h"
#import <objc/runtime.h>
@implementation FlutterMethodChannel (MethodCallDispatch)
- (AMapMethodCallDispatcher *)methodCallDispatcher {
return objc_getAssociatedObject(self, @selector(methodCallDispatcher));
}
- (void)setMethodCallDispatcher:(AMapMethodCallDispatcher *)dispatcher {
objc_setAssociatedObject(self, @selector(methodCallDispatcher), dispatcher, OBJC_ASSOCIATION_RETAIN);
}
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler {
if (self.methodCallDispatcher == nil) {
self.methodCallDispatcher = [[AMapMethodCallDispatcher alloc] init];
__weak typeof(self) weakSelf = self;
[self setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
if (weakSelf.methodCallDispatcher) {
[weakSelf.methodCallDispatcher onMethodCall:call result:result];
}
}];
}
[self.methodCallDispatcher addMethodName:methodName withHandler:handler];
}
- (void)removeHandlerWithMethodName:(NSString *)methodName {
[self.methodCallDispatcher removeHandlerWithMethodName:methodName];
}
- (void)clearAllHandler {
[self.methodCallDispatcher clearAllHandler];
}
@end

View File

@ -0,0 +1,20 @@
//
// MAAnnotationView+Flutter.h
// amap_map
//
// Created by lly on 2020/11/5.
//
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AMapMarker;
@interface MAAnnotationView (Flutter)
- (void)updateViewWithMarker:(AMapMarker *)marker;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,40 @@
//
// MAAnnotationView+Flutter.m
// amap_map
//
// Created by lly on 2020/11/5.
//
#import "MAAnnotationView+Flutter.h"
#import "AMapMarker.h"
#import "AMapInfoWindow.h"
@implementation MAAnnotationView (Flutter)
- (void)updateViewWithMarker:(AMapMarker *)marker {
if (marker == nil) {
return;
}
self.alpha = marker.alpha;
self.image = marker.image;
//anchorcenterOffset
if (self.image) {
CGSize imageSize = self.image.size;
//iOSannotationViewannotation,0.50.5
CGFloat offsetW = imageSize.width * (0.5 - marker.anchor.x);
CGFloat offsetH = imageSize.height * (0.5 - marker.anchor.y);
self.centerOffset = CGPointMake(offsetW, offsetH);
}
self.enabled = marker.clickable;
self.draggable = marker.draggable;
// marker.flat;//flatiOS
self.canShowCallout = marker.infoWindowEnable;
// TODO: iOScalloutOffset
// self.calloutOffset = marker.infoWindow.anchor;
//
self.imageView.transform = CGAffineTransformMakeRotation(marker.rotation / 180.f * M_PI);
self.hidden = (!marker.visible);
self.zIndex = marker.zIndex;
}
@end

View File

@ -0,0 +1,30 @@
//
// MAMapView+Flutter.h
// amap_map
//
// Created by lly on 2020/10/30.
//
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AMapCameraPosition;
@class AMapOption;
@protocol FlutterPluginRegistrar;
@interface MAMapView (Flutter)
- (void)setCameraPosition:(AMapCameraPosition *)cameraPosition animated:(BOOL)animated duration:(CFTimeInterval)duration;
/// 获取地图的当前cameraPostion
- (AMapCameraPosition *)getCurrentCameraPosition;
/// 地图camera更新操作
- (void)setCameraUpdateDict:(NSDictionary *)updateDict;
- (void)updateMapViewOption:(NSDictionary *)dict withRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,222 @@
//
// MAMapView+Flutter.m
// amap_map
//
// Created by lly on 2020/10/30.
//
#import "MAMapView+Flutter.h"
#import "AMapCameraPosition.h"
#import "AMapConvertUtil.h"
#import "AMapJsonUtils.h"
#import <Flutter/Flutter.h>
@implementation MAMapView (Flutter)
- (void)setCameraPosition:(AMapCameraPosition *)cameraPosition animated:(BOOL)animated duration:(CFTimeInterval)duration {
if (cameraPosition == nil) {
return;
}
MAMapStatus *mapStatus = [MAMapStatus statusWithCenterCoordinate:cameraPosition.target
zoomLevel:cameraPosition.zoom
rotationDegree:cameraPosition.bearing
cameraDegree:cameraPosition.tilt
screenAnchor:self.screenAnchor];
[self setMapStatus:mapStatus animated:animated duration:duration];
}
- (AMapCameraPosition *)getCurrentCameraPosition {
AMapCameraPosition *position = [[AMapCameraPosition alloc] init];
position.target = self.centerCoordinate;
position.zoom = self.zoomLevel;
position.bearing = self.rotationDegree;
position.tilt = self.cameraDegree;
return position;
}
- (void)setCameraUpdateDict:(NSDictionary *)updateDict {
if (updateDict == nil || updateDict.count == 0) {
return;
}
BOOL animated;
if ([updateDict[@"animated"] isKindOfClass:[NSNull class]]) {
animated = NO;
} else {
animated = [updateDict[@"animated"] boolValue];
}
double duration;
if ([updateDict[@"duration"] isKindOfClass:[NSNull class]]) {
duration = 0;
} else {
duration = [updateDict[@"duration"] doubleValue]/1000.0;
}
NSArray *cameraUpdate = updateDict[@"cameraUpdate"];
//
NSAssert(cameraUpdate.count >= 1, @"cameraUpdate 参数错误");
NSString *operation = cameraUpdate.firstObject;
if ([operation isEqualToString:@"newCameraPosition"] && cameraUpdate.count == 2) {//cameraPositon
AMapCameraPosition *newCameraPosition = [AMapJsonUtils modelFromDict:cameraUpdate[1] modelClass:[AMapCameraPosition class]];
[self setCameraPosition:newCameraPosition animated:animated duration:duration];
} else if ([operation isEqualToString:@"newLatLng"] && cameraUpdate.count == 2) {//
CLLocationCoordinate2D position = [AMapConvertUtil coordinateFromArray:cameraUpdate[1]];
MAMapStatus *currentStatus = [self getMapStatus];
currentStatus.centerCoordinate = position;
[self setMapStatus:currentStatus animated:animated duration:duration];
} else if ([operation isEqualToString:@"newLatLngBounds"] && cameraUpdate.count == 3) {//
// TODO: 使duration
MAMapRect boundRect = [AMapConvertUtil mapRectFromArray:cameraUpdate[1]];
double padding = [cameraUpdate[2] doubleValue];
UIEdgeInsets inset = UIEdgeInsetsMake(padding, padding, padding, padding);
[self setVisibleMapRect:boundRect edgePadding:inset animated:animated];
} else if ([operation isEqualToString:@"newLatLngZoom"] && cameraUpdate.count == 3) {//zoomLevel
CLLocationCoordinate2D position = [AMapConvertUtil coordinateFromArray:cameraUpdate[1]];
CGFloat zoomLevel = [cameraUpdate[2] floatValue];
MAMapStatus *currentStatus = [self getMapStatus];
currentStatus.centerCoordinate = position;
currentStatus.zoomLevel = zoomLevel;
[self setMapStatus:currentStatus animated:animated duration:duration];
} else if ([operation isEqualToString:@"scrollBy"] && cameraUpdate.count == 3) {//
CGPoint pixelPointOffset = CGPointMake([cameraUpdate[1] doubleValue], [cameraUpdate[2] doubleValue]);
CGPoint updateCenter = CGPointMake(self.center.x + pixelPointOffset.x/[UIScreen mainScreen].scale, self.center.y + pixelPointOffset.y/[UIScreen mainScreen].scale);
CLLocationCoordinate2D centerCoord = [self convertPoint:updateCenter toCoordinateFromView:self];
MAMapStatus *currentStatus = [self getMapStatus];
currentStatus.centerCoordinate = centerCoord;
[self setMapStatus:currentStatus animated:animated duration:duration];
} else if ([operation isEqualToString:@"zoomIn"]) {
MAMapStatus *currentStatus = [self getMapStatus];
currentStatus.zoomLevel = currentStatus.zoomLevel + 1;
[self setMapStatus:currentStatus animated:animated duration:duration];
} else if ([operation isEqualToString:@"zoomOut"]) {
MAMapStatus *currentStatus = [self getMapStatus];
currentStatus.zoomLevel = currentStatus.zoomLevel - 1;
[self setMapStatus:currentStatus animated:animated duration:duration];
} else if ([operation isEqualToString:@"zoomTo"] && cameraUpdate.count == 2) {
MAMapStatus *currentStatus = [self getMapStatus];
currentStatus.zoomLevel = [cameraUpdate[1] doubleValue];
[self setMapStatus:currentStatus animated:animated duration:duration];
}
}
- (void)updateMapViewOption:(NSDictionary *)dict withRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
if ([dict isKindOfClass:[NSDictionary class]] == NO || dict == nil || dict.count == 0) {
return;
}
//
NSNumber *mapType = dict[@"mapType"];
if (mapType) {
self.mapType = mapType.integerValue;
}
NSDictionary *customStyleOptions = dict[@"customStyleOptions"];
if (customStyleOptions) {
BOOL customMapStyleEnabled = [customStyleOptions[@"enabled"] boolValue];
self.customMapStyleEnabled = customMapStyleEnabled;
if (customMapStyleEnabled) {
MAMapCustomStyleOptions *styleOption = [[MAMapCustomStyleOptions alloc] init];
styleOption.styleData = ((FlutterStandardTypedData*)customStyleOptions[@"styleData"]).data;
styleOption.styleExtraData = ((FlutterStandardTypedData*)customStyleOptions[@"styleExtraData"]).data;
[self setCustomMapStyleOptions:styleOption];
}
}
NSDictionary *locationStyleDict = dict[@"myLocationStyle"];
if (locationStyleDict) {
BOOL showUserLocation = [locationStyleDict[@"enabled"] boolValue];
self.showsUserLocation = showUserLocation;
if (showUserLocation) {
self.userTrackingMode = MAUserTrackingModeNone;//demo使
if (locationStyleDict[@"circleFillColor"] != nil
|| locationStyleDict[@"circleStrokeColor"] != nil
|| locationStyleDict[@"circleStrokeWidth"] != nil
|| locationStyleDict[@"icon"] != nil) {//
MAUserLocationRepresentation *locationStyle = [[MAUserLocationRepresentation alloc] init];
if (locationStyleDict[@"circleFillColor"]) {
locationStyle.fillColor = [AMapConvertUtil colorFromNumber:locationStyleDict[@"circleFillColor"]];
}
if (locationStyleDict[@"circleStrokeColor"]) {
locationStyle.strokeColor = [AMapConvertUtil colorFromNumber:locationStyleDict[@"circleStrokeColor"]];
}
if (locationStyleDict[@"circleStrokeWidth"]) {
locationStyle.lineWidth = [locationStyleDict[@"circleStrokeWidth"] doubleValue];
}
if (locationStyleDict[@"icon"]) {
locationStyle.image = [AMapConvertUtil imageFromRegistrar:registrar iconData:locationStyleDict[@"icon"]];
}
[self updateUserLocationRepresentation:locationStyle];
}
}
}
///
NSArray *screenAnchor = dict[@"screenAnchor"];
if (screenAnchor) {
CGPoint anchorPoint = [AMapConvertUtil pointFromArray:screenAnchor];
self.screenAnchor = anchorPoint;
}
//
NSArray* zoomData = dict[@"minMaxZoomPreference"];
if (zoomData) {
CGFloat minZoom = (zoomData[0] == [NSNull null]) ? 3.0 : [zoomData[0] doubleValue];
self.minZoomLevel = minZoom;
CGFloat maxZoom = (zoomData[1] == [NSNull null]) ? 20.0 : [zoomData[1] doubleValue];
self.maxZoomLevel = maxZoom;
}
NSArray *limitBounds = dict[@"limitBounds"];
if (limitBounds) {
MAMapRect limitRect = [AMapConvertUtil mapRectFromArray:limitBounds];
self.limitMapRect = limitRect;
}
//
NSNumber *showTraffic = dict[@"trafficEnabled"];
if (showTraffic) {
self.showTraffic = [showTraffic boolValue];
}
// poi
NSNumber *touchPOIEnable = dict[@"touchPoiEnabled"];
if (touchPOIEnable) {
self.touchPOIEnabled = [touchPOIEnable boolValue];
}
//3D
NSNumber *showBuilding = dict[@"buildingsEnabled"];
if (showBuilding) {
self.showsBuildings = [showBuilding boolValue];
}
//
NSNumber *showLable = dict[@"labelsEnabled"];
if (showLable) {
self.showsLabels = [showLable boolValue];
}
//
NSNumber *showCompass = dict[@"compassEnabled"];
if (showCompass) {
self.showsCompass = [showCompass boolValue];
}
//
NSNumber *showScale = dict[@"scaleEnabled"];
if (showScale) {
self.showsScale = [showScale boolValue];
}
//
NSNumber *zoomEnable = dict[@"zoomGesturesEnabled"];
if (zoomEnable) {
self.zoomEnabled = [zoomEnable boolValue];
}
//
NSNumber *scrollEnable = dict[@"scrollGesturesEnabled"];
if (scrollEnable) {
self.scrollEnabled = [scrollEnable boolValue];
}
//
NSNumber *rotateEnable = dict[@"rotateGesturesEnabled"];
if (rotateEnable) {
self.rotateEnabled = [rotateEnable boolValue];
}
//
NSNumber *rotateCameraEnable = dict[@"tiltGesturesEnabled"];
if (rotateCameraEnable) {
self.rotateCameraEnabled = [rotateCameraEnable boolValue];
}
}
@end

View File

@ -0,0 +1,29 @@
//
// MAPointAnnotation+Flutter.h
// amap_map
//
// Created by lly on 2020/11/9.
//
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
/// AnnotationView的复用标识
extern NSString *const AMapFlutterAnnotationViewIdentifier;
/// 该拓展类型主要用于对地图原PointAnnotation添加一个唯一id,
/// 便于在地图回调代理中通过id快速找到对应的AMapMarker对象
/// 以此来构建对应的MAAnnotatioView
@interface MAPointAnnotation (Flutter)
//为Annotation拓展存储的flutter传入的markerId,便于快速查找对应的marker数据
@property (nullable,nonatomic,copy,readonly) NSString *markerId;
/// 使用MarkerId初始化对应的Annotation
/// @param markerId marker的唯一标识
- (instancetype)initWithMarkerId:(NSString *)markerId;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,31 @@
//
// MAPointAnnotation+Flutter.m
// amap_map
//
// Created by lly on 2020/11/9.
//
#import "MAPointAnnotation+Flutter.h"
#import <objc/runtime.h>
NSString *const AMapFlutterAnnotationViewIdentifier = @"AMapFlutterAnnotationViewIdentifier";
@implementation MAPointAnnotation (Flutter)
- (NSString *)markerId {
return objc_getAssociatedObject(self, @selector(markerId));
}
- (void)setMarkerId:(NSString * _Nonnull)markerId {
objc_setAssociatedObject(self, @selector(markerId), markerId, OBJC_ASSOCIATION_COPY);
}
- (instancetype)initWithMarkerId:(NSString *)markerId {
self = [super init];
if (self) {
self.markerId = markerId;
}
return self;
}
@end

View File

@ -0,0 +1,26 @@
//
// MAPolygon+Flutter.h
// amap_map
//
// Created by lly on 2020/11/12.
//
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
/// 该拓展类型主要用于对地图原MAPolygon添加一个唯一id,
/// 便于在地图回调代理中通过id快速找到对应的AMapPolyline对象
/// 以此来构建对应的polygonRender
@interface MAPolygon (Flutter)
@property (nonatomic,copy,readonly) NSString *polygonId;
/// 使用polygonId初始化对应的MAPolygon
/// @param polygonId polylgon的唯一标识
- (instancetype)initWithPolygonId:(NSString *)polygonId;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,29 @@
//
// MAPolygon+Flutter.m
// amap_map
//
// Created by lly on 2020/11/12.
//
#import "MAPolygon+Flutter.h"
#import <objc/runtime.h>
@implementation MAPolygon (Flutter)
- (NSString *)polygonId {
return objc_getAssociatedObject(self, @selector(polygonId));
}
- (void)setPolygonId:(NSString * _Nonnull)polygonId {
objc_setAssociatedObject(self, @selector(polygonId), polygonId, OBJC_ASSOCIATION_COPY);
}
- (instancetype)initWithPolygonId:(NSString *)polygonId {
self = [super init];
if (self) {
self.polygonId = polygonId;
}
return self;
}
@end

View File

@ -0,0 +1,20 @@
//
// MAPolygonRenderer+Flutter.h
// amap_map
//
// Created by lly on 2020/11/12.
//
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AMapPolygon;
@interface MAPolygonRenderer (Flutter)
- (void)updateRenderWithPolygon:(AMapPolygon *)polygon;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,26 @@
//
// MAPolygonRenderer+Flutter.m
// amap_map
//
// Created by lly on 2020/11/12.
//
#import "MAPolygonRenderer+Flutter.h"
#import "AMapPolygon.h"
@implementation MAPolygonRenderer (Flutter)
- (void)updateRenderWithPolygon:(AMapPolygon *)polygon {
self.lineWidth = polygon.strokeWidth;
self.strokeColor = polygon.strokeColor;
self.fillColor = polygon.fillColor;
self.lineJoinType = polygon.joinType;
if (polygon.visible) {
self.alpha = 1.0;
} else {
self.alpha = 0;
}
}
@end

View File

@ -0,0 +1,26 @@
//
// MAPolyline+Flutter.h
// amap_map
//
// Created by lly on 2020/11/9.
//
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
/// 该拓展类型主要用于对地图原MAPolyline添加一个唯一id,
/// 便于在地图回调代理中通过id快速找到对应的AMapPolyline对象
/// 以此来构建对应的polylineRender
@interface MAPolyline (Flutter)
@property (nonatomic,copy,readonly) NSString *polylineId;
/// 使用polylineId初始化对应的MAPolyline
/// @param polylineId polyline的唯一标识
- (instancetype)initWithPolylineId:(NSString *)polylineId;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,29 @@
//
// MAPolyline+Flutter.m
// amap_map
//
// Created by lly on 2020/11/9.
//
#import "MAPolyline+Flutter.h"
#import <objc/runtime.h>
@implementation MAPolyline (Flutter)
- (NSString *)polylineId {
return objc_getAssociatedObject(self, @selector(polylineId));
}
- (void)setPolylineId:(NSString * _Nonnull)polylineId {
objc_setAssociatedObject(self, @selector(polylineId), polylineId, OBJC_ASSOCIATION_COPY);
}
- (instancetype)initWithPolylineId:(NSString *)polylineId {
self = [super init];
if (self) {
self.polylineId = polylineId;
}
return self;
}
@end

View File

@ -0,0 +1,20 @@
//
// MAPolylineRenderer+Flutter.h
// amap_map
//
// Created by lly on 2020/11/7.
//
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AMapPolyline;
@interface MAPolylineRenderer (Flutter)
- (void)updateRenderWithPolyline:(AMapPolyline *)polyline;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,30 @@
//
// MAPolylineRenderer+Flutter.m
// amap_map
//
// Created by lly on 2020/11/7.
//
#import "MAPolylineRenderer+Flutter.h"
#import "AMapPolyline.h"
@implementation MAPolylineRenderer (Flutter)
- (void)updateRenderWithPolyline:(AMapPolyline *)polyline {
self.lineWidth = polyline.width;
self.strokeColor = polyline.color;
if (polyline.visible) {//
self.alpha = polyline.alpha;
} else {
self.alpha = 0;
}
if (polyline.strokeImage) {
self.strokeImage = polyline.strokeImage;
}
self.lineDashType = polyline.dashLineType;
self.lineJoinType = polyline.joinType;
self.lineCapType = polyline.capType;
self.userInteractionEnabled = YES;//
}
@end

View File

@ -0,0 +1,28 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
@class AMapCameraPosition;
NS_ASSUME_NONNULL_BEGIN
#pragma mark - Object interfaces
@interface AMapCameraPosition : NSObject
/// 可视区域指向的方向以角度为单位从正北向逆时针方向计算从0 度到360 度。
@property (nonatomic, assign) CGFloat bearing;
/// 目标位置的屏幕中心点经纬度坐标。
@property (nonatomic, assign) CLLocationCoordinate2D target;
/// 目标可视区域的倾斜度,以角度为单位。
@property (nonatomic, assign) CGFloat tilt;
/// 目标可视区域的缩放级别
@property (nonatomic, assign) CGFloat zoom;
- (NSDictionary *)toDictionary;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,21 @@
#import "AMapCameraPosition.h"
#import "AMapConvertUtil.h"
@implementation AMapCameraPosition
- (NSDictionary *)toDictionary {
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:4];
[dict setObject:@(self.bearing) forKey:@"bearing"];
[dict setObject:@(self.tilt) forKey:@"tilt"];
[dict setObject:@(self.zoom) forKey:@"zoom"];
if (CLLocationCoordinate2DIsValid(self.target)) {
[dict setObject:[AMapConvertUtil jsonArrayFromCoordinate:self.target] forKey:@"target"];
}
return [dict copy];
}
- (NSString *)description {
return [NSString stringWithFormat:@"CameraPosition(bearing:%.6f, target:%@, tilt:%.6f, zoom:%.6f)",self.bearing,[AMapConvertUtil stringFromCoordinate:self.target],self.tilt,self.zoom];
}
@end

View File

@ -0,0 +1,22 @@
//
// AMapInfoWindow.h
// amap_map
//
// Created by lly on 2020/11/3.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapInfoWindow : NSObject
@property (nonatomic, copy) NSString* title;
@property (nonatomic, copy) NSString* snippet;
@property (nonatomic, assign) CGPoint anchor;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,12 @@
//
// AMapInfoWindow.m
// amap_map
//
// Created by lly on 2020/11/3.
//
#import "AMapInfoWindow.h"
@implementation AMapInfoWindow
@end

View File

@ -0,0 +1,44 @@
//
// AMapLocation.h
// amap_map
//
// Created by lly on 2020/11/12.
//
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
@class MAUserLocation;
@interface AMapLocation : NSObject
///定位提供者
///
///iOS平台只会返回'iOS'
@property (nonatomic, copy) NSString *provider;
///经纬度
@property (nonatomic, assign) CLLocationCoordinate2D latLng;
///水平精确度
@property (nonatomic, assign) double accuracy;
///海拔
@property (nonatomic, assign) double altitude;
///角度
@property (nonatomic, assign) double bearing;
///速度
@property (nonatomic, assign) double speed;
///定位时间,单位:毫秒
@property (nonatomic, assign) double time;
- (void)updateWithUserLocation:(CLLocation *)location;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,32 @@
//
// AMapLocation.m
// amap_map
//
// Created by lly on 2020/11/12.
//
#import "AMapLocation.h"
@implementation AMapLocation
- (instancetype)init {
self = [super init];
if (self) {
self.provider = @"iOS";
}
return self;
}
- (void)updateWithUserLocation:(CLLocation *)location {
if (location == nil) {
return;
}
self.latLng = location.coordinate;
self.accuracy = location.horizontalAccuracy;
self.altitude = location.altitude;
self.bearing = location.course;
self.speed = location.speed;
self.time = [location.timestamp timeIntervalSince1970]*1000;
}
@end

View File

@ -0,0 +1,58 @@
//
// AMapMarker.h
// amap_map
//
// Created by lly on 2020/11/3.
//
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AMapInfoWindow;
@interface AMapMarker : NSObject
@property (nonatomic, copy) NSString *id_;
@property (nonatomic, assign) double alpha;
@property (nonatomic, assign) CGPoint anchor;
//原始的图片BitmapDescriptor的json存储结构
@property (nonatomic, copy) NSArray *icon;
//解析后的图片
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, assign) bool clickable;
@property (nonatomic, assign) bool draggable;
@property (nonatomic, assign) bool flat;
@property (nonatomic, assign) bool infoWindowEnable;
@property (nonatomic, strong) AMapInfoWindow *infoWindow;
@property (nonatomic, assign) CLLocationCoordinate2D position;
@property (nonatomic, assign) double rotation;
@property (nonatomic, assign) bool visible;
@property (nonatomic, assign) double zIndex;
//根据以上marker信息生成的对应的iOS端的Annotation
@property (nonatomic, strong, readonly) MAPointAnnotation *annotation;
/// 更新marker的信息
/// @param changedMarker 带修改信息的marker
- (void)updateMarker:(AMapMarker *)changedMarker;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,68 @@
//
// AMapMarker.m
// amap_map
//
// Created by lly on 2020/11/3.
//
#import "AMapMarker.h"
#import "AMapInfoWindow.h"
#import "MAPointAnnotation+Flutter.h"
@interface AMapMarker ()
@property (nonatomic, strong, readwrite) MAPointAnnotation *annotation;
@end
@implementation AMapMarker
- (instancetype)init {
self = [super init];
if (self) {
_alpha = 1.0;
_clickable = YES;
_draggable = NO;
_visible = YES;
}
return self;
}
- (MAPointAnnotation *)annotation {
if (_annotation == nil) {
NSAssert(self.id_ != nil, @"markerid不能为空");
_annotation = [[MAPointAnnotation alloc] initWithMarkerId:self.id_];
[self _updateAnnotation];
}
return _annotation;
}
/// marker
/// @param changedMarker marker
- (void)updateMarker:(AMapMarker *)changedMarker {
NSAssert((changedMarker != nil && [self.id_ isEqualToString:changedMarker.id_]), @"更新marker数据异常");
self.alpha = changedMarker.alpha;
self.anchor = changedMarker.anchor;
self.clickable = changedMarker.clickable;
self.draggable = changedMarker.draggable;
self.flat = changedMarker.flat;
self.infoWindowEnable = changedMarker.infoWindowEnable;
self.infoWindow = changedMarker.infoWindow;
self.position = changedMarker.position;
self.rotation = changedMarker.rotation;
self.visible = changedMarker.visible;
self.zIndex = changedMarker.zIndex;
if (_annotation) {//Annotation
[self _updateAnnotation];
}
}
- (void)_updateAnnotation {
_annotation.title = self.infoWindow.title;
_annotation.subtitle = self.infoWindow.snippet;
_annotation.coordinate = self.position;
}
@end

View File

@ -0,0 +1,44 @@
//
// AMapPolygon.h
// amap_map
//
// Created by lly on 2020/11/12.
//
#import <Foundation/Foundation.h>
#import <MAMapKit/MAMapKit.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapPolygon : NSObject{
/// 覆盖物的坐标点数组key为@"points"
CLLocationCoordinate2D *_coords;//坐标的数组指针
NSUInteger _coordCount;//坐标的个数
}
@property (nonatomic, copy) NSString *id_;
/// 边框宽度
@property (nonatomic, assign) CGFloat strokeWidth;
/// 边框颜色
@property (nonatomic, strong) UIColor *strokeColor;
/// 填充颜色
@property (nonatomic, strong) UIColor *fillColor;
/// 是否可见
@property (nonatomic, assign) bool visible;
/// 连接点类型
@property (nonatomic, assign) MALineJoinType joinType;
/// 由以上数据生成的polyline对象
@property (nonatomic, strong,readonly) MAPolygon *polygon;
- (void)updatePolygon:(AMapPolygon *)polygon;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,97 @@
//
// AMapPolygon.m
// amap_map
//
// Created by lly on 2020/11/12.
//
#import "AMapPolygon.h"
#import "AMapConvertUtil.h"
#import "MAPolygon+Flutter.h"
@interface AMapPolygon ()
@property (nonatomic, strong,readwrite) MAPolygon *polygon;
@end
@implementation AMapPolygon
- (instancetype)init {
self = [super init];
if (self) {
_visible = YES;
}
return self;
}
- (void)postHookWith:(NSDictionary *)dict {
NSArray *points = dict[@"points"];
NSAssert(points.count > 0, @"polygon传入的经纬度点有误");
//
if (_coords != NULL) {
free(_coords);
_coords = NULL;
}
_coordCount = points.count;
_coords = (CLLocationCoordinate2D*)malloc(_coordCount * sizeof(CLLocationCoordinate2D));
for (NSUInteger index = 0; index < _coordCount; index ++) {
NSArray *point = points[index];
_coords[index] = [AMapConvertUtil coordinateFromArray:point];
}
}
- (void)dealloc {
if (_coords != NULL) {
free(_coords);
_coords = NULL;
}
}
- (MAPolygon *)polygon {
if (_polygon == nil) {
_polygon = [[MAPolygon alloc] initWithPolygonId:self.id_];
[_polygon setPolygonWithCoordinates:_coords count:_coordCount];
}
return _polygon;
}
//polyline
- (void)updatePolygon:(AMapPolygon *)polygon {
NSAssert((polygon != nil && [self.id_ isEqualToString:polygon.id_]), @"更新AMapPolygon数据异常");
if ([self checkCoordsEqualWithPolyline:polygon] == NO) {//polyline
if (_coords != NULL) {
free(_coords);
_coords = NULL;
}
_coordCount = polygon->_coordCount;
_coords = (CLLocationCoordinate2D*)malloc(_coordCount * sizeof(CLLocationCoordinate2D));
for (NSUInteger index = 0; index < _coordCount; index ++) {
_coords[index] = polygon->_coords[index];
}
}
self.strokeWidth = polygon.strokeWidth;
self.strokeColor = polygon.strokeColor;
self.fillColor = polygon.fillColor;
self.visible = polygon.visible;
self.joinType = polygon.joinType;
if (_polygon) {
[_polygon setPolygonWithCoordinates:_coords count:_coordCount];
}
}
- (BOOL)checkCoordsEqualWithPolyline:(AMapPolygon *)newPolygon {
if (_coordCount != newPolygon->_coordCount) {//
return NO;
}
for (NSUInteger index = 0; index < _coordCount; index++) {
if ([AMapConvertUtil isEqualWith:_coords[index] to:newPolygon->_coords[index]] == NO) {
return NO;
}
}
return YES;
}
@end

View File

@ -0,0 +1,60 @@
//
// AMapPolyline.h
// amap_map
//
// Created by lly on 2020/11/6.
//
#import <Foundation/Foundation.h>
#import <MAMapKit/MAMapKit.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapPolyline : NSObject {
/// 覆盖物的坐标点数组key为@"points"
CLLocationCoordinate2D *_coords;//坐标的数组指针
NSUInteger _coordCount;//坐标的个数
}
@property (nonatomic, copy) NSString *id_;
/// 线宽
@property (nonatomic, assign) CGFloat width;
/// 覆盖物颜色,默认值为(0xCCC4E0F0).
@property (nonatomic, strong) UIColor *color;
/// 是否可见
@property (nonatomic, assign) bool visible;
/// 透明度
@property (nonatomic, assign) CGFloat alpha;
/// 自定义纹理图片
@property (nonatomic, copy) NSArray *customTexture;
/// 由customTexture解析生成的图片
@property (nonatomic, strong) UIImage *strokeImage;
/// 是否为大地曲线
@property (nonatomic, assign) BOOL geodesic;
/// 虚线类型
@property (nonatomic, assign) MALineDashType dashLineType;
/// 连接点类型
@property (nonatomic, assign) MALineJoinType joinType;
/// 线头类型
@property (nonatomic, assign) MALineCapType capType;
/// 由以上数据生成的polyline对象
@property (nonatomic, strong, readonly) MAPolyline *polyline;
//更新polyline
- (void)updatePolyline:(AMapPolyline *)polyline;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,104 @@
//
// AMapPolyline.m
// amap_map
//
// Created by lly on 2020/11/6.
//
#import "AMapPolyline.h"
#import "AMapConvertUtil.h"
#import "MAPolyline+Flutter.h"
@interface AMapPolyline ()
@property (nonatomic, strong, readwrite) MAPolyline *polyline;
@end
@implementation AMapPolyline
- (instancetype)init {
self = [super init];
if (self) {
_alpha = 1.0;
_visible = YES;
}
return self;
}
- (void)postHookWith:(NSDictionary *)dict {
NSArray *points = dict[@"points"];
NSAssert(points.count > 0, @"polyline传入的经纬度点有误");
//
if (_coords != NULL) {
free(_coords);
_coords = NULL;
}
_coordCount = points.count;
_coords = (CLLocationCoordinate2D*)malloc(_coordCount * sizeof(CLLocationCoordinate2D));
for (NSUInteger index = 0; index < _coordCount; index ++) {
NSArray *point = points[index];
_coords[index] = [AMapConvertUtil coordinateFromArray:point];
}
}
- (MAPolyline *)polyline {
if (_polyline == nil) {
if (self.geodesic) {//线使
_polyline = [[MAGeodesicPolyline alloc] initWithPolylineId:self.id_];
} else {
_polyline = [[MAPolyline alloc] initWithPolylineId:self.id_];
}
[_polyline setPolylineWithCoordinates:_coords count:_coordCount];
}
return _polyline;
}
- (void)dealloc {
if (_coords != NULL) {
free(_coords);
_coords = NULL;
}
}
//polyline
- (void)updatePolyline:(AMapPolyline *)polyline {
NSAssert((polyline != nil && [self.id_ isEqualToString:polyline.id_]), @"更新Polyline数据异常");
if ([self checkCoordsEqualWithPolyline:polyline] == NO) {//polyline
if (_coords != NULL) {
free(_coords);
_coords = NULL;
}
_coordCount = polyline->_coordCount;
_coords = (CLLocationCoordinate2D*)malloc(_coordCount * sizeof(CLLocationCoordinate2D));
for (NSUInteger index = 0; index < _coordCount; index ++) {
_coords[index] = polyline->_coords[index];
}
}
self.width = polyline.width;
self.color = polyline.color;
self.visible = polyline.visible;
self.alpha = polyline.alpha;
NSAssert(self.geodesic == polyline.geodesic, @"是否为大地曲线的变量,不允许动态修改");
self.dashLineType = polyline.dashLineType;
self.joinType = polyline.joinType;
self.capType = polyline.capType;
if (_polyline) {
[_polyline setPolylineWithCoordinates:_coords count:_coordCount];
}
}
- (BOOL)checkCoordsEqualWithPolyline:(AMapPolyline *)newPolyline {
if (_coordCount != newPolyline->_coordCount) {//
return NO;
}
for (NSUInteger index = 0; index < _coordCount; index++) {
if ([AMapConvertUtil isEqualWith:_coords[index] to:newPolyline->_coords[index]] == NO) {
return NO;
}
}
return YES;
}
@end

View File

@ -0,0 +1,40 @@
//
// AMapMarkerController.h
// amap_map
//
// Created by lly on 2020/11/3.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AMapMarker;
@interface AMapMarkerController : NSObject
- (instancetype)init:(FlutterMethodChannel*)methodChannel
mapView:(MAMapView*)mapView
registrar:(NSObject<FlutterPluginRegistrar>*)registrar;
- (nullable AMapMarker *)markerForId:(NSString *)markerId;
- (void)addMarkers:(NSArray*)markersToAdd;
- (void)changeMarkers:(NSArray*)markersToChange;
- (void)removeMarkerIds:(NSArray*)markerIdsToRemove;
//MARK: Marker的回调
- (BOOL)onMarkerTap:(NSString*)markerId;
- (BOOL)onMarker:(NSString *)markerId endPostion:(CLLocationCoordinate2D)position;
//- (BOOL)onInfoWindowTap:(NSString *)markerId;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,153 @@
//
// AMapMarkerController.m
// amap_map
//
// Created by lly on 2020/11/3.
//
#import "AMapMarkerController.h"
#import "AMapMarker.h"
#import "AMapJsonUtils.h"
#import "AMapConvertUtil.h"
#import "MAAnnotationView+Flutter.h"
#import "FlutterMethodChannel+MethodCallDispatch.h"
@interface AMapMarkerController ()
@property (nonatomic,strong) NSMutableDictionary<NSString*,AMapMarker*> *markerDict;
@property (nonatomic,strong) FlutterMethodChannel *methodChannel;
@property (nonatomic,strong) NSObject<FlutterPluginRegistrar> *registrar;
@property (nonatomic,strong) MAMapView *mapView;
@end
@implementation AMapMarkerController
- (instancetype)init:(FlutterMethodChannel*)methodChannel
mapView:(MAMapView*)mapView
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
self = [super init];
if (self) {
_methodChannel = methodChannel;
_mapView = mapView;
_markerDict = [NSMutableDictionary dictionaryWithCapacity:1];
_registrar = registrar;
__weak typeof(self) weakSelf = self;
[_methodChannel addMethodName:@"markers#update" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
id markersToAdd = call.arguments[@"markersToAdd"];
if ([markersToAdd isKindOfClass:[NSArray class]]) {
[weakSelf addMarkers:markersToAdd];
}
id markersToChange = call.arguments[@"markersToChange"];
if ([markersToChange isKindOfClass:[NSArray class]]) {
[weakSelf changeMarkers:markersToChange];
}
id markerIdsToRemove = call.arguments[@"markerIdsToRemove"];
if ([markerIdsToRemove isKindOfClass:[NSArray class]]) {
[weakSelf removeMarkerIds:markerIdsToRemove];
}
result(nil);
}];
}
return self;
}
- (nullable AMapMarker *)markerForId:(NSString *)markerId {
return _markerDict[markerId];
}
- (void)addMarkers:(NSArray*)markersToAdd {
for (NSDictionary* marker in markersToAdd) {
AMapMarker *markerModel = [AMapJsonUtils modelFromDict:marker modelClass:[AMapMarker class]];
//bitmapDescUIImage
if (markerModel.icon) {
markerModel.image = [AMapConvertUtil imageFromRegistrar:self.registrar iconData:markerModel.icon];
}
// marker
if (markerModel.id_) {
_markerDict[markerModel.id_] = markerModel;
}
[self.mapView addAnnotation:markerModel.annotation];
}
}
- (void)changeMarkers:(NSArray*)markersToChange {
for (NSDictionary* markerToChange in markersToChange) {
NSLog(@"changeMarker:%@",markerToChange);
AMapMarker *markerModelToChange = [AMapJsonUtils modelFromDict:markerToChange modelClass:[AMapMarker class]];
AMapMarker *currentMarkerModel = _markerDict[markerModelToChange.id_];
NSAssert(currentMarkerModel != nil, @"需要修改的marker不存在");
//
if ([AMapConvertUtil checkIconDescriptionChangedFrom:currentMarkerModel.icon to:markerModelToChange.icon]) {
UIImage *image = [AMapConvertUtil imageFromRegistrar:self.registrar iconData:markerModelToChange.icon];
currentMarkerModel.icon = markerModelToChange.icon;
currentMarkerModel.image = image;
}
//
[currentMarkerModel updateMarker:markerModelToChange];
MAAnnotationView *view = [self.mapView viewForAnnotation:currentMarkerModel.annotation];
if (view) {//View
[view updateViewWithMarker:currentMarkerModel];
} //viewDidAddview
}
}
- (void)removeMarkerIds:(NSArray*)markerIdsToRemove {
for (NSString* markerId in markerIdsToRemove) {
if (!markerId) {
continue;
}
AMapMarker* marker = _markerDict[markerId];
if (!marker) {
continue;
}
[self.mapView removeAnnotation:marker.annotation];
[_markerDict removeObjectForKey:markerId];
}
}
//MARK: Marker
- (BOOL)onMarkerTap:(NSString*)markerId {
if (!markerId) {
return NO;
}
AMapMarker* marker = _markerDict[markerId];
if (!marker) {
return NO;
}
[_methodChannel invokeMethod:@"marker#onTap" arguments:@{@"markerId" : markerId}];
return YES;
}
- (BOOL)onMarker:(NSString *)markerId endPostion:(CLLocationCoordinate2D)position {
if (!markerId) {
return NO;
}
AMapMarker* marker = _markerDict[markerId];
if (!marker) {
return NO;
}
[_methodChannel invokeMethod:@"marker#onDragEnd"
arguments:@{@"markerId" : markerId, @"position" : [AMapConvertUtil jsonArrayFromCoordinate:position]}];
return YES;
}
//- (BOOL)onInfoWindowTap:(NSString *)markerId {
// if (!markerId) {
// return NO;
// }
// AMapMarker* marker = _markerDict[markerId];
// if (!marker) {
// return NO;
// }
// [_methodChannel invokeMethod:@"infoWindow#onTap" arguments:@{@"markerId" : markerId}];
// return YES;
//}
@end

View File

@ -0,0 +1,33 @@
//
// AMapPolygonController.h
// amap_map
//
// Created by lly on 2020/11/12.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AMapPolyline;
@class AMapPolygon;
@interface AMapPolygonController : NSObject
- (instancetype)init:(FlutterMethodChannel*)methodChannel
mapView:(MAMapView*)mapView
registrar:(NSObject<FlutterPluginRegistrar>*)registrar;
- (nullable AMapPolygon *)polygonForId:(NSString *)polygonId;
- (void)addPolygons:(NSArray*)polygonsToAdd;
- (void)changePolygons:(NSArray*)polygonsToChange;
- (void)removePolygonIds:(NSArray*)polygonIdsToRemove;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,99 @@
//
// AMapPolygonController.m
// amap_map
//
// Created by lly on 2020/11/12.
//
#import "AMapPolygonController.h"
#import "AMapPolygon.h"
#import "AMapJsonUtils.h"
#import "MAPolygon+Flutter.h"
#import "MAPolygonRenderer+Flutter.h"
#import "FlutterMethodChannel+MethodCallDispatch.h"
@interface AMapPolygonController ()
@property (nonatomic,strong) NSMutableDictionary<NSString*,AMapPolygon*> *polygonDict;
@property (nonatomic,strong) FlutterMethodChannel *methodChannel;
@property (nonatomic,strong) NSObject<FlutterPluginRegistrar> *registrar;
@property (nonatomic,strong) MAMapView *mapView;
@end
@implementation AMapPolygonController
- (instancetype)init:(FlutterMethodChannel*)methodChannel
mapView:(MAMapView*)mapView
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
self = [super init];
if (self) {
_methodChannel = methodChannel;
_mapView = mapView;
_polygonDict = [NSMutableDictionary dictionaryWithCapacity:1];
_registrar = registrar;
__weak typeof(self) weakSelf = self;
[_methodChannel addMethodName:@"polygons#update" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
id polygonsToAdd = call.arguments[@"polygonsToAdd"];
if ([polygonsToAdd isKindOfClass:[NSArray class]]) {
[weakSelf addPolygons:polygonsToAdd];
}
id polygonsToChange = call.arguments[@"polygonsToChange"];
if ([polygonsToChange isKindOfClass:[NSArray class]]) {
[weakSelf changePolygons:polygonsToChange];
}
id polygonIdsToRemove = call.arguments[@"polygonIdsToRemove"];
if ([polygonIdsToRemove isKindOfClass:[NSArray class]]) {
[weakSelf removePolygonIds:polygonIdsToRemove];
}
result(nil);
}];
}
return self;
}
- (nullable AMapPolygon *)polygonForId:(NSString *)polygonId {
return _polygonDict[polygonId];
}
- (void)addPolygons:(NSArray*)polygonsToAdd {
for (NSDictionary* polygonDict in polygonsToAdd) {
AMapPolygon *polygon = [AMapJsonUtils modelFromDict:polygonDict modelClass:[AMapPolygon class]];
// overlay
if (polygon.id_) {
_polygonDict[polygon.id_] = polygon;
}
[self.mapView addOverlay:polygon.polygon];
}
}
- (void)changePolygons:(NSArray*)polygonsToChange {
for (NSDictionary* polygonDict in polygonsToChange) {
AMapPolygon *polygon = [AMapJsonUtils modelFromDict:polygonDict modelClass:[AMapPolygon class]];
AMapPolygon *currentPolygon = _polygonDict[polygon.id_];
NSAssert(currentPolygon != nil, @"需要修改的Polygon不存在");
[currentPolygon updatePolygon:polygon];
MAOverlayRenderer *render = [self.mapView rendererForOverlay:currentPolygon.polygon];
if (render && [render isKindOfClass:[MAPolygonRenderer class]]) { // render
[(MAPolygonRenderer *)render updateRenderWithPolygon:currentPolygon];
}
}
}
- (void)removePolygonIds:(NSArray*)polygonIdsToRemove {
for (NSString* polygonId in polygonIdsToRemove) {
if (!polygonId) {
continue;
}
AMapPolygon* polygon = _polygonDict[polygonId];
if (!polygon) {
continue;
}
[self.mapView removeOverlay:polygon.polygon];
[_polygonDict removeObjectForKey:polygonId];
}
}
@end

View File

@ -0,0 +1,34 @@
//
// AMapPolylineController.h
// amap_map
//
// Created by lly on 2020/11/6.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AMapPolyline;
@interface AMapPolylineController : NSObject
- (instancetype)init:(FlutterMethodChannel*)methodChannel
mapView:(MAMapView*)mapView
registrar:(NSObject<FlutterPluginRegistrar>*)registrar;
- (nullable AMapPolyline *)polylineForId:(NSString *)polylineId;
- (void)addPolylines:(NSArray*)polylinesToAdd;
- (void)changePolylines:(NSArray*)polylinesToChange;
- (void)removePolylineIds:(NSArray*)polylineIdsToRemove;
- (BOOL)onPolylineTap:(NSString*)polylineId;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,125 @@
//
// AMapPolylineController.m
// amap_map
//
// Created by lly on 2020/11/6.
//
#import "AMapPolylineController.h"
#import "AMapPolyline.h"
#import "AMapJsonUtils.h"
#import "AMapMarker.h"
#import "MAPolyline+Flutter.h"
#import "MAPolylineRenderer+Flutter.h"
#import "AMapConvertUtil.h"
#import "FlutterMethodChannel+MethodCallDispatch.h"
@interface AMapPolylineController ()
@property (nonatomic,strong) NSMutableDictionary<NSString*,AMapPolyline*> *polylineDict;
@property (nonatomic,strong) FlutterMethodChannel *methodChannel;
@property (nonatomic,strong) NSObject<FlutterPluginRegistrar> *registrar;
@property (nonatomic,strong) MAMapView *mapView;
@end
@implementation AMapPolylineController
- (instancetype)init:(FlutterMethodChannel*)methodChannel
mapView:(MAMapView*)mapView
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
self = [super init];
if (self) {
_methodChannel = methodChannel;
_mapView = mapView;
_polylineDict = [NSMutableDictionary dictionaryWithCapacity:1];
_registrar = registrar;
__weak typeof(self) weakSelf = self;
[_methodChannel addMethodName:@"polylines#update" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
id polylinesToAdd = call.arguments[@"polylinesToAdd"];
if ([polylinesToAdd isKindOfClass:[NSArray class]]) {
[weakSelf addPolylines:polylinesToAdd];
}
id polylinesToChange = call.arguments[@"polylinesToChange"];
if ([polylinesToChange isKindOfClass:[NSArray class]]) {
[weakSelf changePolylines:polylinesToChange];
}
id polylineIdsToRemove = call.arguments[@"polylineIdsToRemove"];
if ([polylineIdsToRemove isKindOfClass:[NSArray class]]) {
[weakSelf removePolylineIds:polylineIdsToRemove];
}
result(nil);
}];
}
return self;
}
- (nullable AMapPolyline *)polylineForId:(NSString *)polylineId {
return _polylineDict[polylineId];
}
- (void)addPolylines:(NSArray*)polylinesToAdd {
for (NSDictionary* polyline in polylinesToAdd) {
AMapPolyline *polylineModel = [AMapJsonUtils modelFromDict:polyline modelClass:[AMapPolyline class]];
if (polylineModel.customTexture) {
polylineModel.strokeImage = [AMapConvertUtil imageFromRegistrar:self.registrar iconData:polylineModel.customTexture];
}
// overlay
if (polylineModel.id_) {
_polylineDict[polylineModel.id_] = polylineModel;
}
[self.mapView addOverlay:polylineModel.polyline];
}
}
- (void)changePolylines:(NSArray*)polylinesToChange {
for (NSDictionary* polylineToChange in polylinesToChange) {
AMapPolyline *polyline = [AMapJsonUtils modelFromDict:polylineToChange modelClass:[AMapPolyline class]];
AMapPolyline *currentPolyline = _polylineDict[polyline.id_];
NSAssert(currentPolyline != nil, @"需要修改的Polyline不存在");
//
if ([AMapConvertUtil checkIconDescriptionChangedFrom:currentPolyline.customTexture to:polyline.customTexture]) {
currentPolyline.strokeImage = [AMapConvertUtil imageFromRegistrar:self.registrar iconData:polyline.customTexture];
currentPolyline.customTexture = polyline.customTexture;
}
//
[currentPolyline updatePolyline:polyline];
MAOverlayRenderer *render = [self.mapView rendererForOverlay:currentPolyline.polyline];
if (render && [render isKindOfClass:[MAPolylineRenderer class]]) { // render
[(MAPolylineRenderer *)render updateRenderWithPolyline:currentPolyline];
}
}
}
- (void)removePolylineIds:(NSArray*)polylineIdsToRemove {
for (NSString* polylineId in polylineIdsToRemove) {
if (!polylineId) {
continue;
}
AMapPolyline* polyline = _polylineDict[polylineId];
if (!polyline) {
continue;
}
[self.mapView removeOverlay:polyline.polyline];
[_polylineDict removeObjectForKey:polylineId];
}
}
//MARK: Marker
- (BOOL)onPolylineTap:(NSString*)polylineId {
if (!polylineId) {
return NO;
}
AMapPolyline* polyline = _polylineDict[polylineId];
if (!polyline) {
return NO;
}
[_methodChannel invokeMethod:@"polyline#onTap" arguments:@{@"polylineId" : polylineId}];
return YES;
}
@end

View File

@ -0,0 +1,68 @@
//
// AMapConvertUtil.h
// amap_map
//
// Created by lly on 2020/10/30.
//
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <Flutter/Flutter.h>
#import <MAMapKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@class MATouchPoi;
@interface AMapConvertUtil : NSObject
/// 经纬度坐标转字符串
/// @param coordinate 经纬度坐标
+ (NSString *)stringFromCoordinate:(CLLocationCoordinate2D)coordinate;
/// 颜色的色值解析色值必须为json中的number类型
/// @param numberColor 色值
+ (UIColor*)colorFromNumber:(NSNumber*)numberColor;
/// 将数组内含数字转换为point坐标默认数组第一个元素为x值第二个为y值
/// @param data 数组
+ (CGPoint)pointFromArray:(NSArray*)data;
/// 从数据中解析经纬度
/// @param array 经纬度数组对(默认第一个当做维度,第二个当做经度)
+ (CLLocationCoordinate2D)coordinateFromArray:(NSArray *)array;
/// 经纬度转json数组
/// @param coord 经纬度
+ (NSArray *)jsonFromCoordinate:(CLLocationCoordinate2D )coord;
/// 经纬度转json数组
/// @param coordinate 经纬度
+ (NSArray<NSNumber *> *)jsonArrayFromCoordinate:(CLLocationCoordinate2D)coordinate;
+ (UIImage*)imageFromRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar iconData:(NSArray*)iconData;
/// 检测图标相关的描述,是否修改过
/// @param previousIcon 之前的图标
/// @param currentIcon 当前新的图标
/// @return 修改了则返回yes否则返回NO
+ (BOOL)checkIconDescriptionChangedFrom:(NSArray *)previousIcon to:(NSArray *)currentIcon;
/// 经纬度坐标比较
/// @param coord1 坐标1
/// @param coord2 坐标2
+ (BOOL)isEqualWith:(CLLocationCoordinate2D)coord1 to:(CLLocationCoordinate2D)coord2;
/// TouchPOI转字典
/// @param poi 点击POI
+ (NSDictionary *)dictFromTouchPOI:(MATouchPoi *)poi;
/// 解析得到mapRect结构
/// @param array json数组[southwest,northeast],分别为西南、东北的坐标
+ (MAMapRect)mapRectFromArray:(NSArray *)array;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,215 @@
//
// AMapConvertUtil.m
// amap_map
//
// Created by lly on 2020/10/30.
//
#import "AMapConvertUtil.h"
@implementation AMapConvertUtil
///
/// @param coordinate
+ (NSString *)stringFromCoordinate:(CLLocationCoordinate2D)coordinate {
return [NSString stringWithFormat:@"{%.6f,%.6f}", coordinate.longitude, coordinate.latitude];
}
+ (UIColor*)colorFromNumber:(NSNumber*)numberColor {
if (numberColor == nil || [numberColor isKindOfClass:[NSNumber class]] == NO) {
return nil;
}
unsigned long value = [numberColor unsignedLongValue];
return [UIColor colorWithRed:((float)((value & 0xFF0000) >> 16)) / 255.0
green:((float)((value & 0xFF00) >> 8)) / 255.0
blue:((float)(value & 0xFF)) / 255.0
alpha:((float)((value & 0xFF000000) >> 24)) / 255.0];
}
+ (CGPoint)pointFromArray:(NSArray*)data {
NSAssert((data != nil && [data isKindOfClass:[NSArray class]] && data.count == 2), @"数组类型转point格式错误");
return CGPointMake([data[0] doubleValue],
[data[1] doubleValue]);
}
///
/// @param array
+ (CLLocationCoordinate2D)coordinateFromArray:(NSArray *)array {
CLLocationCoordinate2D location = kCLLocationCoordinate2DInvalid;
if (array.count == 2) {
double latitude = [array[0] doubleValue];
double longitude = [array[1] doubleValue];
if ([self checkValidLatitude:latitude longitude:longitude]) {
location = CLLocationCoordinate2DMake(latitude, longitude);
} else if ([self checkValidLatitude:longitude longitude:latitude]) {//
location = CLLocationCoordinate2DMake(longitude, latitude);
} else {
NSLog(@"经纬度参数异常,解析为无效经纬度");
}
} else {
NSLog(@"经纬度参数异常,解析为无效经纬度");
}
return location;
}
+ (NSArray *)jsonFromCoordinate:(CLLocationCoordinate2D )coord {
if (CLLocationCoordinate2DIsValid(coord)) {
return @[@(coord.latitude),@(coord.longitude)];
} else {
NSLog(@"经纬度无效,返回为空");
return @[];
}
}
///
/// @param latitude
/// @param longitude
+ (BOOL)checkValidLatitude:(double)latitude longitude:(double)longitude {
if (latitude > 90 || latitude < -90) {
return false;
}
if (longitude > 180 || longitude < -180) {
return false;
}
return true;
}
+ (NSArray<NSNumber *> *)jsonArrayFromCoordinate:(CLLocationCoordinate2D)coordinate {
if (CLLocationCoordinate2DIsValid(coordinate)) {
return @[ @(coordinate.latitude), @(coordinate.longitude) ];
} else {
return @[];
}
}
+ (UIImage*)scaleImage:(UIImage*)image param:(NSNumber*)scaleParam {
double scale = 1.0;
if ([scaleParam isKindOfClass:[NSNumber class]]) {
scale = scaleParam.doubleValue;
}
if (fabs(scale - 1) > 1e-3) {
return [UIImage imageWithCGImage:[image CGImage]
scale:(image.scale * scale)
orientation:(image.imageOrientation)];
}
return image;
}
+ (UIImage*)imageFromRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar iconData:(NSArray*)iconData {
UIImage* image;
if ([iconData.firstObject isEqualToString:@"defaultMarker"]) {
image = [UIImage imageNamed:[registrar lookupKeyForAsset:@"packages/amap_map/res/marker_default.png"]];//
CGFloat screenScale = [[UIScreen mainScreen] scale];
image = [self scaleImage:image param:[NSNumber numberWithFloat:screenScale]];
//
} else if ([iconData.firstObject isEqualToString:@"fromAsset"]) {
if (iconData.count == 2) {
image = [UIImage imageNamed:[registrar lookupKeyForAsset:iconData[1]]];
CGFloat screenScale = [[UIScreen mainScreen] scale];
image = [self scaleImage:image param:[NSNumber numberWithFloat:screenScale]];
}
} else if ([iconData.firstObject isEqualToString:@"fromAssetImage"]) {
if (iconData.count == 3) {
image = [UIImage imageNamed:[registrar lookupKeyForAsset:iconData[1]]];
NSNumber* scaleParam = iconData[2];
image = [self scaleImage:image param:scaleParam];
} else {
NSString* error =
[NSString stringWithFormat:@"'fromAssetImage' should have exactly 3 arguments. Got: %lu",
(unsigned long)iconData.count];
NSException* exception = [NSException exceptionWithName:@"InvalidBitmapDescriptor"
reason:error
userInfo:nil];
@throw exception;
}
} else if ([iconData[0] isEqualToString:@"fromBytes"]) {
if (iconData.count == 2) {
@try {
FlutterStandardTypedData* byteData = iconData[1];
CGFloat screenScale = [[UIScreen mainScreen] scale];
image = [UIImage imageWithData:[byteData data] scale:screenScale];
} @catch (NSException* exception) {
@throw [NSException exceptionWithName:@"InvalidByteDescriptor"
reason:@"Unable to interpret bytes as a valid image."
userInfo:nil];
}
} else {
NSString* error = [NSString
stringWithFormat:@"fromBytes should have exactly one argument, the bytes. Got: %lu",
(unsigned long)iconData.count];
NSException* exception = [NSException exceptionWithName:@"InvalidByteDescriptor"
reason:error
userInfo:nil];
@throw exception;
}
}
return image;
}
///
/// @param previousIcon
/// @param currentIcon
/// @return yesNO
+ (BOOL)checkIconDescriptionChangedFrom:(NSArray *)previousIcon to:(NSArray *)currentIcon {
if (previousIcon.count != currentIcon.count) {
return YES;
}
//
for (NSUInteger index = 0; index < previousIcon.count; index ++) {
if ([previousIcon[index] isKindOfClass:[NSString class]]) {
if ([previousIcon[index] isEqualToString:currentIcon[index]] == NO) {
return YES;
}
} else if ([previousIcon[index] isKindOfClass:[NSNumber class]]) {
if (fabs([previousIcon[index] doubleValue] - [currentIcon[index] doubleValue]) > 0.000001) {
return YES;
}
} else {//
return NO;
}
}
return NO;
}
+ (BOOL)isEqualWith:(CLLocationCoordinate2D)coord1 to:(CLLocationCoordinate2D)coord2 {
if (fabs(coord1.latitude - coord2.latitude) > 0.000001 || fabs(coord1.longitude - coord2.longitude) > 0.000001) {
return NO;
}
return YES;
}
+ (NSDictionary *)dictFromTouchPOI:(MATouchPoi *)poi {
if (poi == nil) {
return nil;
}
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:3];
if (poi.name) {
[dict setObject:poi.name forKey:@"name"];
}
if (CLLocationCoordinate2DIsValid(poi.coordinate)) {
[dict setObject:[AMapConvertUtil jsonArrayFromCoordinate:poi.coordinate] forKey:@"latLng"];
}
if (poi.uid) {
[dict setObject:poi.uid forKey:@"id"];
}
return [dict copy];
}
+ (MAMapRect)mapRectFromArray:(NSArray *)array {
NSAssert((array && [array isKindOfClass:[NSArray class]] && array.count == 2), @"解析mapRect的参数有误");
CLLocationCoordinate2D southwest = [AMapConvertUtil coordinateFromArray:array[0]];
CLLocationCoordinate2D northeast = [AMapConvertUtil coordinateFromArray:array[1]];
MAMapPoint mapNorthEastPoint = MAMapPointForCoordinate(northeast);
MAMapPoint mapSouthWestPoint = MAMapPointForCoordinate(southwest);
double width = fabs(mapNorthEastPoint.x - mapSouthWestPoint.x);
double height = fabs(mapNorthEastPoint.y - mapSouthWestPoint.y);
MAMapRect limitRect = MAMapRectMake(mapSouthWestPoint.x, mapNorthEastPoint.y, width, height);
return limitRect;
}
@end

View File

@ -0,0 +1,35 @@
//
// MAJsonUtils.h
// amap_map
//
// Created by shaobin on 2019/2/13.
// Copyright © 2019 Amap.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface AMapJsonUtils : NSObject
/**
model转为可序列化为json的对象。
@param model model对象:支持NSDictionary、NSArray、自定义类且支持嵌套(Dict、Array内包含自定义类示例或自定义类内包含Dict、Array) 注意如果自定义类或dict、array中包含非字符串、数字、布尔、null类型的属性其行为是undefined的
@return 返回NSArray或者NSDictionary对象如果失败返回nil。
*/
+ (id)jsonObjectFromModel:(id)model;
/**
dict转model
@param dict dict
@param modelClass model对应的Class
@return 返回modelClass实例
*/
+ (id)modelFromDict:(NSDictionary*)dict modelClass:(Class)modelClass;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,275 @@
//
// MAJsonUtils.m
// amap_map
//
// Created by shaobin on 2019/2/13.
// Copyright © 2019 Amap.com. All rights reserved.
//
#import "AMapJsonUtils.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import <CoreLocation/CoreLocation.h>
#import "AMapConvertUtil.h"
@implementation AMapJsonUtils
+ (BOOL)isValidJsonValue:(id)value {
if([value isKindOfClass:NSString.class] ||
[value isKindOfClass:NSNumber.class] ||
value == [NSNull null]) {
return YES;
}
return NO;
}
+ (id)jsonValueFromObject:(id)obj {
if([self isValidJsonValue:obj]) {
return obj;
}
if(!obj) {
return [NSNull null];
}
//not exhausted
if([obj isKindOfClass:NSDate.class] ||
[obj isKindOfClass:NSData.class] ||
[obj isKindOfClass:NSValue.class]) {
NSString *retStr = [NSString stringWithFormat:@"%@", obj];
return retStr;
}
if([obj isKindOfClass:NSArray.class]) {
NSArray *oldArray = (NSArray*)obj;
NSMutableArray *retArray = [NSMutableArray arrayWithCapacity:[oldArray count]];
for(id item in oldArray) {
id jsonValue = [self jsonValueFromObject:item];
[retArray addObject:jsonValue];
}
return retArray;
}
if([obj isKindOfClass:NSDictionary.class]) {
NSDictionary *oldDict = (NSDictionary *)obj;
NSMutableDictionary *retDict = [NSMutableDictionary dictionaryWithCapacity:[oldDict count]];
for(id key in [oldDict allKeys]) {
id item = [oldDict objectForKey:key];
id jsonValue = [self jsonValueFromObject:item];
if(jsonValue) {
[retDict setObject:jsonValue forKey:key];
}
}
return retDict;
}
NSArray *propertyArray = [self allPropertiesOfClass:[obj class]];
NSMutableDictionary *returnDict = [NSMutableDictionary dictionaryWithCapacity:propertyArray.count];
for(NSString *property in propertyArray) {
id value = [obj valueForKey:property];
if(value) {
id jsonValue = [self jsonValueFromObject:value];
NSString *mappedName = property;
if(jsonValue) {
[returnDict setObject:jsonValue forKey:mappedName];
}
}
}
return returnDict;
}
+ (id)jsonObjectFromModel:(id)model {
id ret = [self jsonValueFromObject:model];
if(![NSJSONSerialization isValidJSONObject:ret]) {
return nil;
}
return ret;
}
+ (id)modelFromDict:(NSDictionary*)dict modelClass:(Class)modelClass {
if(![dict isKindOfClass:[NSDictionary class]]) {
NSLog(@"[AMap] the object must be of %@", [NSDictionary class]);
return nil;
}
if([modelClass isSubclassOfClass:[NSDictionary class]]) {
return [dict copy];
}
//clazz
NSArray *propertyArray = [self allPropertiesOfClass:modelClass];
NSMutableArray* missedProperties = [NSMutableArray array];
id ret = [[modelClass alloc] init];
//clazz
for (NSString *propertyName in propertyArray) {
NSString *keyName = propertyName;
id value = [dict objectForKey:keyName];
//'id''id''id_'
if(!value && [propertyName isEqualToString:@"id_"]) {
value = [dict objectForKey:@"id"];
}
if(!value) {
[missedProperties addObject:propertyName];
continue;
}
if(value == [NSNull null]) {
continue;
}
Class propertyClass = nil;
objc_property_t property = class_getProperty(modelClass, [propertyName UTF8String]);
NSString *propertyAttributes = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
NSArray *splitPropertyAttributes = [propertyAttributes componentsSeparatedByString:@","];
if(splitPropertyAttributes.count > 0) {
NSString *encodeType = splitPropertyAttributes[0];
if([encodeType hasPrefix:@"T@"]) {
NSArray *splitEncodeType = [encodeType componentsSeparatedByString:@"\""];
NSString *className = nil;
if(splitEncodeType.count > 1) {
className = splitEncodeType[1];
}
if(className) {
propertyClass = NSClassFromString(className);
}
} else if ([encodeType isEqualToString:@"T{CLLocationCoordinate2D=dd}"]) {//
//
CLLocationCoordinate2D coordinate = [self coordinateFromModel:value];
//使msgSend
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]);
((void (*)(id,SEL,CLLocationCoordinate2D))objc_msgSend)(ret,sel,coordinate);
continue;
} else if ([encodeType isEqualToString:@"T{CGPoint=dd}"]) {//CGPoint点
CGPoint point = [AMapConvertUtil pointFromArray:value];
//使用msgSend直接设置经纬度的属性
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]);
((void (*)(id,SEL,CGPoint))objc_msgSend)(ret,sel,point);
continue;
}
}
//property
if(propertyClass) {
if([value isKindOfClass:propertyClass]) {
//array
if([propertyClass isSubclassOfClass:NSArray.class]) {
NSString *elementClassSel = [NSString stringWithFormat:@"%@ElementClass", propertyName];
SEL selector = NSSelectorFromString(elementClassSel);
if([[ret class] respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
Class elementCls = [[ret class] performSelector:selector];
#pragma clang diagnostic pop
NSArray *arr = (NSArray *)value;
NSMutableArray *mutArr = [NSMutableArray arrayWithCapacity:arr.count];
for(id item in arr) {
id newItem = [self modelFromDict:item modelClass:elementCls];
if(newItem) {
[mutArr addObject:newItem];
} else {
[mutArr addObject:item];
}
}
[ret setValue:mutArr forKey:propertyName];
} else {
[ret setValue:value forKey:propertyName];
}
} else {
[ret setValue:value forKey:propertyName];
}
} else if([value isKindOfClass:NSDictionary.class]){
NSDictionary *tempDic = value;
id model = [self modelFromDict:tempDic modelClass:propertyClass];
[ret setValue:model forKey:propertyName];
} else if ([value isKindOfClass:[NSNumber class]] && [NSStringFromClass(propertyClass) isEqualToString:@"UIColor"]) {
UIColor *color = [AMapConvertUtil colorFromNumber:value];
[ret setValue:color forKey:propertyName];
} else {
[ret setValue:value forKey:propertyName];
#ifdef DEBUG
Class valueClaz = [value class];
NSLog(@"\U0001F913\U0001F913 Warning1: property '%@' of %@ is %@, %@ is received", propertyName, modelClass, propertyClass, valueClaz);
#endif
}
} else { //end of if(propertyClaz) @"Ti" @"Tf"
if([self isValidJsonValue:value]){
[ret setValue:value forKey:propertyName];
} else {
#ifdef DEBUG
Class valueClaz = [value class];
NSLog(@"\U0001F913\U0001F913 Warning1: property '%@' of %@ is %@, %@ is received", propertyName, modelClass, propertyClass, valueClaz);
#endif
}
}
}
#ifdef DEBUG
if([missedProperties count] > 0) {
NSLog(@"\U0001F913\U0001F913 Warning2: %@ value missed: %@", modelClass, missedProperties);
}
#endif
NSString *postHookSel = [NSString stringWithFormat:@"postHookWith:"];
SEL sel = NSSelectorFromString(postHookSel);
if([ret respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[ret performSelector:sel withObject:dict];
#pragma clang diagnostic pop
}
return ret;
}
//array of propertyNames
+ (NSArray<NSString*> *)allPropertiesOfClass:(Class)cls {
Class clazz = cls;
NSMutableArray *mutArr = [[NSMutableArray alloc] init];
while(clazz != [NSObject class]) {
unsigned int count = 0;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
for (int i = 0; i < count ; i++) {
objc_property_t prop = properties[i];
NSString *propertyName = [NSString stringWithCString:property_getName(prop) encoding:NSUTF8StringEncoding];
[mutArr addObject:propertyName];
}
if(properties) {
free(properties);
}
clazz = class_getSuperclass(clazz);
}
return mutArr;
}
//model
+ (CLLocationCoordinate2D)coordinateFromModel:(id)model {
CLLocationCoordinate2D location = kCLLocationCoordinate2DInvalid;
if ([model isKindOfClass:[NSArray class]]) {
return [AMapConvertUtil coordinateFromArray:model];
} else if ([model isKindOfClass:[NSString class]]) {//
NSString *coordStr = model;
NSArray *array = [coordStr componentsSeparatedByString:@","];
array = [[array reverseObjectEnumerator] allObjects];//
return [AMapConvertUtil coordinateFromArray:array];
} else if ([model isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict = model;
NSNumber *latitudeNum = [dict objectForKey:@"latitude"];
NSNumber *longitudeNum = [dict objectForKey:@"longitude"];
if (latitudeNum && longitudeNum) {
location = CLLocationCoordinate2DMake([latitudeNum doubleValue], [longitudeNum doubleValue]);
} else {
NSLog(@"经纬度参数异常,解析为无效经纬度");
}
}
return location;
}
@end

View File

@ -0,0 +1,27 @@
//
// AMapMethodCallDispatcher.h
// amap_map
//
// Created by lly on 2020/11/16.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
/// methodCall的分发器该对象以Category的形式设置给FlutterMethodChannel作为FlutterMethodCallHandler
/// 再根据call.method来分发处理对应的处理block
@interface AMapMethodCallDispatcher : NSObject
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler;
- (void)removeHandlerWithMethodName:(NSString *)methodName;
- (void)clearAllHandler;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,61 @@
//
// AMapMethodCallDispatcher.m
// amap_map
//
// Created by lly on 2020/11/16.
//
#import "AMapMethodCallDispatcher.h"
@interface AMapMethodCallDispatcher ()
@property (nonatomic, strong) NSRecursiveLock *dictLock;
@property (nonatomic, strong) NSMutableDictionary *callDict;
@end
@implementation AMapMethodCallDispatcher
- (instancetype)init {
self = [super init];
if (self) {
self.dictLock = [[NSRecursiveLock alloc] init];
self.callDict = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
[self.dictLock lock];
FlutterMethodCallHandler handle = [self.callDict objectForKey:call.method];
[self.dictLock unlock];
if (handle) {
handle(call,result);
} else {
NSLog(@"call method:%@ handler is null",call.method);
result(nil);
}
}
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler {
NSAssert((methodName.length > 0 && handler != nil), @"添加methodCall回调处理参数异常");
[self.dictLock lock];
[self.callDict setObject:handler forKey:methodName];
[self.dictLock unlock];
}
- (void)removeHandlerWithMethodName:(NSString *)methodName {
NSAssert(methodName.length > 0, @"移除methodCall时参数异常");
[self.dictLock lock];
[self.callDict removeObjectForKey:methodName];
[self.dictLock unlock];
}
- (void)clearAllHandler {
[self.dictLock lock];
[self.callDict removeAllObjects];
[self.dictLock unlock];
}
@end