google 地图开发记录

业务需求 :给别人发送当前位置功能
点击查看别人的位置信息,
功能需求 :
1. 点击发送位置按钮, 进入地图界面. 定位到自己当前的位置
2. 定位到自己当前位置的大头针, 不是地图自带的小圆点, 而是自己的头像.
3. 移动屏幕, 大头针始终在屏幕中心. 当停止移动时, 将大头针设置为当前位置.
4. 获得大头针所在位置附近的商圈, 在列表中显示.
5. 点击列表中的位置信息, 大头针跟着移动.
6. 点击定位按钮, 大头针回到自己当前位置
7. 以上所有移动地图的操作 都要保证大头针始终在屏幕中心.
8. 查看别人发送的位置, 别人的位置需要显示头像, 我的位置显示默认小蓝点, 默认显示别人的位置, 点击定位按钮后,回到我的位置.


  • 功能需求一: 点击发送位置按钮, 进入地图界面. 定位到自己当前的位置
    google 设置地图中心点的方式是(这个记不清了….)

-(void)startFollowing:(id)sender{
    // 指南针
    _mapView.settings.compassButton = NO;
    // 定位按钮是否显示
    _mapView.settings.myLocationButton = NO;
    // Listen to the myLocation property of GMSMapView.
    [_mapView addObserver:self
               forKeyPath:@"myLocation"
                  options:NSKeyValueObservingOptionNew
                  context:NULL];
    // Ask for My Location data after the map has already been added to the UI.
    if (self.provider.paramters.mapType == TPMapType_Receive_GoogleMap) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _mapView.myLocationEnabled = YES;
        });
    }
}

#pragma mark - KVO updates 跟随态代理
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
    if (!_firstLocationUpdate) {
        // If the first location update has not yet been recieved, then jump to that
        // location.
        _firstLocationUpdate = YES;
        CLLocation *location = [change objectForKey:NSKeyValueChangeNewKey];
        if (!location) {
            _mapView.camera = [GMSCameraPosition cameraWithTarget:location.coordinate
                                                             zoom:14];
        }
    }
}
// 点击定位按钮, 回到自己的位置
- (IBAction)locationBtnDidClick:(id)sender {
    CLLocation *location =  _mapView.myLocation ;
    if (!location || !CLLocationCoordinate2DIsValid(location.coordinate)) {
        return;
    }

    _mapView.layer.cameraLatitude = location.coordinate.latitude;
    _mapView.layer.cameraLongitude = location.coordinate.longitude;
    _mapView.layer.cameraBearing = 0.0;

    // Access the GMSMapLayer directly to modify the following properties with a
    // specified timing function and duration.

    CAMediaTimingFunction *curve =
    [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    CABasicAnimation *animation;

    animation = [CABasicAnimation animationWithKeyPath:kGMSLayerCameraLatitudeKey];
    animation.duration = 2.0f;
    animation.timingFunction = curve;
    animation.toValue = @(location.coordinate.latitude);
    [_mapView.layer addAnimation:animation forKey:kGMSLayerCameraLatitudeKey];

    animation = [CABasicAnimation animationWithKeyPath:kGMSLayerCameraLongitudeKey];
    animation.duration = 2.0f;
    animation.timingFunction = curve;
    animation.toValue = @(location.coordinate.longitude);
    [_mapView.layer addAnimation:animation forKey:kGMSLayerCameraLongitudeKey];

    animation = [CABasicAnimation animationWithKeyPath:kGMSLayerCameraBearingKey];
    animation.duration = 2.0f;
    animation.timingFunction = curve;
    animation.toValue = @0.0;
    [_mapView.layer addAnimation:animation forKey:kGMSLayerCameraBearingKey];

    // Fly out to the minimum zoom and then zoom back to the current zoom!
    CGFloat zoom = _mapView.camera.zoom;
    NSArray *keyValues = @[@(zoom), @(zoom - 2), @(zoom)];
    CAKeyframeAnimation *keyFrameAnimation =
    [CAKeyframeAnimation animationWithKeyPath:kGMSLayerCameraZoomLevelKey];
    keyFrameAnimation.duration = 2.0f;
    keyFrameAnimation.values = keyValues;
    [_mapView.layer addAnimation:keyFrameAnimation forKey:kGMSLayerCameraZoomLevelKey];

}
  • 功能需求二: 2. 定位到自己当前位置的大头针, 不是地图自带的小圆点, 而是自己的头像.
    这个就比较难了, 因为需要替换自带小圆点,翻了不少Stack Overflow 看到上面说谷歌谷歌没有提供自定义蓝色小圆点的方法. 有人提出了用 CLLocationManager来做, 于是这个功能的实现我是借助了CLLocationManager实现的
    第一步需要将小圆点隐藏 只需要在功能需求一 中将_mapView.myLocationEnabled 设置成NO 即可, 但是结果是功能一的定位按钮没有了. 我断点看了一下是 _mapView.myLocation 为nil. 所以我借助CLLocationManager定位成功后, 用经纬度实例化一个CLLocation *_location. 在功能一点击定位按钮处检查, 如果_location有就用_location.
    第二步, 在CLLocationManager获得经纬后 添加大头针.
    第三步, 移动屏幕中心到当前经纬度.
#pragma send location show my icon
- (void)createCCLocationManage{
    //定位管理器
    _locationManager = [[CLLocationManager alloc]init];
    //如果没有授权则请求用户授权
    if ([CLLocationManager authorizationStatus]==kCLAuthorizationStatusNotDetermined){
        [_locationManager requestWhenInUseAuthorization];
    }else if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedWhenInUse){
        //设置代理
        _locationManager.delegate=self;
        //设置定位精度
        _locationManager.desiredAccuracy=kCLLocationAccuracyBest;
        //定位频率,每隔多少米定位一次
        CLLocationDistance distance= 10.0;//十米定位一次
        _locationManager.distanceFilter=distance;
        //启动跟踪定位
        [_locationManager startUpdatingLocation];
    }
}


