在程序中实现定位功能

Core Location是iOS SDK中一个提供设备位置的框架。可以使用三种技术来获取位置:GPS、蜂窝或WiFi。在这些技术中,GPS最为精准,如果有GPS硬件,Core Location将优先使用它。如果设备没有GPS硬件(如WiFi iPad)或使用GPS获取当前位置时失败,Core Location将退而求其次,选择使用蜂窝或WiFi。

Core Location的大多数功能是由位置管理器(CLLocationManager)提供的,可以使用位置管理器来指定位置更新的频率和精度,以及开始和停止接收这些更新。

要使用位置管理器,必须首先将框架Core Location加入到项目中,再导入其接口文件:

#import <CoreLocation/CoreLocation.h>

接下来,需要分配并初始化一个位置管理器实例、指定将接收位置更新的委托并启动更新:

CLLocationManager *locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
[locManager startUpdatingLocation];
//[locManager stopUpdatingLocation];

位置管理器委托(CLLocationManagerDelegate)有两个与位置相关的方法:

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{

}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{

}

第一个方法处理定位成功,manager参数表示位置管理器实例;locations为一个数组,是位置变化的集合,它按照时间变化的顺序存放。如果想获得设备的当前位置,只需要访问数组的最后一个元素即可。集合中每个对象类型是CLLocation,它包含以下属性:

coordinate — 坐标。一个封装了经度和纬度的结构体。

altitude — 海拔高度。正数表示在海平面之上,而负数表示在海平面之下。

horizontalAccuracy — 位置的精度(半径)。位置精度通过一个圆表示,实际位置可能位于这个圆内的任何地方。这个圆是由coordinate(坐标)和horizontalAccuracy(半径)共同决定的,horizontalAccuracy的值越大,那么定义的圆就越大,因此位置精度就越低。如果horizontalAccuracy的值为负,则表明coordinate的值无效。

verticalAccuracy — 海拔高度的精度。为正值表示海拔高度的误差为对应的米数;为负表示altitude(海拔高度)的值无效。

speed — 速度。该属性是通过比较当前位置和前一个位置,并比较它们之间的时间差异和距离计算得到的。鉴于Core Location更新的频率,speed属性的值不是非常精确,除非移动速度变化很小。

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *curLocation = [locations lastObject];

    if(curLocation.horizontalAccuracy > 0)
    {
        NSLog(@"当前位置:%.0f,%.0f +/- %.0f meters",curLocation.coordinate.longitude,
              curLocation.coordinate.latitude,
              curLocation.horizontalAccuracy);
    }

    if(curLocation.verticalAccuracy > 0)
    {
        NSLog(@"当前海拔高度:%.0f +/- %.0f meters",curLocation.altitude,curLocation.verticalAccuracy);
    }
}

应用程序开始跟踪用户的位置时,将在屏幕上显示一个是否允许定位的提示框。如果用户禁用定位服务,iOS不会禁止应用程序运行,但位置管理器将生成错误。

第二个方法处理这种定位失败,该方法的参数指出了失败的原因。如果用户禁止应用程序定位,error参数将为kCLErrorDenied;如果Core Location经过努力后无法确认位置,error参数将为kCLErrorLocationUnknown;如果没有可供获取位置的源,error参数将为kCLErrorNetwork。

通常,Core Location将在发生错误后继续尝试确定位置,但如果是用户禁止定位,它就不会这样做;在这种情况下,应使用方法stopUpdatingLocation停止位置管理器。

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    if(error.code == kCLErrorLocationUnknown)
    {
        NSLog(@"Currently unable to retrieve location.");
    }
    else if(error.code == kCLErrorNetwork)
    {
        NSLog(@"Network used to retrieve location is unavailable.");
    }
    else if(error.code == kCLErrorDenied)
    {
        NSLog(@"Permission to retrieve location is denied.");
        [manager stopUpdatingLocation];
    }
}

可根据实际情况来指定位置精度。例如,对于只需确定用户在哪个国家的应用程序,没有必要要求Core Location的精度为10米。要指定精度,可在启动位置更新前设置位置管理器的desiredAccuracy。有6个表示不同精度的枚举值:

extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation;
extern const CLLocationAccuracy kCLLocationAccuracyBest;
extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;

对位置管理器启动更新后,更新将不断传递给位置管理器委托,直到停止更新。您无法直接控制这些更新的频率,但可使用位置管理器的属性distanceFilter进行间接控制。在启动更新前设置属性distanceFilter,它指定设备(水平或垂直)移动多少米后才将另一个更新发送给委托。下面的代码使用适合跟踪长途跋涉者的设置启动位置管理器:

CLLocationManager *locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
locManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
locManager.distanceFilter = 200;
[locManager startUpdatingLocation];

P.s. 定位要求的精度越高、属性distanceFilter的值越小,应用程序的耗电量就越大。

位置管理器有一个headingAvailable属性,它指出设备是否装备了磁性指南针。如果该属性为YES,就可以使用Core Location来获取航向(heading)信息。接收航向更新与接收位置更新极其相似,要开始接收航向更新,可指定位置管理器委托,设置属性headingFilter以指定要以什么样的频率(以航向变化的度数度量)接收更新,并对位置管理器调用方法startUpdatingHeading:

位置管理器委托协议定义了用于接收航向更新的方法。该协议有两个与航向相关的方法:

- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
{
    return YES;
}

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{

}

第一个方法指定位置管理器是否向用户显示校准提示。该提示将自动旋转设备360°。由于指南针总是自我校准,因此这种提示仅在指南针读数剧烈波动时才有帮助。当设置为YES后,提示可能会分散用户的注意力,或影响用户的当前操作。

第二个方法的参数newHeading是一个CLHeading对象。CLHeading通过一组属性来提供航向读数:magneticHeading和trueHeading。这些值的单位为度,类型为CLLocationDirection,即双精度浮点数。这意味着:

如果航向为0.0,则前进方向为北;

如果航向为90.0,则前进方向为东;

如果航向为180.0,则前进方向为南;

如果航向为270.0,则前进方向为西。

CLHeading对象还包含属性headingAccuracy(精度)、timestamp(读数的测量时间)和description(这种描述更适合写入日志而不是显示给用户)。下面演示了利用这个方法处理航向更新:

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    if(newHeading.headingAccuracy >=0)
    {
        NSString *headingDesc = [NSString stringWithFormat:@"%.0f degrees (true), %.0f degrees (magnetic)",newHeading.trueHeading,newHeading.magneticHeading];

        NSLog(@"%@",headingDesc);
    }
}

trueHeading和magneticHeading分别表示真实航向和磁性航向。如果位置服务被关闭了,GPS和wifi就只能获取magneticHeading(磁场航向)。只有打开位置服务,才能获取trueHeading(真实航向)。

下面的代码演示了,当存在一个确定了经纬度的地点,当前位置离这个地点的距离及正确航向:

#import "ViewController.h"

#define kDestLongitude 113.12 //精度
#define kDestLatitude 22.23 //纬度
#define kRad2Deg 57.2957795 // 180/π
#define kDeg2Rad 0.0174532925 // π/180

@interface ViewController ()
@property (strong, nonatomic) IBOutlet UILabel *lblMessage;
@property (strong, nonatomic) IBOutlet UIImageView *imgView;
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) CLLocation *recentLocation;

-(double)headingToLocation:(CLLocationCoordinate2D)desired current:(CLLocationCoordinate2D)current;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
    self.locationManager.distanceFilter = 1609; //1英里≈1609米
    [self.locationManager startUpdatingLocation];

    if([CLLocationManager headingAvailable])
    {
        self.locationManager.headingFilter = 10; //10°
        [self.locationManager startUpdatingHeading];
    }
}

/*
 * According to Movable Type Scripts
 * http://mathforum.org/library/drmath/view/55417.html
 *
 *  Javascript:
 *
 * var y = Math.sin(dLon) * Math.cos(lat2);
 * var x = Math.cos(lat1)*Math.sin(lat2) -
 * Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
 * var brng = Math.atan2(y, x).toDeg();
 */
