前言
高德地图提供包括:web前端、Android、iOS、服务器、小程序等平台的地图服务, 地图功能众多,本文记载的只是自己遇到的一些问题,绝大部分功能只要参照官方文档和Dome都可以实现出来。
本文目录
- 地图的基本显示
- 地图上放置图标
- 在地图上绘制路线路线
- 后台持续定位
- 地理编码与逆地理编码
- 遇到的问题
地图的基本显示
注意:AMapFoundation.framework中提示含有 IDFA,我在一个设置了NSAppTransportSecurity为ture 的工程中使用,审核并没有被拒绝。
AppDelegate 中
#import <CoreLocation/CoreLocation.h>
#import <AMapFoundationKit/AMapFoundationKit.h>
<CLLocationManagerDelegate>
{
CLLocationManager *location; // 如果不设为全局的,弹框会一闪而过。
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[AMapServices sharedServices] setEnableHTTPS:YES];
[AMapServices sharedServices].apiKey = @"6fc7498adXXXXXXXXXXX";
location = [[CLLocationManager alloc] init];
location.delegate= self;
[location requestWhenInUseAuthorization];//弹框授权提示
}
需要展示地图的页面
#import <MAMapKit/MAMapView.h>
<MAMapViewDelegate>
myMapView = [[MAMapView alloc]init];
myMapView.bounds = CGRectMake(0, 0, WIDTH, HEIGHT);
myMapView.center = CGPointMake(self.view.center.x, self.view.center.y);
[myMapView setDelegate:self];
myMapView.showsCompass = NO;
myMapView.showTraffic = NO;
myMapView.showsScale = NO;
myMapView.showsUserLocation = YES; //显示用户位置
myMapView.customizeUserLocationAccuracyCircleRepresentation = YES;
[self.view addSubview:myMapView];
myMapView.rotateEnabled= NO;
myMapView.rotateCameraEnabled = NO;
[myMapView setCameraDegree:10.f animated:YES duration:0];//倾斜
myMapView.userTrackingMode = MAUserTrackingModeFollow;
[myMapView setZoomLevel:18 animated:YES];
//定位显示在地图中心, 是代理方法,
- (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation
{
//onceUserCenter为了避免因为一直定位造成的无法移动地图,
if (!onceUserCenter) {
coordinate = userLocation.coordinate;
[myMapView setCenterCoordinate:coordinate];
}
onceUserCenter = YES;
}
地图上放置图标
如何自定义当前用户的定位图标:
//设置显示当前用户位置
myMapView.showsUserLocation = YES; //显示用户位置
//在某个经纬度下放置图标
MAPointAnnotation *annotation = [[MAPointAnnotation alloc]init];
annotation.coordinate = locationCorrrdinate;
[_myMapView addAnnotations:@[annotation]];
// MyAnnation是一个自己定义的类
MyAnnation *annotation = [[MyAnnation alloc]initWithCoordinate:locationCorrrdinateGR];
[_myMapView addAnnotations:@[annotation]];
//这是一个专门显示地图上图标的方法体 是代理方法
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation
{
if ([annotation isKindOfClass:[MAPointAnnotation class]])
{
static NSString *reuseIndetifier = @"annotationReuseIndetifier";
MAAnnotationView *annotationView = (MAAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseIndetifier];
if (annotationView == nil)
{
annotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:reuseIndetifier];
}
annotationView.image = [UIImage imageNamed:@"annotation.png"];
//设置中心点偏移,使得标注底部中间点成为经纬度对应点
annotationView.centerOffset = CGPointMake(0, -18);
return annotationView;
}
//找到当前定位点,如果这里不设置,那个默认的蓝点是不会消失的。
else if (annotation == mapView.userLocation)
{
static NSString *MAPCellIdentifier = @"MAPCellIdentifier";
MAAnnotationView *poiAnnotationView = (MAPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:MAPCellIdentifier];
if (poiAnnotationView == nil)
{
poiAnnotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:MAPCellIdentifier];
}
poiAnnotationView.canShowCallout = NO;
poiAnnotationView.image = [UIImage imageNamed:@"gc.png"];
return poiAnnotationView;
}
else if ([annotation isKindOfClass:[MyAnnation class]]){
}
return nil;
}`
效果如下:
这里说明一下:MyAnnation是一个自己定义的类,如果需要你可以自定义很多这样的类,在代理中加以区分显示不同的图标,不过你也可以使用MAPointAnnotation 来加载,通过设置不同的标题title;来加以区分,这样是最简单的。
自定义MyAnnation
源码:
.h文件
#import <Foundation/Foundation.h>
#import <MAMapKit/MAShape.h>
@interface MyAnnation : NSObject
<MAAnnotation>
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate;
@property (nonatomic, readwrite) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@end
.m文件
#import "MyAnnation.h"
@implementation MyAnnation
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate {
if(self = [super init])
self.coordinate = coordinate;
return self;
}
@end
在地图上绘制路线
路线规划(在地图上显示两个地点之间的路线时)需要参照 iOS导航SDK,而不是 iOS地图SDK,不然你就走远啦
参照高德开发文档中的步骤即可
路线参照文档,同时可以考高德地图的Dome中的示例代码。
源码:
#import <AMapNaviKit/AMapNaviKit.h>
<MAMapViewDelegate,AMapNaviWalkManagerDelegate>
{
AMapNaviPoint *startPoint;
AMapNaviPoint *endPoint;
}
@property (nonatomic,strong) AMapNaviWalkManager *walkManager;
self.walkManager = [[MethodTool shareTool]backWalkManager];
[self.walkManager setDelegate:self];
startPoint = [AMapNaviPoint locationWithLatitude:locationCorrrdinate.latitude longitude:locationCorrrdinate.longitude];
endPoint = [AMapNaviPoint locationWithLatitude:locationCorrrdinateGR.latitude longitude:locationCorrrdinateGR.longitude];
[self routePlanAction];
#pragma mark-------------------地图路线规划 代理方法----------------
- (void)routePlanAction
{
//进行步行路径规划
[self.walkManager calculateWalkRouteWithStartPoints:@[startPoint]
endPoints:@[endPoint]];
}
// 路线规划成功时
- (void)walkManagerOnCalculateRouteSuccess:(AMapNaviWalkManager *)walkManager
{
NSLog(@"onCalculateRouteSuccess");
//显示路径或开启导航
if (walkManager.naviRoute == nil)
{
return;
}
[_myMapView removeOverlays:_myMapView.overlays];
NSUInteger coordianteCount = [walkManager.naviRoute.routeCoordinates count];
//使用一个定长的数组把返回的路线中的每个点都装起来,在加载到地图上即可
CLLocationCoordinate2D coordinates[coordianteCount];
for (int i = 0; i < coordianteCount; i++)
{
AMapNaviPoint *aCoordinate = [walkManager.naviRoute.routeCoordinates objectAtIndex:i];
coordinates[i] = CLLocationCoordinate2DMake(aCoordinate.latitude, aCoordinate.longitude);
}
MAPolyline *polyline = [MAPolyline polylineWithCoordinates:coordinates count:coordianteCount];
[_myMapView addOverlay:polyline];
[_myMapView setVisibleMapRect:[polyline boundingMapRect] animated:YES];
[_myMapView setHeight:Scale_Y(200)];
self.toUpdateA();
}
//绘制路线的方法
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id<MAOverlay>)overlay
{
if ([overlay isKindOfClass:[MAPolyline class]]) //路线
{
MAPolylineRenderer *polylineView = [[MAPolylineRenderer alloc] initWithOverlay:overlay];
//设置路线宽度
polylineView.lineWidth = Scale_X(6);
//设置路线在地图上显示的颜色
polylineView.strokeColor = RGB(255, 170, 166, 1);
return polylineView;
}
return nil;
}
- (void)walkManager:(AMapNaviWalkManager *)walkManager error:(NSError *)error;
{
NSLog(@"error: %@",error);
}
- (void)walkManager:(AMapNaviWalkManager *)walkManager onCalculateRouteFailure:(NSError *)error;
{
NSLog(@"error11: %@",error);
}
效果大概如下:
注意导航规划路线的时候,AMapNaviWalkManager对象整个工程只能有一个,如果有多个,那么后面初始化的 AMapNaviWalkManager 是无法规划路线的。所以我使用了单例来保存这个对象供全局使用。
后台持续定位
高德提供不依赖地图的定位,实现后台定位、持续定位:
高德地图定位
在Info.plist中加入两个字段
NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
这两个字段会义提示用户授权使用地理定位功能时的提示语。
<key>NSLocationAlwaysUsageDescription</key>
<true/>
<key>NSLocationWhenInUseUsageDescription</key>
<true/>
如果实现后台持续定位,需要开启后台模式,并且这两个字段一个都不能少,否则不会出现如下效果。
源码:
#import <AMapFoundationKit/AMapFoundationKit.h>
#import <AMapLocationKit/AMapLocationKit.h>
<AMapLocationManagerDelegate>
@property(strong,nonatomic)AMapLocationManager *locationManager;
self.locationManager = [[AMapLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = 100;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
self.locationManager.allowsBackgroundLocationUpdates = YES;
}else{
[self.locationManager setPausesLocationUpdatesAutomatically:NO];
}
//开启持续定位
- (void)startUploadLocation;
{
//开始持续定位
[self.locationManager startUpdatingLocation];
}
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode
{
NSLog(@"location:{lat:%f; lon:%f; accuracy:%f}", location.coordinate.latitude, location.coordinate.longitude, location.horizontalAccuracy);
[self uploadLoction:location.coordinate];
}
不过值得注意的是,在退出的时候不要忘记关掉持续定位,否则退出账号后还是会在后台显示定位。
- (void)endUpLoadLocation
{
//关闭持续定位
[self.locationManager stopUpdatingLocation];
}
地理编码与逆地理编码
逆地理编码(坐标转地址)为例源码:
#import <AMapSearchKit/AMapSearchKit.h>
#import "ReGeocodeAnnotation.h"
<AMapSearchDelegate>
@property(strong,nonatomic)AMapSearchAPI *search;
{
AMapReGeocodeSearchRequest *regeo = [[AMapReGeocodeSearchRequest alloc] init];
regeo.location = [AMapGeoPoint locationWithLatitude:myMapView.centerCoordinate.latitude longitude:myMapView.centerCoordinate.longitude];
regeo.requireExtension = YES;
[self.search AMapReGoecodeSearch:regeo];
}
/* 逆地理编码回调. */
- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response
{
if (response.regeocode != nil)
{
[MBProgressHUD hideHUDForView:self.view];
self.newAddressBlock(response.regeocode.formattedAddress);
NSLog(@"addressComponent :%@",response.regeocode.addressComponent);
[self.navigationController popViewControllerAnimated:YES];
}
}
注意在地理编码与逆地理编码的解析中会使用到一些类文件,可以在高德的SDK中直接Copy过来使用。
关于根据地址解析出经纬度.使用系统自带的方法和使用高德的方法。
[[FBLocationManger shareManger]getUserGeography:@"XXXXXXXXX"];
[FBLocationManger shareManger].bolck = ^(CLLocationCoordinate2D loca) {
NSLog(@"高德地址: %f %f",loca.longitude,loca.latitude);
[myMapView setCenterCoordinate:loca];
[myMapView setHeight:Scale_Y(200)];
MyAnnation *annotation = [[MyAnnation alloc]initWithCoordinate:loca];
[myMapView addAnnotations:@[annotation]];
};
[[CCLocationManager shareLocation]getCodeFormAdress:@"杭州市滨江区建业路511号华业大厦" withCode:^(CLLocationCoordinate2D locationCorrrdinate) {
NSLog(@"系统自带的地址: %f %f",locationCorrrdinate.longitude,locationCorrrdinate.latitude);
[myMapView setCenterCoordinate:locationCorrrdinate];
[myMapView setHeight:Scale_Y(200)];
MAPointAnnotation *annotation = [[MAPointAnnotation alloc]init];
annotation.coordinate = locationCorrrdinate;
[myMapView addAnnotations:@[annotation]];
}];
你会发现使用系统自带的你想地址解析API解析出来的经纬度更加准确,图中A是目的地,使用高德经纬度解析解析出来的是B。
综上所述,我们可以总结下:
关于地理编码与逆地理编码
根据地址反编译出经纬度,使用系统的方法比使用高德的方法更精确;
根据经纬度获得地址,使用高德的方法比使用系统的方法更精确;系统的方法定位出的地址有偏差。
遇到的问题
-
iOS 自带的地理位置反编译,是需要联万维网的,内网开发中是不回有数据返回的。
iOS 自带的地理位置反编译返回的是拼音?那是因为你的手机语言设置不是汉语环境,而是英语环境。
-
路线规划一直失败
那是因为你的 Bundle ID在高德地图中心没有注册。错误码:Error Domain=AMapNaviErrorDomain Code=2 "CalculateRouteError: 2(10008)" UserInfo={NSLocalizedDescription=CalculateRouteError: 2(10008)}
[AMapFoundationKit][Info] : Key验证失败 - INVALID_USER_SCODE[28680c9926f2c44f88fdbc20476884e7]
-
若项目中使用地图相关类,一定要检测内存情况,因为地图是比较耗费App内存的,因此在根据文档实现某地图相关功能的同时,我们需要注意内存的正确释放,大体需要注意的有需在使用完毕时将地图、代理等滞空为nil,注意地图中标注(大头针)的复用,并且在使用完毕时清空标注数组等。
- (void)clearMapView{ self.mapView = nil; self.mapView.delegate =nil; self.mapView.showsUserLocation = NO; [self.mapView removeAnnotations:self.annotations]; [self.mapView removeOverlays:self.overlays]; [self.mapView setCompassImage:nil]; }
-
出现格格状
(1)没有网络来验证用户key,(2)APPKey 不对应 ,(3)bundle文件没导入正确
-
iOS 大头针怎么固定在地图中间,且移动地图 怎么获取到 大头针下的具体位置经纬度
把大头针放在 视图中心
myMapView.centerCoordinate 是高德地图 API中定义的获取地图的方法。__weak typeof(self)weakSelf = self; [MBProgressHUD showHUDAddedTo:self.view animated:YES]; [[CCLocationManager shareLocation] getAdressFormCode:myMapView.centerCoordinate.latitude :myMapView.centerCoordinate.longitude withAddress:^(NSString *addressString) { [MBProgressHUD hideHUDForView:weakSelf.view]; weakSelf.newAddressBlock(addressString); [weakSelf.navigationController popViewControllerAnimated:YES]; }];
-
如何定位到当前位置
//定位显示在地图中心 - (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation { if (!onceUserCenter) { coordinate = userLocation.coordinate; [myMapView setCenterCoordinate:coordinate]; } onceUserCenter = YES; }
-
在其它地方想回到开始的定位位置使用下面的方法:
[myMapView setCenterCoordinate:coordinate animated:YES];
提交AppStore必读
引入了 IDFA,可能会造成您的应用提交 AppStore 审核失败,请您认真阅读下文。-
编译报错
增加GLKit.framework系统库就可以了
-
宽度设置WIDTH 地图是两个屏幕的宽度。
//正常显示 newMapView = [[MAMapView alloc] initWithFrame:CGRectMake(0, Scale_Y(50), view1.frame.size.width, Scale_Y(200))]; //地图是两个屏幕的宽度 newMapView = [[MAMapView alloc] initWithFrame:CGRectMake(0, Scale_Y(50), WIDTH, Scale_Y(200))];
-
关于地图显示太大,世界级地图?
//定位显示在地图中心 - (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation { if (!onceUserCenter) { coordinate = userLocation.coordinate; [myMapView setCenterCoordinate:coordinate]; [myMapView setHeight:Scale_Y(200)]; } onceUserCenter = YES; }
这样就可以显示当前位置,并展示小区域地图了
-
如果你真的遇到问题,解决不了,加QQ群聊吧
-
如果你不知道到哪里找对应的开发文档,请搜索,搜索可以解决绝大部分问题。
-
如何实现用户方向的展示?
//根据头部信息显示方向 -(void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation{ if(nil == userLocation || nil == userLocation.heading || userLocation.heading.headingAccuracy < 0) { return; } //获取头部方向 CLLocationDirection theHeading = userLocation.heading.magneticHeading; float direction = theHeading; if(nil != _myLocationAnnotationView) { if (direction > 180) { direction = 360 - direction; } else { direction = 0 - direction; } _myLocationAnnotationView.image = [self.myLocationImage imageRotatedByDegrees:-direction]; } }
-
如何实现GPS信号的强弱的展示?
GPS信号是没有直接数据的展示的.我们需要从回调方法的location参数中拿到horizontalAccuracy属性和verticalAccuracy属性的值,这两个值就是判断精度圈大小的,如果GPS信号弱的话,那么精度圈就会很大,horizontalAccuracy属性和verticalAccuracy这两个值就会很大.相反,如果GPS信号强的话,那么两者的值就会很小.
typedef enum : NSUInteger { strengthGradeBest = 1,//信号最好 可精确到0-20米 strengthGradeBetter,//信号强 可精确到20-100米 strengthGradeAverage,//信号弱 可精确到100-200米 strengthGradeBad,//信号很弱 ,200米开外 } strengthGrade; - (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode{ locationModel.gpsStrength = [self gpsStrengthWithLocation:location]; } #pragma mark ---GPS信号强弱--- -(strengthGrade)gpsStrengthWithLocation:(CLLocation *)location{ if (location.horizontalAccuracy>200 &&location.verticalAccuracy >200) { return strengthGradeBad; } if (location.horizontalAccuracy>100 &&location.verticalAccuracy >100&&location.horizontalAccuracy<200 &&location.verticalAccuracy <200) { return strengthGradeAverage; } if (location.horizontalAccuracy>20 &&location.verticalAccuracy >20&&location.horizontalAccuracy<100 &&location.verticalAccuracy <100) { return strengthGradeBetter; } if (location.horizontalAccuracy<20 &&location.verticalAccuracy <20) { return strengthGradeBest; } return strengthGradeBad; }
小结
以上只是比较基础的地图应用,如果后续有用的新的功能,或者新的发现,会持续更新本文......
如有错误,欢迎留言指正,谢谢。