amap_map/ios/Classes/AMapViewController.m

510 lines
21 KiB
Mathematica
Raw Normal View History

2023-12-22 21:23:24 +08:00
//
// 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);
}];
2024-01-03 17:12:29 +08:00
[self.channel addMethodName:@"map#toScreenCoordinate" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
CLLocationCoordinate2D location = [AMapConvertUtil coordinateFromArray:call.arguments];
CGPoint point = [weakSelf.mapView convertCoordinate:location toPointToView:weakSelf.mapView];
result([AMapConvertUtil dictionaryFromPoint:point]);
}];
[self.channel addMethodName:@"map#fromScreenCoordinate" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
CGPoint point = [AMapConvertUtil pointFromDictionary:call.arguments];
CLLocationCoordinate2D coordinate = [weakSelf.mapView convertPoint:point toCoordinateFromView:weakSelf.mapView];
result([AMapConvertUtil arrayFromLocation:coordinate]);
}];
2023-12-22 21:23:24 +08:00
}
//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