-(double)headingToLocation:(CLLocationCoordinate2D)desired current:(CLLocationCoordinate2D)current
{
    double lat1 = current.latitude*kDeg2Rad;
    double lat2 = desired.latitude*kDeg2Rad;
    double lon1 = current.longitude;
    double lon2 = desired.longitude;
    double dlon = (lon2-lon1)*kDeg2Rad;

    double y = sin(dlon)*cos(lat2);
    double x = cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(dlon);

    double heading=atan2(y,x);
    heading=heading*kRad2Deg;
    heading=heading+360.0;
    heading=fmod(heading,360.0);
    return heading;
}

//处理航向
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    if(self.recentLocation!=nil && newHeading.headingAccuracy>=0)
    {
        CLLocation *destLocation = [[CLLocation alloc] initWithLatitude:kDestLatitude longitude:kDestLongitude];

        double course = [self headingToLocation:destLocation.coordinate current:self.recentLocation.coordinate];

        double delta = newHeading.trueHeading - course;

        if (abs(delta) <= 10)
        {
            self.imgView.image = [UIImage imageNamed:@"up_arrow.png"];
        }
        else
        {
            if (delta > 180)
            {
                self.imgView.image = [UIImage imageNamed:@"right_arrow.png"];
            }
            else if (delta > 0)
            {
                self.imgView.image = [UIImage imageNamed:@"left_arrow.png"];
            }
            else if (delta > -180)
            {
                self.imgView.image = [UIImage imageNamed:@"right_arrow.png"];
            }
            else
            {
                self.imgView.image = [UIImage imageNamed:@"left_arrow.png"];
            }
        }
        self.imgView.hidden = NO;
    }
    else
    {
        self.imgView.hidden = YES;
    }
}

//处理定位成功
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *curLocation = [locations lastObject];

    if(curLocation.horizontalAccuracy >= 0)
    {
        self.recentLocation = curLocation;

        CLLocation *destLocation = [[CLLocation alloc] initWithLatitude:kDestLatitude longitude:kDestLongitude];

        CLLocationDistance distance = [destLocation distanceFromLocation:curLocation];

        if(distance<500)
        {
            [self.locationManager stopUpdatingLocation];
            [self.locationManager stopUpdatingHeading];
            self.lblMessage.text = @"您已经到达目的地!";
        }
        else
        {
            self.lblMessage.text = [NSString stringWithFormat:@"距离目的地还有%f米",distance];
        }
    }
}

//处理定位失败
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    if(error.code == kCLErrorLocationUnknown)
    {
        NSLog(@"Currently unable to retrieve location.");
    }
    else if(error.code == kCLErrorNetwork)
    {
        NSLog(@"Network used to retrieve location is unavailable.");
    }
    else if(error.code == kCLErrorDenied)
    {
        NSLog(@"Permission to retrieve location is denied.");
        [self.locationManager stopUpdatingLocation];
        self.locationManager = nil;
    }
}

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

@end

在程序中实现定位功能

时间: 2024-10-09 02:01:46

在程序中实现定位功能的相关文章

ios 定位新功能----在程序中实现定位功能

Core Location是iOS SDK中一个提供设备位置的框架.可以使用三种技术来获取位置:GPS.蜂窝或WiFi.在这些技术中,GPS最为精准,如果有GPS硬件,Core Location将优先使用它.如果设备没有GPS硬件(如WiFi iPad)或使用GPS获取当前位置时失败,Core Location将退而求其次,选择使用蜂窝或WiFi. Core Location的大多数功能是由位置管理器(CLLocationManager)提供的,可以使用位置管理器来指定位置更新的频率和精度,以及

微信小程序后台持续定位功能使用

微信小程序团队在7月30日更新了 基础库 2.8.0 其中新添加了小程序后台持续定位功能和联系定位的接口 从上到下分别是 1.wx.onLocationChange//监听位置实时变化 2.wx.stopLocationUpdate//关闭监听实时位置变化,前后台都停止消息接收 3.wx.startLocationUpdate//开启小程序进入前台时接收位置消息 4.wx.startLocationUpdataBackground//开启小程序进入前后台时均接收位置消息 详细信息可查看https

HOW TO: 在 Visual C# .NET 应用程序中提供文件拖放功能

