第 9 章 设备传感器 上一章介绍了Cordova中加速度传感器的调用方法,除了加速度传感器外,Cordova也提供了对其他设备传感器的调用方法。对设备传感器的使用主要分为对地理位置的获取和方向的获取。为了能够方便开发者调用,Cordova封装了用来访问GPS信息的Geolocation类和用来访问设备方向的Compass类。 本章的主要内容有: 使用getCurrentPosition()方法获取设备在当前所处的坐标位置。 利用watchPosition()方法对设备所处的坐标位置进行监听。 使用getCurrentHeading()方法获取设备当前的朝向。 利用watchHeading()方法监听设备的朝向。 9.1 利用Geolocation类获取设备地理信息 GPS是现代智能手机中一个非常重要的功能,能够实现全球范围内对设备的实时定位,近几年来在一些社交应用中也经常见到它发挥作用。比如微信的“摇一摇”功能就利用了GPS来获取用户的地理位置。图9-1是微信利用GPS获取两用户之间距离的一个例子。 图9-1 微信通过GPS计算用户之间的距离 Cordova利用类Geolocation来获取设备所在地理位置的坐标。对于一些不支持GPS的设备,Geolocation类还可以借助IP地址、RFID、Wi-Fi、蓝牙的MAC地址或GSM/CDMA手机ID的网络信号做出推断,以保证其兼容性。 虽然基于IP地址、GSM基站等方法都可以保证返回设备所在地理位置的经度和纬度,但是这样得到的结果却不一定准确。在实际开发时仍要充分考虑到不支持GPS的设备可能存在的误差。 9.2 利用getCurrentPosition()方法获取 设备所在坐标 在Geolocation类中,最基本的方法就是getCurrentPosition()了,它的作用是通过一个Positon对象来返回设备所在的位置信息。范例9-1是使用getCurrentPosition()方法的一个例子。 首先在命令行执行命令添加插件:cordova plugin add cordova-plugin-geolocation。 【范例9-1】使用getCurrentPosition()方法获取设备位置信息。 01 02 03 04 05 使用getCurrentPosition()方法获取设备位置信息 06 07 29 37 38 39

获取当前位置信息

40
41

你的当前位置:

42

经度:

43

纬度:

44

海拔高度:

45

精度:

46

海拔准确度:

47

航向:

48

速度:

49

时间:

50 51 运行后设备上将显示出当前所处的位置信息,如图9-2所示。 图9-2 使用getCurrentPosition()获取当前的位置信息 本范例使用了方法getCurrentPosition()来获取设备所处的位置信息,如第12行所示。与其他Cordova所提供的API相似,该方法同样是将处理成功和失败的两个方法onSuccess和onError作为参数。 不过在onSuccess()方法中默认会传送一个position对象,该对象保存了两个子对象coords和timestamp。其中coords封装了一系列与设备当前所处地理位置有关的信息,比如经度、纬度、海拔等。timestamp对象则只是单纯地记录了coords对象被创建的时间。表9-1中是coords对象中所包含的各个属性以及它们的含义。 表9-1 coords对象中封装的属性 名称 类型 说明 latitude 数字 以十进制小数表示的纬度信息 longitude 数字 以十进制小数表示的经度信息 altitude 数字 海拔高度,单位为米 accuracy 数字 经度和纬度的精确度 altitudeAccuracy 数字 海拔高度的精确度 heading 数字 当前设备运动状态,以正北为零点显示当前运动方向与正北方向的角度 speed 数字 以米/秒为单位显示当前设备运动的速度 第16~23行可以看到这些属性的使用,需要注意的是timestamp并不只是单纯的以小时来记录coords被创建的时间,其中还包含了年、月以及所处的时区等信息。 在Cordova中并不是单纯地使用从GPS中获取的数据来显示位置信息的,当GPS不可用时,Cordova还会利用网络甚至是与基站的通信来判断当前的位置。因此即使在不具备GPS功能的设备上也可以使用该功能。 9.3 使用watchPosition()方法 监控设备的位置变化 本节将介绍一种与上一节中的getCurrentPosition()方法具有类似功能的方法,只不过它能够对设备的位置信息进行连续监控。看到这一点不知道读者有没有联想到什么?没错,那就是在上一章介绍过的加速度传感器,也有着类似的方法用来监视设备加速度的变化。范例9-2中展示了watchPosition()方法的使用。 【范例9-2】使用watchPosition()方法监视设备的位置变化。 01 02 03 04 05 使用watchPosition()方法监视设备的位置变化 06 07 36 44 45 46