-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    CLLocation *location=[locations firstObject];//取出第一个位置
    CLLocationCoordinate2D coordinate=location.coordinate;//位置坐标
    // NSLog(@"经度:%f,纬度:%f,海拔:%f,航向:%f,行走速度:%f",coordinate.longitude,coordinate.latitude,location.altitude,location.course,location.speed);
    [self addPointAnnotationWithLatitude:coordinate.latitude longitude:coordinate.longitude];
    // 第三步, 移动屏幕中心到当前经纬度.
    if (!_camera) {
        GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:coordinate.latitude                                                            longitude:coordinate.longitude                                                                  zoom:16];
        _mapView.camera = camera;
    }
    _location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
}

//添加大头针
- (IBAction)addPointAnnotationWithLatitude:(double)latitude longitude:(double)longitude{

    GMSMarker *anotherSydneyMarker = [[GMSMarker alloc] init];
  //   TPMapAnnotationView 这是自定义类
    TPMapAnnotationView *annotationView = [TPMapAnnotationView new];
    [annotationView addAvatarUrl:self.provider.paramters.avatarUrl];
    annotationView.frame = CGRectMake(0, 0,40, 50);

    anotherSydneyMarker.iconView = annotationView;


    anotherSydneyMarker.position = CLLocationCoordinate2DMake(latitude, longitude);

    anotherSydneyMarker.map = _mapView;

    _markers = [NSMutableArray arrayWithObject:anotherSydneyMarker];
}
  • 功能需求三: 移动屏幕, 大头针始终在屏幕中心. 当停止移动时, 将大头针设置为当前位置.
    这个功能我暂时没有找到正规的api实现, 所以我用的是一个比较土的办法.
    首先我下self.view(不是_mapView)上新建了一个ViewA(用它假装成大头针), ViewA比mapView后添加, 所以会出现在屏幕上. 第二步, 我注释了功能二中添加大头针的调用. 第三步, 在每一次地图拖拽完成后, 通过代理获得当前地图中心的经纬度, 在给ViewA一个动画, 假装大头针扎在了地图上.