本文假定您熟悉下列主题: Windows 窗体列表框控件 Windows 窗体事件处理 生成示例的步骤 列表框控件提供了您需要处理的两个拖放事件: DragEnter 和 DragDrop. 当您在控件的边界内拖动对象时,便会发生DragEnter 事件:该事件用于确定当前拖动的对象是不是您要放到控件上的对象. 在将一个或多个文件拖到控件上时,需要处理此事件. 这使得在将对象拖到控件上方时,能够根据所拖动的对象显示相应的图标. 将拖动的对象释放到控件上时,会发生DragDrop 事件. 通过处理

安卓中实现定位功能

大家好,今天我们讲一下比较热门的定位服务,闲话少叙直奔主题.因为是使用高德地图所以首先咱们就得先在高德开发平台上注册一个账号,具体注册流程在这里就不一一赘诉了,下面就讲一下再注册成功之后如何申请key,要申请key就得需要发布版NAS1码与测试版NAS1码以及工程的包地址,下面就讲一下如何获取NAS1码. 第一步:申请NAS1 1.若是想获得发布版的NAS1码,就得先把你的工程打包,打包成功后你就会获得一个以.jsk为后缀名的文件,打包的时候你会设置一个密码,一会用到这个文件的储存路径以及你设置

在.NET程序中实现HttpServer功能

最近在实现一个可视化数据解析工具,需要在Wpf程序中实现一个HttpServer,实现RESTfull接口,可以接收客户端(DTU或其他嵌入式设备)发送的请求.这种接口在ASP.NET中很容易实现,在Wpf程序中,需要有一个HttpServer才可以,开始考虑将Node.js签入到Wpf中,基本的功能可以实现,但是太麻烦了,程序的可移植性降低了,最好是在Wpf程序中内置这样的一个HttpServer. 从CodeProject找到两篇文章:http://www.codeproject.com/A

微信小程序中悬浮窗功能的实现(主要探讨和解决在原生组件上的拖动)

问题场景 所谓悬浮窗就是图中微信图标的按钮,采用fixed定位,可拖动和点击. 这算是一个比较常见的实现场景了. 为什么要用cover-view做悬浮窗?原生组件出来背锅了~ 最初我做悬浮窗用的不是cover-view,而是view. 这是简化的代码结构: index.wxml: <view class="move-view" style=" top:{{top}}px;left:{{left}}px;" bindtap="goToHome"

自定义提示用户授权使用地理定位功能时的提示语

以前程序的地理定位功能若查询GPS授权情况,返回的是CLAuthorizationStatus.NotDetermined,意思是授权状态未定. 需要在使用CoreLocation前调用方法 requestWhenInUseAuthorization() 或者 requestAlwaysAuthorization() 并在Info.plist中加入两个缺省没有的字段 NSLocationAlwaysUsageDescription NSLocationWhenInUseUsageDescript

浅谈百度地图的简单开发之结合方向传感器实现定位功能(三)

  今天我们来谈下百度地图的定位功能.在此之前我已经将百度地图的基本地图大概说了下,事实上百度地图的基本功能还有非常多的内容. 感兴趣的能够到百度地图的开发人员的官网看看.今天就開始来讲下百度地图中的定位功能. 今天所讲的百度地图所涉及的内容主要有:基本定位的实现.自己定义定位图标.结合方向传感器定位,选择定位中的几种模式(罗盘模式,普通模式,尾随模式). 一.基本定位的实现: 所谓定位无非就是获取到一个地方所处地球的经纬度坐标.这个反映到地图中就是一个点.可是怎么去实现一个定位呢?? 首先,须

IOS 开启定位功能 CLLocationManager 介绍-简单使用

iOS 中的定位功能,主要在 CoreLocation库中,需要用到位置管理器 CLLocationManager 来完成绝大多数事情. 要使用 CLLocationManager 首先需要一个对象~ 以及对它进行简单的设置,最后开启定位功能, 就开始定位了,定位成功或者失败后都会调用代理方法返回信息 1 CLLocationManager *manger; 2 3 manger = [[CLLocationManager alloc] init]; //初始化 4 5 manger.deleg