zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

iOS 地图 MKWebView(在中国是使用高德地图)

ios中国 地图 高德 使用
2023-09-11 14:22:56 时间

一、定位服务介绍

iOS中有三个定位服务组件:

(1)Wifi定位,通过查询一个Wifi路由器的地理位置的信息。比较省电,iPod touch和iPad也可以采用。

(2)蜂窝基站定位,通过移动运用商基站定位。也适合有3G版本的iPod touch和iPad

(3)GPS卫星定位,通过3-4颗GPS定位位置定位,最为准确,但是耗电量大,不能遮挡。

二、项目引用库介绍

(1)CoreLocation.framework 是开发定位服务应用程序的框架

(2)MapKit.framework 是开发地图应用的框架


三、位置模拟

模拟器定位有6个选项:


(1)None

(2)Custom Location

(3)Apple

(4)City Bicycle Ride

(5)City Run

(6)Freeway Drive

单机"Custom Location"选项,会弹出如下对话框,要求设置待模拟的经纬度


设置后,会触发 “-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations;” 函数,打印如下:


locations = (

    "<+26.06400300, +119.3107300> +/- 5.00m (speed -1.00 mps / course -1.00) @ 7/1/16, 4:05:32 PM China Standard Time"

)

注意:如果设置的不是 “Custom Location”,其他的选项我试了一遍,都会报错

触发 “-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error” 函数,打印如下


didFailWithError,error = Error Domain = kCLErrorDomainCode = 0 "(null)"

四、项目实战

(1)ViewController.h

//
//  ViewController.h
//  MapDemo
//
//  Created by 555chy on 6/30/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import <UIKit/UIKit.h>
//CoreLocation.framework
#import <CoreLocation/CoreLocation.h>
//MapKit.framework
#import <MapKit/MapKit.h>
//标注@protocol<MKAnnotation>
#import "CustomAnnotation.h"

@interface ViewController : UIViewController<CLLocationManagerDelegate, MKMapViewDelegate>


@end

(2)ViewController.m

//
//  ViewController.m
//  MapDemo
//
//  Created by 555chy on 6/30/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()
@property MKMapView *mapView;
@property CLLocationManager *locationManager;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    [self initLocationManager];
    
    [self initMapView];
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - CLLocationManagerDelegate 获取当前位置
-(void)initLocationManager {
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    /*
     extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0);
     extern const CLLocationAccuracy kCLLocationAccuracyBest;
     extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
     extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
     extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
     extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;
     
     desired  渴望的、想得到的
     accuracy 精确性、准确性
     */
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    /*
     *  distanceFilter
     *  Discussion: 讨论、谈论、详述、论述
     *      Specifies the minimum update distance in meters. Client will not be notified of movements of less
     *      than the stated value, unless the accuracy has improved. Pass in kCLDistanceFilterNone to be
     *      notified of all movements. By default, kCLDistanceFilterNone is used.
     */
    //locationManager.distanceFilter = kCLDistanceFilterNone;
    self.locationManager.distanceFilter = 1000.0f;
}

/*
 This method is deprecated. If locationManager:didUpdateLocations: is implemented, this method will not be called.
 当位置变化超过distanceFilter时,会调用该方法(该方法已被废弃,将不会触发该方法)
 */
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    NSLog(@"didUpdateToLocation, newLocation = %@, oldLocation = %@", newLocation, oldLocation);
}

/*
 chronological 按时间的前后循序排列的、编年的
 locations is an array of CLLocation objects in chronological order.
 当位置变化超过distanceFilter时,会调用该方法
 */
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    NSLog(@"didUpdateLocations, locations = %@", locations);
}

//如果地图查询错误,则会调用下面的协议函数
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"didFailWithError, error = %@", error);
}