获取当前位置信息

47
48

你的当前位置:

49

经度:

50

纬度:

51

海拔高度:

52

精度:

53

海拔准确度:

54

航向:

55

速度:

56

时间:

57 58 通过范例不难看出,该方法与在上一节中介绍过的getCurrentPosition()方法在用法上非常类似,只是增加了一个参数option。那么参数option又是干什么的呢? 从Cordova提供的文档中可以了解到,这里的option实际上是一个geolocationOptions类型的可选参数,用来定义对程序获取位置信息的一些设置。它的具体属性以及说明参见表9-2。 表9-2 option对象中的属性 名称 类型 说明 frequency 整数型 用来定义获取设备位置信息的频率,单位是毫秒 enableHighAccuracy 布尔类型 提供一个表明应用程序希望获得最佳可能结果的提示,可以理解为是否希望使用高精确度的定位 timeout 整数型 两次获取设备位置信息所允许的最大时间间隔,单位为毫秒 maximumAge 整数型 应用程序将接受一个缓存的位置信息,该缓存的位置信息的年龄不大于此参数设定值,单位是毫秒。 实际上maximumAge属性的出现是由于最初对frequency的定义不符合W3C规范,因此设计了这个参数计划在将来用它来取代frequency。 如果说watchPosition()的用法就只有这些,也许已经足够了;但是在某些应用上却可能会有一些瑕疵,比如当用户想要停止获取设备位置时该怎么办呢?总不可能让用户去“后台”强行关闭掉程序吧。 事实上还有一个方法是笔者没有介绍到的,那就是在范例第33行用到的clearWatch()方法。该方法只需要一个参数,就是当前所监视位置信息所使用的id,那么这个id又是从哪里来的呢?再回过头来看范例第14行。在watchPosition()方法开始执行时会返回一个id数值,而在本范例中将这个数值保存在了变量watchID中,因此当想要停止对设备位置的监控时只需要执行: navigator.geolocation.clearWatch(watchID); 说到这里,笔者突然想到了一种非常不错的表白方法,读者可以去尝试一下,当然还是利用本节中介绍的watchPosition()方法来实现。既然能够利用watchPosition()方法实现对设备位置信息的获取,那么如果把具有同样类型的应用装在女神的手机里会怎样呢? 当然这不是教唆读者利用这种方法去监视女神的动态,然后半路拦截;而是有更加浪漫的方法。既然能够获取女神的位置了,是不是可以将这些坐标在屏幕上显示出来呢?那么如果拿着女神的手机在田野里绕着一个心形的图案跑一圈屏幕上是不是就会显示出一个心形呢? 好了,话就说这么多,能不能成功就看各位读者的动手能力了。 9.4 设备方向的获取 本章前面的内容介绍了怎样获取设备的位置信息,不知道读者在学完了这些内容之后,有没有考虑过这些API能够实现什么样的功能呢?反正笔者当时思考了很久,结果近乎荒诞地想到了指南针。这是一个非常愚蠢的想法,因为从坐标信息到方向信息完全是两个不搭边的功能。但是这也说明了一个问题,指南针作为移动设备在地理信息方面的应用实在是太深入人心了,如图9-3所示的就是一款指南针应用的界面。 图9-3 一款指南针应用的界面 有过开发应用经验的读者可能都知道,想要开发一个具有动画效果(如指南针的转动)的应用是很难的,但是如果用HTML 5就能够比较轻松地实现这样的动画效果。那么是不是可以用Cordova来实现一款指南针呢?答案是肯定的。 如果要实现指南针的功能,就必须要有能够获取设备方向的API,这正是在本节所要介绍的内容。 首先在命令行执行命令添加插件:cordova plugin add cordova-plugin-device-orientation。 【范例9-3】利用getCurrentHeading()方法获取设备的当前朝向。 01 02 03 04 05 利用getCurrentHeading()方法获取设备的当前朝向 06 07 24 25 26