#pragma mark - GMSMapViewDelegate 地图拖拽完成
- (void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position{
// 加段动画
// ....
// 通过经纬度获得周边信息
[self reverseGeoShortUrlShareWithLatitude:position.target.latitude longitude:position.target.longitude];
}
  • 功能需求四: 获得大头针所在位置附近的商圈, 在列表中显示.
    严格的讲这个功能我并没有实现. 在讲这个功能之前, 先要说一下google留的坑. 在大概2015年5月份左右, google 将地图分成了三部分 . 但是他的中文文档没有更新, 所以不要相信googleMap的官方文档, 至少到今天(2017年02月19日19:10:48)为止, 他还没有更新.
 pod 'GoogleMaps'
 pod 'GooglePlaces'
 还有一个记不清得了...

在GoogleMaps 这个库中提供了一个方法获得周边信息的.但是返还的信息好简陋啊, 不忍直视.

-(IBAction)reverseGeoShortUrlShareWithLatitude:(double)latitude longitude:(double)longitude{

    //坐标
    NSString* _coordinateXText = [NSString stringWithFormat:@"%.6f", longitude];
    NSString* _coordinateYText = [NSString stringWithFormat:@"%.6f", latitude];

    pt = (CLLocationCoordinate2D){[_coordinateYText floatValue], [_coordinateXText floatValue]};
    //    GMSCameraPosition zoomAtCoordinate:pt forMeters:kCLLocationAccuracyNearestTenMeters perPoints:<#(CGFloat)#>
    __weak typeof(self) weakSelf = self;
    GMSReverseGeocodeCallback  handler = ^(GMSReverseGeocodeResponse *response, NSError *error) {
        GMSAddress *address = response.firstResult;

        if (self.provider.paramters.mapType == TPMapType_Receive_GoogleMap && address) {

            NSLog(@"Geocoder result: %@", address);
            NSLog(@"geocoder country %@",address.country);
            NSLog(@"geocoder locality %@", address.locality);
            NSLog(@"geocoder subLocality %@", address.subLocality);
            NSLog(@"geocoder thoroughfare %@",address.thoroughfare);
            NSLog(@"geocoder administrative %@", address.administrativeArea);
        }else if (self.provider.paramters.mapType == TPMapType_Send_GoogleMap){


        }
    };
    [_geocoder reverseGeocodeCoordinate:pt completionHandler:handler];
}

后来我翻到了 pod ‘GooglePlaces’库. 要在appdelegate里为这个类注册. 在申请key时要勾选place 这一项.

[GMSServices provideAPIKey:@"googleKey"];
[GMSPlacesClient provideAPIKey:@"googleKey"];

GooglePlaces 提供的周边信息要比GoogleMaps详细的多, 但是, 但是, 还是有缺陷, 我没找到_placesClient 怎么获得指定经纬度的周边信息, 也就是说, 下面这个方法只能获得当前位置的经纬度信息…..操了. 这个我暂时也没找到合适的api, 只能先用GoogleMaps的简陋数据…..

 [_placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *placeLikelihoodList, NSError *error){
        if (error != nil) {
            NSLog(@"Pick Place error %@", [error localizedDescription]);
            return;
        }
        if (placeLikelihoodList != nil) {
            if (self.provider.paramters.mapType == TPMapType_Send_GoogleMap){
                NSMutableArray *poiList = [NSMutableArray array];
                NSInteger i = 0;
                for (GMSPlaceLikelihood *likelihood in [placeLikelihoodList likelihoods]) {
                    GMSPlace *place = [likelihood place];
                    TPMapBottomViewParamter *paramter = [TPMapBottomViewParamter new];
                    paramter.latitude = place.coordinate.latitude;
                    paramter.longitude = place.coordinate.longitude;
                    paramter.name = place.name;
                    paramter.addressText = place.formattedAddress;
                    paramter.showMarker = i == 0? YES : NO;
                    i++;
                    [poiList addObject:paramter];
                }
                [weakSelf fillBottomLocationViewWithParamters:poiList];
            }
        }
    }];
  • 功能需求五 点击列表中的位置信息, 大头针跟着移动.
// 实现地图中心移动. 
 GMSCameraUpdate *newCamera = [GMSCameraUpdate setTarget:CLLocationCoordinate2DMake(paramter.latitude, paramter.longitude)];
    [_mapView moveCamera:newCamera];
  • 功能需求六 点击定位按钮, 大头针回到自己当前位置
    这个在功能需求一种介绍过, 不在赘述.

  • 功能需求七 在功能五中已经保证.

  • 功能需求八 查看别人发送的位置, 别人的位置需要显示头像, 我的位置显示默认小蓝点, 默认显示别人的位置, 点击定位按钮后,回到我的位置.
    这个别的都不难, 就是说一点, 先显示别人的位置

// 在viewWillAppear 中设置即可, 
_camera = [GMSCameraPosition cameraWithLatitude:self.provider.paramters.latitudeD                               longitude:self.provider.paramters.longitudeD
    zoom:16];

好了 以上介绍完毕, 如果有不对的地方, 请多指教 邮箱 [email protected], 多谢!!!


下面是我在开发是看到的不错的文章,
拉起第三方 http://www.jianshu.com/p/183f66da9d9c
开发详细步骤: http://www.jianshu.com/p/2a1bf192e496


Google Places API http://blog.csdn.net/wangjia55/article/details/8996256


遇到的坑

一.依赖库

虽然googleMap 官方提供了cocoapod的集成方法。 但有时候也会出现问题所以贴出几个依赖库,已备检查。
http://stackoverflow.com/questions/17920813/undefined-symbols-for-architecture-i386-glkmatrix3identity-referenced-from

AVFoundation.framework
CoreData.framework
CoreLocation.framework
CoreText.framework
GLKit.framework
ImageIO.framework
libc++.dylib
libicucore.dylib
libz.dylib
OpenGLES.framework
QuartzCore.framework
SystemConfiguration.framework

坑二

下载的demo 特意去申请的key。 但是提示

ClientParametersRequest failed, 3 attempts remaining (0 vs 10). Error Domain=com.google.HTTPStatus Code=400 "(null)" UserInfo={data=<..........>}

原因是 key 与 buildID 没有对应起来

你可能感兴趣的:(第三方)