/*
 没有该函数时,运行MKMapView报错
 Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
 除了实现该函数,还要在Info.plist中添加
 NSLocationAlwaysUsageDescription       String  任意的描述语
 NSLocationWhenInUseUsageDescription    String  任意的描述语
 Discussion: Invoked when the authorization status changes for this application.
 */
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    /*
     typedef NS_ENUM(int, CLAuthorizationStatus) {
     // User has not yet made a choice with regards to this application
     kCLAuthorizationStatusNotDetermined = 0,
     
     // This application is not authorized to use location services.  Due
     // to active restrictions on location services, the user cannot change
     // this status, and may not have personally denied authorization
     kCLAuthorizationStatusRestricted,
     
     // User has explicitly denied authorization for this application, or
     // location services are disabled in Settings.
     kCLAuthorizationStatusDenied,
     
     // User has granted authorization to use their location at any time,
     // including monitoring for regions, visits, or significant location changes.
     kCLAuthorizationStatusAuthorizedAlways NS_ENUM_AVAILABLE(NA, 8_0),
     
     // User has granted authorization to use their location only when your app
     // is visible to them (it will be made visible to them if you continue to
     // receive location updates while in the background).  Authorization to use
     // launch APIs has not been granted.
     kCLAuthorizationStatusAuthorizedWhenInUse NS_ENUM_AVAILABLE(NA, 8_0),
     
     // This value is deprecated, but was equivalent to the new -Always value.
     kCLAuthorizationStatusAuthorized NS_ENUM_DEPRECATED(10_6, NA, 2_0, 8_0, "Use kCLAuthorizationStatusAuthorizedAlways") __WATCHOS_PROHIBITED = kCLAuthorizationStatusAuthorizedAlways
     };
     */
    switch (status) {
        case kCLAuthorizationStatusAuthorizedAlways:
            NSLog(@"didChangeAuthorizationStatus, status = %d(%@)", status, @"kCLAuthorizationStatusAuthorizedAlways");
            [self.locationManager startUpdatingLocation];
            break;
        case kCLAuthorizationStatusAuthorizedWhenInUse:
            NSLog(@"didChangeAuthorizationStatus, status = %d(%@)", status, @"kCLAuthorizationStatusAuthorizedWhenInUse");
            [self.locationManager startUpdatingLocation];
            break;
        case kCLAuthorizationStatusDenied:
            NSLog(@"didChangeAuthorizationStatus, status = %d(%@)", status, @"kCLAuthorizationStatusDenied");
            break;
        case kCLAuthorizationStatusNotDetermined:
            NSLog(@"didChangeAuthorizationStatus, status = %d(%@)", status, @"kCLAuthorizationStatusNotDetermined");
            if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
                //应用在前台的时候可以搜到更新的位置信息
                [self.locationManager requestWhenInUseAuthorization];
                //应用在前台和后台(suspend或terminated)都可以获取到更新的位置数据信息
                //[self.locationManager requestAlwaysAuthorization];
                [self.locationManager startUpdatingLocation];
            }
            break;
        case kCLAuthorizationStatusRestricted:
            NSLog(@"didChangeAuthorizationStatus, status = %d(%@)", status, @"kCLAuthorizationStatusRestricted");
            break;
        default:
            break;
    }
}

#pragma mark - initMapView 初始化地图控件
-(void)initMapView {
    self.mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
    self.mapView.zoomEnabled = true;
    self.mapView.scrollEnabled = true;
    self.mapView.showsBuildings = true;
    //显示罗盘
    self.mapView.showsCompass = true;
    self.mapView.showsScale = true;
    self.mapView.showsTraffic = true;
    self.mapView.showsUserLocation = true;
    [self.mapView setDelegate:self];
    
    [self.view addSubview:self.mapView];
    
    /*
     2d坐标
     我这里用的是 中国福建省福州市工人文化宫的坐标
     北纬N26.03‘39“ 东经E119.17‘57“
     */
    CLLocationCoordinate2D coordinate;
    //纬度
    coordinate.latitude = 26.064003;
    //经度
    coordinate.longitude = 119.310730;
    
    //设置地图显示范围
    MKCoordinateSpan coordinateSpan;
    //(0, 180]
    coordinateSpan.latitudeDelta = 0.01;
    //(0, 360]
    coordinateSpan.longitudeDelta = 0.01;
    
    //设置地图中心
    MKCoordinateRegion coordinateRegion;
    coordinateRegion.center = coordinate;
    coordinateRegion.span = coordinateSpan;
    //MKCoordinateRegionMake(<#CLLocationCoordinate2D centerCoordinate#>, <#MKCoordinateSpan span#>)
    
    /*
     hybrid     杂种的、混合的
     satellite  卫星
     flyover    立交桥、高架公路
     
     typedef NS_ENUM(NSUInteger, MKMapType) {
     MKMapTypeStandard = 0,
     MKMapTypeSatellite,
     MKMapTypeHybrid,
     MKMapTypeSatelliteFlyover NS_ENUM_AVAILABLE(10_11, 9_0),
     MKMapTypeHybridFlyover NS_ENUM_AVAILABLE(10_11, 9_0),
     } NS_ENUM_AVAILABLE(10_9, 3_0) __WATCHOS_PROHIBITED;
     */
    [self.mapView setMapType:MKMapTypeStandard];
    [self.mapView setRegion:coordinateRegion animated:YES];
    
    //在中心点创建标记
    [self createAnnotationWithCoordinate:coordinate];
    
    //获取地图中心的地理位置描述
    [self initGeocoderWithCoordinate:coordinate];
}