显示当前的方向

27 28 运行结果如图9-4所示,得出的结果是笔者的手机所朝的方向。 图9-4 手机上获取了当前设备方向 读者在使用Cordova的指南针功能时一定要在真机上进行测试,否则会获取失败。 getCurrentHeading()方法的使用与其他Cordova中的API非常类似,依然是在回调函数onSuccess中对获取到的结果进行处理。该方法传递来的结果是一个heading对象,它包含了表9-3所示的4个属性。 表9-3 heading对象中的属性 名称 类型 说明 magneticHeading 数字 用来表示设备在某一时刻相对于正北方向偏移的角度,它的值从0~359.99不等 trueHeading 数字 与magneticHeading相同,但是当当前的方向不确定时,比如你现在正在北极,那么该属性的值将是负的 headingAccuracy 数字 测量的方向可能存在的误差 timestamp 整数 用来记录获取设备方向的时间,单位是毫秒 9.5 监视设备方向的两种方法 上一节介绍了使用Cordova获取设备方向的方法,细心的读者可能已经发现笔者在本节要介绍的两种传感器了。但是为什么要把它们合在一起介绍呢?除了都可以用来获取与地理位置有关的信息之外,也许还会有其他的原因。 那就是这两种传感器的用法实在是太相近了,在获取设备的位置信息时,可以使用getCurrentPosition()和 watchPosition(),而在获取设备的方向时除了可以使用上一节中介绍的getCurrentHeading()之外,还可以使用另一个方法watchHeading()来对设备的方向进行监视。 【范例9-4】使用watchHeading()方法监视设备方向。 01 02 03 04 05 使用watchHeading()方法监视设备方向 06 07 33 41 42 43

显示当前的方向

44
45

46

47 48 运行结果如图9-5所示,如果点击屏幕顶部的“显示当前方向”字样,则会停止对设备方向的监视。 图9-5 监视设备方向所得的结果 通过对范例的阅读可以发现,watchHeading()的使用与9.3节介绍的watchPosition()方法是一样的,因此这里就不再对它的用法做过多的重复介绍了。这里要说的是除了watchHeading(),在Cordova中还有一种方法能够实现对方向的监控,那就是watchHeadingFilter()方法,它的作用是当设备方向发生变化时执行相对应的onSuccess函数。 【范例9-5】使用watchHeadingFilter()方法监视设备方向。 01 02 03 04 05 使用watchHeadingFilter()方法监视设备方向 06 07 33 41 42 43

显示当前的方向

44
45

46

47 48 运行结果如图9-6所示,读者可以通过静止手机或是将手机转动一定的角度来观察屏幕上数据的变化。 图9-6 使用watchHeadingFilter()方法监视设备方向 从范例中可以看出,该watchHeadingFilter()方法在使用上与范例9-4中的watchHeading()方法非常类似,但是在第13行中可以看到,该方法的option参数发生了变化,因为在此处所使用的option变成了一个compassOptions类型的对象,开发者可以通过它来设置当设备变化了多少角度时程序才会有所反应。 接下来对这两种方法进行比较,不过既然同时存在两种方法,而没有废除掉其中的一种,那就说明两种方法都存在可取的地方。watchHeading()方法用来按照一定的时间周期对设备的方向进行监视,这就会导致一个问题,如果这个频率设得太高,比如每隔1ms就获取一次方向数据,即使是八核的CPU也会有些吃力;而如果频率设得太低,则获取的数据又不够精确。 使用watchHeadingFilter()方法就不需要考虑这样的问题,但是却会遇到另一种麻烦,比如将option参数中的值设的过大,如范例中的10,就会造成设备不够灵敏。但是一般来说将这个值设为1就足够使用了。但是假设此时遇到了一个爱动的用户,它尝试让手机在指尖旋转,那么就会发生可怕的事情,虽然手机不会爆炸,但至少这个程序很难再保持正常运行了。