指南针开发

ios 定位新功能----在程序中实现定位功能
转:http://www.2cto.com/kf/201501/369336.html
2015-01-14      0个评论    来源:haogaoming123的专栏   
收藏    我要投稿

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

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

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

?


1

#import <corelocation corelocation.h=""></corelocation>

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

?


1

2

3

4

CLLocationManager *locManager = [[CLLocationManager alloc] init];

locManager.delegate = self;

[locManager startUpdatingLocation];

//[locManager stopUpdatingLocation];

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

?


1

2

3

4

5

6

7

8

9

- (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属性的值不是非常精确,除非移动速度变化很小

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

- (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停止位置管理器。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

- (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个表示不同精度的枚举值

?


1

2

3

4

5

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,它指定设备(水平或垂直)移动多少米后才将另一个更新发送给委托。下面的代码使用适合跟踪长途跋涉者的设置启动位置管理器:

?


1

2

3

4

5

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:

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

?


1

2

3

4

5

6

7

8

9

- (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(这种描述更适合写入日志而不是显示给用户)。下面演示了利用这个方法处理航向更新:

?


1

2

3

4

5

6

7

8

9

- (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(真实航向)。

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

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

#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-29 12:04:17

指南针开发的相关文章

ym——android源代码大放送(实战开发必备)

转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! 目录 PATH 列表 卷序列号为 000A-8F50 E:. │  javaapk.com文件列表生成工具.bat │  使用说明.txt │  免费下载很多其它源代码.url │  文件夹列表.txt │ ├─android web应用 │      jqmDemo_static.zip │      jqmMobileDemo-master.zip │      jqmMobil

Android 自定义View视图

创建全新的视图将满足我们独特的UI需求. 本文介绍在指南针开发中会用到的罗盘的界面UI,通过继承View类实现的自定义视图,以此来深刻了解自定义视图. 实现效果图: 源代码: 布局文件activity_main(其中CompassView继承View类): <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.

Android学习笔记-传感器开发之利用传感器和Tween开发简易指南针

本次我们学习Android传感器的开发,前面已经介绍过了,tween的使用,所以,我们可以结合传感器与tween动画,开发简易的指南针. 首先先介绍一下传感器的相关知识, 在Android应用程序中使用传感器要依赖于android.hardware.SensorEventListener接口.通过该接口可以监听传感器的各种事件.SensorEventListener接口的代码如下: package android.hardware; public interface SensorEventLis

安卓传感器开发之指南针

代码很简单,主要是一些常用传感器的监听,指南针还是挺好用的. 布局代码 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="

iOS 开发者旅途中的指南针 - LLDB 调试技术

文章转载于:iOS 开发者旅途中的指南针 - LLDB 调试技术 今天给大家介绍的内容,无关乎任何功能性开发技术,但又对开发的效率影响至深,这就是调试技术. 何为调试呢,比如我们用 print 函数在指定位置进行输出,来定位某些节点的变量内的取值: 12345 let result = parseJSON("[1,2,3]");print(result); result = parseJSON("error");print(result);4 相信我们大家看到类似这

iOS开发入门教程_iOS开发视频教程

iOS开发入门教程 (Object-C.网络编程.多线程.蓝牙.二维码.Cocos2D.OpenGL)适合人群:初级课时数量:34课时用到技术:IOS,Object-C,OpenGL,XCode,Cocos 2D涉及项目:Cocos+2D.Game Kit蓝牙数据处理等咨询QQ:1840215592 iOS开发入门教程详细查看:http://www.ibeifeng.com/goods-471.html1.1.课程目标iOS开发入门教程内容的目标是初学者入门,让入门者提高,让所有人符合企业招聘的

AppCan 移动应用开发项目源码分享:嗡嗡旅游App开发

开发者介绍:老家湖北巴东好山好水,神农溪.巴人河.三里城等都是旅游好去处.中秋节回了趟老家,看到家乡的原生态景色吸引了大批游客,由此萌发了想法:用移动技术开发一个App试水,把家乡景点介绍给更多的人.于是,耗时一个月的<嗡嗡旅游>应运而生,特此将项目源码分享给广大AppCan开发者. 项目实现功能 用户注册.登录,游记查看和发布,查看辖区内景区.酒店.交通.攻略等信息,内容收藏.评论和分享,查看地图,景区门票.酒店电话预定等. 项目使用插件 引导页 引导页3张图片采用的是全屏显示的slider

android源码大放送(实战开发必备),免费安卓demo源码,例子大全文件详细列表

免费安卓demo源码,例子大全文件详细列表 本列表源码永久免费下载地址:http://www.jiandaima.com/blog/android-demo 卷 yunpan 的文件夹 PATH 列表 卷序列号为 0000-73EC E:. │ jiandaima.com文件列表生成.bat │ 例子大全说明.txt │ 本例子永久更新地址~.url │ 目录列表2016.03.10更新.txt │ ├─前台界面 │ ├─3D标签云卡片热门 │ │ Android TagCloudView云标签

iOS开发之──传感器使用 (转载)

在实际的应用开发中,会用到传感器,下面首先介绍一下iphone4的传感器,然后对一些传感器的开发的API作一简单介绍. AD:WOT2015 互联网运维与开发者大会 热销抢票 在实际的应用开发中,会用到传感器,下面首先介绍一下iphone4的传感器,然后对一些传感器的开发的API作一简单介绍 一. iPhone 4的传感器技术 进入正题,iPhone 4到底用上了哪些传感器呢? 1) 影像传感器 简单说就是相机镜头,由于只牵涉到微光学与微电子,没有机械成份在里头,即便加入马达.机械驱动的镜头,这