#pragma mark - MKAnnotation 在相应的坐标点创建标记
-(void)createAnnotationWithCoordinate:(CLLocationCoordinate2D) coordinate {
    CustomAnnotation *annotation = [[CustomAnnotation alloc] initWithCoordinate:coordinate];
    [self.mapView addAnnotation:annotation];
}

#pragma mark - CLGeocoder 将经纬坐标编码对象转化为地理信息的描述对象
-(void)initGeocoderWithCoordinate:(CLLocationCoordinate2D) coordinate {
    
    //MKReverseGeocoder is now deprecated. Use CLGeocoder in CoreLocation instead.
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    //[NSDate date] 是获取当前时间
    CLLocation *location = [[CLLocation alloc] initWithCoordinate:coordinate altitude:kCLDistanceFilterNone horizontalAccuracy:kCLLocationAccuracyBest verticalAccuracy:kCLLocationAccuracyBest timestamp:[NSDate date]];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        //NSLog(@"reverseGeocodeLocation completionHandler, placemarks = %@, error = %@ ", placemarks, error);
        if(error == nil && placemarks.count > 0) {
            for(int i=0;i<placemarks.count;i++) {
                CLPlacemark *placemark = [placemarks objectAtIndex:i];
                /*
                 *  addressDictionary
                 *
                 *  Discussion:
                 *    This dictionary can be formatted as an address using ABCreateStringWithAddressDictionary,
                 *    defined in the AddressBookUI framework.
                 
                @property (nonatomic, readonly, copy, nullable) NSDictionary *addressDictionary;
                
                // address dictionary properties
                @property (nonatomic, readonly, copy, nullable) NSString *name; // eg. Apple Inc.
                @property (nonatomic, readonly, copy, nullable) NSString *thoroughfare; // street name, eg. Infinite Loop
                @property (nonatomic, readonly, copy, nullable) NSString *subThoroughfare; // eg. 1
                @property (nonatomic, readonly, copy, nullable) NSString *locality; // city, eg. Cupertino
                @property (nonatomic, readonly, copy, nullable) NSString *subLocality; // neighborhood, common name, eg. Mission District
                @property (nonatomic, readonly, copy, nullable) NSString *administrativeArea; // state, eg. CA
                @property (nonatomic, readonly, copy, nullable) NSString *subAdministrativeArea; // county, eg. Santa Clara
                @property (nonatomic, readonly, copy, nullable) NSString *postalCode; // zip code, eg. 95014
                @property (nonatomic, readonly, copy, nullable) NSString *ISOcountryCode; // eg. US
                @property (nonatomic, readonly, copy, nullable) NSString *country; // eg. United States
                @property (nonatomic, readonly, copy, nullable) NSString *inlandWater; // eg. Lake Tahoe
                @property (nonatomic, readonly, copy, nullable) NSString *ocean; // eg. Pacific Ocean
                @property (nonatomic, readonly, copy, nullable) NSArray<NSString *> *areasOfInterest; // eg. Golden Gate Park
                 thorough 彻底的、全面的、充分的、详尽的
                 thorough 通行、大道、大街
                 */
                NSLog(@"reverseGeocodeLocation placemark, locality = %@,%@, thoroughfare = %@,%@, name = %@", placemark.locality, placemark.subLocality, placemark.thoroughfare, placemark.subThoroughfare, placemark.name);
            }
        }
    }];
}

@end

(3)CustomAnnotation.h

//
//  CustomAnnotation.h
//  MapDemo
//
//  Created by 555chy on 7/1/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

//大头针标注
@interface CustomAnnotation : NSObject<MKAnnotation>

@property CLLocationCoordinate2D coordinate;
@property NSString *title;
@property NSString *subtitle;

-(id)initWithCoordinate:(CLLocationCoordinate2D)coordinate;

@end

(4)CustomAnnotation.m

//
//  CustomAnnotation.m
//  MapDemo
//
//  Created by 555chy on 7/1/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "CustomAnnotation.h"

@implementation CustomAnnotation

-(id)initWithCoordinate:(CLLocationCoordinate2D)coordinate {
    if(self = [super init]) {
        self.coordinate = coordinate;
        self.title = @"标题";
        self.subtitle = @"子标题";
    }
    return self;
}

@end

五、运行截图