SlideShare une entreprise Scribd logo
1  sur  184
PhoneGap API Getting Started




范圣刚,princetoad@gmail.com, www.tfan.org
Accelerometer
What we will learn?
• 三维⽅方位解析
• 设备⽅方位查询
• 加速度检测
三维⽅方位的定义:x, y, z轴
轴向⽰示例
• 平放桌⾯面:X:0, Y:0, Z:10
• 沿左边竖⽴立:X:10, Y:0, Z:0
• 沿底边竖⽴立:X:0, Y:10, Z:0
• 沿顶边倒⽴立:X:0, Y:-10, Z:0
Accelerometer的应⽤用
• ⽤用户交互的⼀一种⽅方式
• 游戏:Midnight Bowling,Driving Game
• 趣味:摇⼀一摇功能
Accelerometer两个主要API
• 查询设备的当前⽅方位
• 判断加速度
accelerometer.getCurrentAcceleration




   • 说明:使⽤用该⽅方法查询设备的当前⽅方位
   • 参数:
    • onAccelSuccess:当加速度计数据有效时调⽤用;
    • onAccelFailure:提取加速度计数据出错时调⽤用;
Acceleration对象
• 回调onSuccess时会传递⼀一个acceleration对象作为
 参数
• 四个属性值:
 • x:在x轴⽅方向上的加速度量(m/s^2)
 • y: 在y轴⽅方向上的加速度量(m/s^2)
 • z: 在z轴⽅方向上的加速度量(m/s^2)
 • timestamp:以毫秒计的时间戳
Demo:Accel01
iPad⽅方位获取
设备⽅方位的观测
• ⽅方法1:⼿手动实现阶段性的⽅方向检查
• 定义加速度计观测
• iOS Core Motion的实现
accelerometer.watchAcceleration


• 说明:
 • 定期获得移动设备的加速度。
 • 每次获得⼀一个Acceleration对象时,onAccelSuccess回调函数就会被
  调⽤用。

 • 通过设置acceleratorOptions的frequency参数指定间隔时间,以毫
  秒计。
clearWatch和watchID
• 使⽤用watchAcceleration返回的watchID作为
 clearWatch的参数来取消观察
Accelerometer注意问题
• 加速度计的返回值问题:操作系统不同,返回值
 的范围也有差异
• 加速度计硬件检测问题
• accelOptions的默认值:如果accelOptions参数被
 忽略,那么默认每10秒中测量⼀一次加速度计数
 据。(accelerometerOptions只有⼀一个选项:
 frequency)
• iPhone Quirks
Camera
Camera API简介
PhoneGap Camera API提供给应⽤用处理照⽚片的能
⼒力,可以直接从摄像头采集或者从设备的相册获取
照⽚片。
当提取照⽚片时,API可以返回指向设备⽂文件系统上
的image⽂文件URI,或者以base64编码字符串的⽅方式
返回image⽂文件内容。
Camera API只提供了⼀一个⽅方法:
navigator.camera.getPicture。但是getPicture的
cameraOptions参数提供了⾮非常丰富的配置选项!
访问照⽚片(拍照,相⽚片库)
  navigator.camera.getPicture( onCameraSuccess,
       onCameraError, [ cameraOptions ] );


• 说明:
• 同样需要传⼊入两个函数:onCameraSuccess,
 onCameraError。成功得到照⽚片的时候调⽤用
 onCameraSuccess函数;⽤用户取消或者获取照⽚片失败的
 时候会调⽤用onCameraError函数。

• cameraOptions是⼀一个可选的配置选项。(后⾯面会详细
 介绍)
Camera API Demo1 - 拍照
getPicture代码⽰示例
  <!DOCTYPE html>
<html>
  <head>
    <title>Example Camera</title>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <meta name="viewport" id="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" />
    <script type="text/javascript" charset="utf-8" src="cordova-2.0.0.js"></script>
    <script type="text/javascript" charset="utf-8">
       function onBodyLoad() {
         alert("onBodyLoad");
         document.addEventListener("deviceready", onDeviceReady, false);
       }

      function onDeviceReady() {
        navigator.notification.alert("onDeviceReady");
      }

      function takePhoto() {
        //alert("takePhoto");
        navigator.camera.getPicture(onCameraSuccess, onCameraError,
        	   	     { quality: 50, destinationType: Camera.DestinationType.FILE_URI });
        // navigator.camera.getPicture(onCameraSuccess, onCameraError);
      }

      function onCameraSuccess(imageURL) {
        navigator.notification.alert("onCameraSuccess: " + imageURL);
      }

      function onCameraError() {
         navigator.notification.alert("onCameraError");
      }
    </script>
  </head>
  <body onload="onBodyLoad()">
    <h1>Example Camera-1</h1>
    <p>
      使⽤用 PhoneGap Camera API
      <br />
      <input type="button" value="拍张照⽚片" onclick="takePhoto();">
    </p>
  </body>
</html>
cameraOptions的默认⾏行为
• 从camera获得照⽚片
• 返回指向图⽚片⽂文件的URI
• iOS和Android的注意问题
Camera API Demo 2 - 拍照并在⻚页⾯面显⽰示


                    和前⼀一个例⼦子的主要代码差异

 function onCameraSuccess(imageURL) {
   navigator.notification.alert("onCameraSuccess: " + imageURL);
   //得到⽤用于显⽰示图⽚片的div的id
   ic = document.getElementById('imageContainer');
   //使⽤用从camera程序得到的URL写⼀一个img标签,并且输出到刚才得到的div。
   ic.innerHTML = '<img src="' + imageURL + '" width="50%" />';
 }
效果
cameraOptions - quality

	        	{   quality : 75,
    		        destinationType : Camera.DestinationType.DATA_URL,
    		        sourceType : Camera.PictureSourceType.CAMERA,
    		        allowEdit : true,
    		        encodingType: Camera.EncodingType.JPEG,
    		        targetWidth: 100,
    		        targetHeight: 100,
    		        popoverOptions: CameraPopoverOptions,
    		        saveToPhotoAlbum: false };




         quality:保存相⽚片的质量。范围[0, 100](Number)
quality参数的使⽤用和注意事项
• 采⽤用多⾼高质量
 • 保存为⽂文件时,采⽤用多⾼高的照⽚片质量?⽂文件⼤大⼩小,设
  备内存,⺴⽹网络传输...... ⼀一般50%-100%。

 • 使⽤用base64字符串返回时,采⽤用多⾼高的照⽚片质量?字
  符串⻓长度,JS的处理能⼒力。⼀一般50%及以下。

• BlackBerry会忽略quality参数
cameraOptions - destinationType

	        	 { quality : 75,
    		      destinationType : Camera.DestinationType.FILE_URI,
    		      sourceType : Camera.PictureSourceType.CAMERA,
    		      allowEdit : true,
    		      encodingType: Camera.EncodingType.JPEG,
    		      targetWidth: 100,
    		      targetHeight: 100,
    		      popoverOptions: CameraPopoverOptions,
    		      saveToPhotoAlbum: false };




         destinationType: 返回的格式。在
         navigator.camera.DestinationType中定义(Number)


     Camera.DestinationType = {
        DATA_URL : 0,                // 以base64编码字符串格式返回照⽚片内容
        FILE_URI : 1                 // 返回image⽂文件的URI
     };
destinationType的使⽤用场景
• FILE_URI
                   巨⻓长的滚动条
 • 在⻚页⾯面上显⽰示;
 • 保存到相册;
 • 拷⻉贝到其他位置。
• DATA_URL
 • 保存到数据库;
 • 上传到服务器。
cameraOptions - sourceType

	      	 { quality : 75,                                        从相册选取的图⽚片
    		     destinationType : Camera.DestinationType.DATA_URL,
    		     sourceType : Camera.PictureSourceType.CAMERA,
    		     allowEdit : true,
    		     encodingType: Camera.EncodingType.JPEG,
    		     targetWidth: 100,
    		     targetHeight: 100,
    		     popoverOptions: CameraPopoverOptions,
    		     saveToPhotoAlbum: false };




         sourceType: 设置照⽚片源。在
         navigator.camera.PictureSourceType中定义(Number)

Camera.PictureSourceType = {
    PHOTOLIBRARY : 0,
    CAMERA : 1,
    SAVEDPHOTOALBUM : 2
};
sourceType注意事项
• 如果不设置sourceType参数,默认会使⽤用camera
 抓取照⽚片;
• 在⼤大多数平台上,设置sourceType为
 PHOTOLIBRARY或SAVEDPHOTOALBUM效果是⼀一样
 的;
• BlackBerry会忽略这个参数。
cameraOptions - allowEdit

	      	 { quality : 75,
    		     destinationType : Camera.DestinationType.DATA_URL,
    		     sourceType : Camera.PictureSourceType.CAMERA,
    		     allowEdit : true,
    		    encodingType: Camera.EncodingType.JPEG,
    		    targetWidth: 100,
    		    targetHeight: 100,
    		    popoverOptions: CameraPopoverOptions,
    		    saveToPhotoAlbum: false };




     allowEdit: 选取前是否允许简单的编辑。(Boolean)
allowEdit注意事项
• 适⽤用平台
  • iOS可以在确定选取前对相⽚片进⾏行移动和缩放;
  • Android等都不⽀支持。
cameraOptions - encodingType

	      	 { quality : 75,
    		     destinationType : Camera.DestinationType.DATA_URL,
    		     sourceType : Camera.PictureSourceType.CAMERA,
    		     allowEdit : true,
    		     encodingType: Camera.EncodingType.JPEG,
    		     targetWidth: 100,
    		     targetHeight: 100,
    		     popoverOptions: CameraPopoverOptions,
    		     saveToPhotoAlbum: false };




         encodingType: 选择返回image⽂文件的编码。在
         navigator.camera.EncodingType中定义(Number)


     Camera.EncodingType = {
         JPEG : 0,                // 以JPEG格式编码image
         PNG : 1                  // 以PNG格式编码image
     };
encodingType注意事项
• ⼤大部分平台默认是JPEG格式。(照⽚片通常是JPEG)
cameraOptions - targetWidth & targetHeight

	        	 { quality : 75,
    		       destinationType : Camera.DestinationType.DATA_URL,
    		       sourceType : Camera.PictureSourceType.CAMERA,
    		       allowEdit : true,
    		       encodingType: Camera.EncodingType.JPEG,
    		       targetWidth: 1024,
    		       targetHeight: 768,
    		      popoverOptions: CameraPopoverOptions,
    		      saveToPhotoAlbum: false };




         targetWidth: 设定照⽚片宽度,以像素为单位。(Number)
         targetHeight: 设定照⽚片⾼高度,以像素为单位。(Number)
宽⾼高⽐比的注意事项
• 可以单独指定宽度或者⾼高度,照⽚片会相应的缩放。如果两个都同
 时指定,照⽚片会按照最⼩小的宽⾼高⽐比设置。

• 例如: 原⽐比例是1000:500(1/2), 设置500:300, ⾼高度⽐比1/2, 宽度⽐比3/5, 结
 果是按照较⼩小的1/2缩放。也就是500:250。

• 不管怎么设定,⾼高宽⽐比会被保持。
• 在拍照前,没有办法以编程的⽅方式判断camera的分辨率,以及⽀支
 持的宽⾼高⽐比。因此除了推测及在每款⽀支持的设备上进⾏行测试以
 外,没有⽅方法能够在应⽤用内⾮非常精确的设定这些值。
cameraOptions - mediaType
	       	 { quality : 75,
    	 	     destinationType : Camera.DestinationType.DATA_URL,
    	 	     sourceType :
Camera.PictureSourceType.PHOTOLIBRARY,
    	   	      allowEdit : true,
    	   	      encodingType: Camera.EncodingType.JPEG,
    	   	      targetWidth: 100,
    	   	      targetHeight: 100,
               mediaType: Camera.MediaType.PICTURE,
    	 	        popoverOptions: CameraPopoverOptions,
    	 	        saveToPhotoAlbum: false };




            mediaType: 设置从哪类媒体中选择。仅在
            PictureSourceType为PHOTOLIBRARY或SAVEDPHOTOALBUM
            时有效。在navigator.camera.MediaType中定义。


Camera.MediaType = {
    PICTURE: 0,             // 只能选择静态图⽚片。返回格式由destinationType字段确定。
    VIDEO: 1,               // 只能选择视频。以FILE_URI格式返回。
    ALLMEDIA : 2            // 可以从所有的媒体类型中选择
cameraOptions - correctOrientation

	        	 { quality : 75,
    		       destinationType : Camera.DestinationType.DATA_URL,
    		       sourceType : Camera.PictureSourceType.CAMERA,
    		       allowEdit : true,
    		       encodingType: Camera.EncodingType.JPEG,
    		       targetWidth: 100,
    		       targetHeight: 100,
             correctOrientation: true,
    		      popoverOptions: CameraPopoverOptions,
    		      saveToPhotoAlbum: false };



         correctOrientation: 采集时针对设备⽅方向翻转图⽚片。(Boolean)
cameraOptions - saveToPhotoAlbum

	        	 { quality : 75,
    		       destinationType : Camera.DestinationType.DATA_URL,
    		       sourceType : Camera.PictureSourceType.CAMERA,
    		       allowEdit : true,
    		       encodingType: Camera.EncodingType.JPEG,
    		       targetWidth: 100,
    		       targetHeight: 100,
             correctOrientation: true,
    		       popoverOptions: CameraPopoverOptions,
    		       saveToPhotoAlbum: false };


         saveToPhotoAlbum: 抓取
         后是否保存到设备相册。
         (Boolean)
cameraOptions - popoverOptions

	        	 { quality : 75,
    		       destinationType : Camera.DestinationType.DATA_URL,
    		       sourceType : Camera.PictureSourceType.CAMERA,
    		       allowEdit : true,
    		       encodingType: Camera.EncodingType.JPEG,
    		       targetWidth: 100,
    		       targetHeight: 100,
             correctOrientation: true,
    		       popoverOptions: CameraPopoverOptions,
    		      saveToPhotoAlbum: false };




         popoverOptions: 指定在iPad上popover的位置。(Boolean)

         仅适⽤用于iOS平台。
平台相关的注意事项
• Android
 • 忽略allowEdit参数
 • Camera.PictureSourceType.PHOTOLIBRARY和
   Camera.PictureSourceType.SAVEDPHOTOALBUM显⽰示同样的
   相册。

• iOS
 • 在某些设备上设置quality⼩小于50以避免内存错误。
 • 当设置使⽤用destinationType.FILE_URI时,照⽚片被保存到应⽤用
   的临时⺫⽬目录。开发者可以使⽤用navigator.fileMgr API删除这些
   ⽂文件以进⾏行空间管理。(参⻅见iOS⽂文件指南)

 • 或者使⽤用camera.cleanup
平台相关的注意事项(续)
• BlackBerry
 • 忽略quality参数
 • 忽略sourceType参数
 • 忽略allowEdit参数
 • 忽略correctOrientation参数
 • 应⽤用必须具有injection权限以在拍照后关闭本地Camera应⽤用
 • 不⽀支持Camera.MediaType
• Windows Phone 7
 • 忽略allowEdit参数
 • 忽略correctOrientation参数
camera.cleanup
• 仅适⽤用于iOS
• 清理camera⽣生成的临时⽂文件

  navigator.camera.cleanup(onSuccess, onFail);

  function onSuccess() {
      console.log("Camera cleanup success.")
  }

  function onFail(message) {
      alert('Failed because: ' + message);
  }
Camera常⻅见问题
• 设备没有摄像头怎么办?
• 应⽤用为什么会Crash?
Capture
What we will learn?
• 图⽚片,视频,⾳音频采集的基本⽅方法
• 采集选项的指定:次数,时⻓长...
• 采集⽂文件数组的遍历和⽂文件属性
• 获取采集⽂文件的格式相关信息
Capture API简介
• PhoneGap Capture API允许应⽤用程序使⽤用移动设备
 上合适的内置应⽤用进⾏行audio,video和image的采
 集。
• 设备默认的camera应⽤用被⽤用来采集image和
 video,同样设备默认的voice recorder应⽤用被⽤用来
 采集⾳音频剪辑。
• PhoneGap Capture API的实现基于W3C Media
 Capture API规范。但是PhoneGap对于规范并没有
 提供完全的⽀支持,有⼀一些选项还没有实现。
Camera vs. Capture
 Q: Camera和Capture都可以采集图⽚片,功能为什么会重
 叠呢?
 A:
1.Camera API的实现在PhoneGap采纳W3C Capture API之
  前,PhoneGap保留Camera API是为了和现有的应⽤用保持
  向下兼容。
2.虽然两个API都可以采集image,但是以不同的⽅方式进⾏行
  操作。Camera API只能采集图⽚片,但是既⽀支持从camera
  拍照,⼜又可以从相册获取;Capture API只能直接从
  camera拍照,并且⽀支持从⼀一个单独的API调⽤用进⾏行多个
  采集。
使⽤用Capture API
• 采集⼀一个或多个audio⽂文件:
 navigator.device.capture.captureAudio(onCaptureSuccess
 , onCaptureError, captureOptions);

• 采集⼀一个或多个image⽂文件:
 navigator.device.capture.captureImage(onCaptureSuccess
 , onCaptureError, captureOptions);

• 采集⼀一个或多个video⽂文件:
 navigator.device.capture.captureVideo(onCaptureSuccess
 , onCaptureError, captureOptions);
Capture演⽰示 - ⾳音频采集




选择⾳音频    录⾳音机   保存结果   采集完成
Capture演⽰示 - 图⽚片采集




选择图⽚片    相机     确定使⽤用   采集完成
Capture演⽰示 - 视频采集




选择视频    开始摄像    完成   摄像完成
Capture 演⽰示 - 采集多个
Capture API 代码实例讲解
 function doCapture() {
   //清空前⾯面的结果
   res.innerHTML = "采集初始化...";
   //从⻚页⾯面读取数量,时⻓长等参数
   var numItems = document.getElementById("numItems").value;
   var capDur = document.getElementById("duration").value;
   //搞定采集类型
   var captureType = document.getElementById("captureType").selectedIndex;
   switch(captureType) {
     case 0:
       //⾳音频采集
       navigator.device.capture.captureAudio(onCaptureSuccess, onCaptureError, {
         duration : capDur,
         limit : numItems
       });
       break;
     case 1:
       //图⽚片采集
       navigator.device.capture.captureImage(onCaptureSuccess, onCaptureError, {
         limit : numItems
       });
       break;
     case 2:
       //视频采集
       navigator.device.capture.captureVideo(onCaptureSuccess, onCaptureError, {
         duration : capDur,
         limit : numItems
       });
       break;
   }
 }
CaptureOption对象
• CaptureAudioOption
• CaptureVideoOption
• CaptureImageOption
captureOptions对象 - 属性
var captureOptions = {duration: 5, limit: 3};


• duration:时⻓长
• limit:采集次数限制
• mode:模式
                         不同采集类型的可⽤用选项


                                        Capture选项
  Capture类型            Duration             Limit   Mode
       Audio                X                   X    X

       Image                                    X    X

       Video                X                   X    X
duration
• duration属性只能应⽤用于⾳音频和视频采集,⽤用于控
 制⼀一个特定媒体采集的⻓长度(以秒为单位)。允
 许应⽤用指定⾳音视频剪辑的最⼤大秒数。
• 当在应⽤用中使⽤用时,⽤用户可以可以录制短于,但
 是不能⻓长于这个属性设置的秒数。
• 注意:⺫⽬目前为⽌止,duration采集选项在Android和
 BlackBerry上还不被⽀支持,只在iOS上录制⾳音频时
 ⽀支持。由于这些限制,现在最好不要在PhoneGap
 应⽤用上使⽤用这个选项。
limit
• 定义每次可执⾏行的最⼤大采集次数。
• 如果设置了这个选项的话,必须要设置1或者更⼤大
  的值才可以。
mode
• 定义为每⼀一种⽀支持的采集类型的录制模式。
• 例如为image采集指定JPGE还是PNG。
onCaptureSuccess的处理过程
      function onCaptureSuccess(fileList) {
        var i, len, htmlStr;
        len = fileList.length;
        //确保采集成功。如果成功的话,length应该 > 0
        if(len > 0) {
          htmlStr = "<p>Results:</p><ol>";
          for( i = 0, len; i < len; i += 1) {
            alert(fileList[i].fullPath);
            htmlStr += '<li><a href="' + fileList[i].fullPath + '">' +
fileList[i].name + '</a></li>';
          }
          htmlStr += "</ol>";
          //这是result内容
          res.innerHTML = htmlStr;
        }
      }




         采集结果是⼀一个MediaFile数组,遍历以获得所有采集结果。
MediaType对象
• 对象属性
 • name: ⽂文件名(⽆无路径信息)(DOMString)
 • fullPaht: ⽂文件全路径,包括⽂文件名(DOMString)
 • type: mime type(DOMString)
 • lastModifiedDate: 最后修改的⽇日期和时间(Date)
 • size: ⽂文件⼤大⼩小(以字节计)(Number)
• ⽅方法
 • MediaFile.getFormatData: 获得媒体⽂文件的格式信息。
getFormatData⽅方法
mediaFile.getFormatData(
    MediaFileDataSuccessCB successCallback,
    [MediaFileDataErrorCB errorCallback]
);
成功的话,回调successCallBack,并传⼊入⼀一个
MediaFileData对象。
MediaFileData对象
• 封装了有关媒体⽂文件的格式信息
• 属性:
 • codecs: ⾳音视频⽂文件的真实格式。(DOMString)
 • bitrate: 内容的平均⽐比特率。如果是图⽚片的话,这个属
  性值为0。(Number)

 • height: 图⽚片或视频的⾼高度(像素)。如果是⾳音频剪辑的
  话,这个属性值为0。(Number)
 • width: 图⽚片或视频的宽度(像素)。 如果是⾳音频剪辑的
  话,这个属性值为0。(Number)
 • duration: ⾳音视频⽂文件的时⻓长(秒)。如果是图⽚片的话这
  个值为0。
onCaptureError的处理
 function onCaptureError(e) {
   var msgText;
   //采集失败的话,清空前⾯面⽣生成的内容。
   res.innerHTML = "";
   //根据API返回的错误码构建⼀一个消息字符串
   switch(e.code) {
     case CaptureError.CAPTURE_INTERNAL_ERR:
       msgText = "内部错误, 摄像头或者⻨麦克⻛风采集图⽚片或⾳音频失败。";
       break;
     case CaptureError.CAPTURE_APPLICATION_BUSY:
       msgText = "摄像头应⽤用或者录⾳音机程序正在被其他采集请求使⽤用。";
       break;
     case CaptureError.CAPTURE_INVALID_ARGUMENT:
       msgText = "传递给API的参数⽆无效。";
       break;
     case CaptureError.CAPTURE_NO_MEDIA_FILES:
       msgText = "⽤用户可能取消了采集过程。";
       break;
     case CaptureError.CAPTURE_NOT_SUPPORTED:
       msgText = "该设备不⽀支持请求的操作。";
       break;
     default:
       //针对其他错误⽣生成⼀一个常规回复
       msgText = "未知错误 (" + e.code + ")";
   }
   //使⽤用alert通知⽤用户
   navigator.notification.alert(msgText, null, "采集出错了!");
 }




                                  错误码定义及其含义
Compass
What we will learn?
• 罗盘原理及地磁轴和实际南北极的差别
• 通过API获得设备朝向
• 设置朝向变更⾃自动通知
• 使⽤用jQuery图⽚片旋转扩展和 Compass API 开发⼀一个
 HTML5的指南针应⽤用
Compass API简介
• Compass API 允许PhoneGap应⽤用通过⼀一个⼤大致对应
 于地球表⾯面的⼆二维平⾯面来获得设备的朝向。⼤大多数
 的智能⼿手机都装有⼀一个物理的罗盘传感器(芯⽚片),
 API就是简单的对芯⽚片进⾏行⼀一个查询,然后返回⼀一个0
 到360度的⼀一个⾓角度来表⽰示设备所指的⽅方向。
• ⾓角度和⽅方向
 • 0度 - 正北(N)
 • 90度 - 正东(E)
 • 180度 - 正南(S)
 • 270度 - 正⻄西(W)
Compass API简介(续)
• Compass API的⼯工作⽅方式和Accelerometer类似,既
 可以⼿手动查询设备的朝向,也可以设定⼀一个watch
 让API以⼀一个指定的频率在设备朝向变化超过设定
 的最⼩小的阀值时向应⽤用报告朝向。
• 注意:不是所有的智能机都具有物理罗盘。
 iPhone 3GS及以后都有,BlackBerry知道7 OS设备
 才有。
Compass 使⽤用演⽰示

得到当前朝向   设置观察者(每秒报告4次),使⽤用jQuery根据罗盘⽅方向⾃自动旋转图⽚片。




          ⼀一个简单的HTML5的指南针应⽤用
获得设备朝向
 • 查询设备朝向的API⽅方法:
    navigator.compass.getCurrentHeading(
    onSuccess, onError);
        function getHeading() {
         //alert("getHeading");
         if(pgr == true) {
           if(hasCompass == true) {
             //清空当前的朝向内容,
             //输出提⽰示信息,以防读取数据耗时较⻓长
             hc.innerHTML = "正在从罗盘获取当前朝向...";
             //得到当前朝向
             navigator.compass.getCurrentHeading(onHeadingSuccess,
onHeadingError);
           } else {
             alert("没有找到罗盘。");
           }
         } else {
           alert("请稍侯,PhoneGap 尚未就绪。");
         }
      }
onHeadingSuccess
 • 查询设备朝向成功时调⽤用


      function onHeadingSuccess(heading) {
        var d = new Date(heading.timestamp);
        hc.innerHTML = "<b>Magnetic Heading:</b> " + heading.magneticHeading
+ "<br /><b>True Heading:</b> " + heading.trueHeading + "<br /><b>Heading
Accuracy:</b> " + heading.headingAccuracy + "<br /><b>Timestamp:</b> " +
d.toLocaleString();
      }
onHeadingError
• 查询设备朝向失败时调⽤用

  function onHeadingError(compassError) {
    //alert("onHeadingFailure");
    if(compassError.code == CompassError.COMPASS_NOT_SUPPORTED) {
      hc.innerHTML = "Compass not available."
      alert("Compass not supported.");
      hasCompass == false;
    } else
    if(compassError.code == CompassError.COMPASS_INTERNAL_ERR) {
      alert("Compass Internal Error");
    } else {
      alert("Unknown heading error!");
    }
  }
设置观察者
 • 设置罗盘朝向观测的API⽅方法:
   navigator.compass.watchHeading(onHeading
   Success, onHeadingError, watchOptions);


	 	 	 function onDeviceReady() {
	 	 	 	 alert("onDeviceReady");
	 	 	 	 //设置观察者
	 	 	 	 //每秒四次读取罗盘数据 (250 milliseconds, .25 seconds)
	 	 	 	 var watchOptions = {
	 	 	 	 	 frequency : 250
	 	 	 	 };
	 	 	 	 watchID = navigator.compass.watchHeading(onHeadingSuccess,
onHeadingError, watchOptions);
	 	 	 }
compassOptions对象
• ⾃自定义读取罗盘数据选项的参数
• 属性
 • frequency:毫秒计的获取罗盘数据间隔时⻓长(默认:
  100)(Number)
 • filter:引发⼀一次watchHeading成功回调的最⼩小度数变
  化。(Number)
onHeadingSuccess
    • 读取罗盘数据成功时回调


	   	   	   function onHeadingSuccess(heading) {
	   	   	   	 //alert("onHeadingSuccess");
	   	   	   	 var hv = Math.round(heading.magneticHeading);
	   	   	   	 hi.innerHTML = "<b>Heading:</b>" + hv + " degrees";
	   	   	   	 $("#compass").rotate(-hv);
	   	   	   }
compassHeading对象
• 读取罗盘数据成功时传⼊入的数据对象
 • magneticHeading:地磁轴的⽅方向,0-355.99度。
 • trueHeading:地球转轴(地理南北极连线)的真正⽅方
  向。【地磁轴和实际的南北极并不⼀一致,相交约11.5
  度】

 • headingAccuracy:报告的度数和实际度数之差。
 • timestamp:获得数据时的时间戳。
onHeadingError
    • 读取罗盘数据出错时回调
	   	   	   function onHeadingError(compassError) {
	   	   	   	   //alert("onHeadingFailure");
	   	   	   	   //出错时移除观察者。
	   	   	   	   navigator.compass.clearWatch(watchID);
	   	   	   	   //从⻚页⾯面上清空朝向数据。
	   	   	   	   hi.innerHTML = "";
	   	   	   	   //错误提醒。
	   	   	   	   if(compassError.code == CompassError.COMPASS_NOT_SUPPORTED) {
	   	   	   	   	   alert("不⽀支持罗盘功能。");
	   	   	   	   } else if(compassError.code == CompassError.COMPASS_INTERNAL_ERR)
{
	   	   	   	   	   alert("罗盘内部错误!");
	   	   	   	   } else {
	   	   	   	   	   alert("未知的朝向错误!");
	   	   	   	   }
	   	   	   }
watchOptions
 • 查询设备观测的API⽅方法:
   navigator.compass.watchHeading(onHeading
   Success, onHeadingError, watchOptions);


	 	 	 function onDeviceReady() {
	 	 	 	 alert("onDeviceReady");
	 	 	 	 //设置观察者
	 	 	 	 //每秒四次读取罗盘数据 (250 milliseconds, .25 seconds)
	 	 	 	 var watchOptions = {
	 	 	 	 	 frequency : 250
	 	 	 	 };
	 	 	 	 watchID = navigator.compass.watchHeading(onHeadingSuccess,
onHeadingError, watchOptions);
	 	 	 }
Connection
Connection API简介
• PhoneGap Connection 对象提供给应⽤用程序当前
 应⽤用可⽤用⺴⽹网络连接的相关信息。
演⽰示程序
connection.type
• Connection对象包含⼀一个单⼀一的属性:
 connection.type,具有下列常量值:
 • Connection.UNKNOWN
 • Connection.ETHERNET
 • Connection.WIFI
 • Connection.CELL_2G
 • Connection.CELL_3G
 • Connection.CELL_4G
 • Connection.NONE
Connection 代码⽰示例
function onDeviceReady() {
  navigator.notification.alert("PhoneGap 就绪!");
  //Add the online event listener
  document.addEventListener("online", isOnline, false);
  //Add the offline event listener
  document.addEventListener("offline", isOffline, false);
}

function isOnline() {
  //alert("isOnline");
  var d = new Date();
  $('#networkInfo').prepend("在线 (" + getConnectionTypeStr() + ")<br />");
}

function isOffline() {
  //alert("isOffline");
  var d = new Date();
  $('#networkInfo').prepend("离线<br />");
}

function getConnectionTypeStr() {
  //得到⺴⽹网络状态
  var networkState = navigator.network.connection.type;
  alert(networkState);
  //返回表⽰示⺴⽹网络状态的字符串
  //return states[networkState];
  return networkState;
}
为什么需要识别当前可⽤用的⺴⽹网络类型?


• 基于server型服务的需求
• 服务需要针对不同的带宽提供弹性⽅方案
• 传递⼤大数据前⼀一定要检查是否存在⾼高速⺴⽹网络(Wi-
 Fi or 4G)
Contacts
Contacts API简介
• PhoneGap Contacts API 为应⽤用提供了⼀一个到设备
 联系⼈人数据库的访问接⼝口,可以被⽤用来从设备的
 本地“联系⼈人”应⽤用创建,定位,编辑,拷⻉贝以及
 删除联系⼈人记录。
• PhoneGap的Contacts API是W3C Contacts API 规范
 的⼀一个实现。
Contacts 演⽰示 - 创建新联系⼈人
创建⼀一个联系⼈人
• 返回⼀一个新的Contact对象
function addContact() {
  alert("Adding " + contactInfo.FullName + " to contacts application");
  var contact = navigator.contacts.create();
  contact.displayName = contactInfo.FullName;
  contact.nickname = contactInfo.FullName;
  var tmpName = new ContactName();
  tmpName.givenName = contactInfo.FirstName;
  tmpName.familyName = contactInfo.LastName;
  tmpName.formatted = contactInfo.FullName;
  contact.name = tmpName;
  var phoneNums = [2];
  phoneNums[0] = new ContactField('work', contactInfo.OfficePhone, false);
  phoneNums[1] = new ContactField('mobile', contactInfo.MobilePhone, true);
  contact.phoneNumbers = phoneNums;
  var emailAddresses = [1];
  emailAddresses[0] = new ContactField('home', contactInfo.EmailAddress, true);
  contact.emails = emailAddresses;

    // 保存到设备
    contact.save(onContactSaveSuccess, onContactSaveError);
}
Contact对象
•   id: A globally unique identifier. (DOMString)

•   displayName: The name of this Contact, suitable for display to end-users.
    (DOMString)

•   name: An object containing all components of a persons name. (ContactName)

•   nickname: A casual name to address the contact by. (DOMString)

•   phoneNumbers: An array of all the contact's phone numbers. (ContactField[])

•   emails: An array of all the contact's email addresses. (ContactField[])

•   addresses: An array of all the contact's addresses. (ContactAddress[])

•   ims: An array of all the contact's IM addresses. (ContactField[])

•   organizations: An array of all the contact's organizations. (ContactOrganization[])

•   birthday: The birthday of the contact. (Date)

•   note: A note about the contact. (DOMString)

•   photos: An array of the contact's photos. (ContactField[])

•   categories: An array of all the contacts user defined categories. (ContactField[])

•   urls: An array of web pages associated to the contact. (ContactField[])
成功和失败的回调函数
function onContactSaveSuccess() {
  alert(contactInfo.FullName + " 已经成功保存到设备联系⼈人数据库。");
}

function onContactSaveError(e) {
  var msgText;
  switch(e.code) {
    case ContactError.UNKNOWN_ERROR:
      msgText = "An Unknown Error was reported while saving the contact.";
      break;
    case ContactError.INVALID_ARGUMENT_ERROR:
      msgText = "An invalid argument was used with the Contact API.";
      break;
    case ContactError.TIMEOUT_ERROR:
      msgText = "Timeout Error.";
      break;
    case ContactError.PENDING_OPERATION_ERROR:
      msgText = "Pending Operation Error.";
      break;
    case ContactError.IO_ERROR:
      msgText = "IO Error.";
      break;
    case ContactError.NOT_SUPPORTED_ERROR:
      msgText = "Not Supported Error.";
      break;
    case ContactError.PERMISSION_DENIED_ERROR:
      msgText = "Permission Denied Error.";
Contacts 演⽰示 - 联系⼈人搜索
搜索联系⼈人                               navigator.contacts.find(contactFields, contactSuccess,
                                         contactError, contactFindOptions);



      function searchContacts() {
        alert("searchContacts");
        $('#contacts').html('<p>Search Results</p>');
        var searchStr = document.getElementById("editSearch").value;
        var searchScope = document.getElementById("searchScope").selectedIndex;
        var contactFields = [];
        switch(searchScope) {
           case 1:
             contactFields = ['displayName', 'name', 'nickname'];
             break;
           case 2:
             contactFields = ['streetAddress', 'locality', 'region', 'postalCode', 'country'];
             break;
           case 3:
             contactFields = ['note'];
             break;
           default:
             contactFields = ['*'];
        }
        //Populate the search options object
        var searchOptions = {
           filter : searchStr,
           multiple : true,
        };
        //Execute the search
        navigator.contacts.find(contactFields, onContactSearchSuccess, onContactSearchError,
searchOptions);
onContactSearchSuccess
      function onContactSearchSuccess(contacts) {
        var i, len, theList;
        contactList = contacts;
        len = contacts.length;
        if(len > 0) {
          theList = '<ul data-role="listview">';
          for( i = 0, len; i < len; i += 1) {
            if(contacts[i].displayName == null) {
              theList += '<li><a onclick="showContact(' + i + ');">' +
contacts[i].name.familyName + ", " + contacts[i].name.givenName + '</a></li>';
            } else {
              theList += '<li><a onclick="showContact(' + i + ');">' +
contacts[i].displayName + '</a></li>';
            }
          }
          theList += '</ul>';
          $('#contacts').replaceWith(theList);
          $.mobile.changePage("#contactList", "slide", false, true);
        } else {
          navigator.notification.alert('Search returned 0 results', null, 'Contact
Search');
        }
      }
克隆联系⼈人
var contact2 = contact1.clone();
返回调⽤用Contact对象的拷⻉贝
删除联系⼈人
contact.remove(onContactRemoveSuccess
, onContactRemoveError);
从设备的联系⼈人数据库中删除联系⼈人
Device
Device API简介
PhoneGap Device 对象允许应⽤用访问关于应⽤用和运
⾏行⼀一个PhoneGap应⽤用的设备的有限数量的信息。
device.name: 根据平台的不同,有可能是设备⼚厂商
分配的名称或者是⼿手机⽤用户设置的名称.
device.cordova:构建应⽤用的PhoneGap的版本号;
device.platform: 移动设备平台的的名称;
device.uuid: universally unique identifier
device.version: 操作系统版本号
Device API Demo

             	 function onDeviceReady() {
             	 	 //得到要操作的DOM元素
             	 	 var element =
             document.getElementById("deviceInfo");
             	 	 //替换成使⽤用设备信息
                     element.innerHTML =
             "<b>device.name: " + device.name + br +
             	 	 "<b>device.cordova:</b> " +
             device.cordova + br +
             	 	 "<b>device.platform:</b> " +
             device.platform + br +
             	 	 "<b>device.uuid:</b> " + device.uuid
             + br +
             	 	 "<b>device.version:</b> " +
             device.version + br;
             	 }
Events
Events API简介
 PhoneGap Events API 可以让应⽤用程序为发⽣生在⽀支持
 的smartphone设备上的不同的事件注册事件监听
 器。
• deviceready 事件
• Application status 事件
• Network 事件
• Button 事件
Event API Demo
deviceready Event
	   	   	   function onBodyLoad() {
	   	   	   	 document.addEventListener("deviceready", onDeviceReady, false);
	   	   	   }

	   	   	   function onDeviceReady() {
	   	   	   	 navigator.notification.alert("PhoneGap就绪!");
	   	   	   }




    document.addEventListener(“eventName”,
    functionName, useCapture);
    eventName: 事件名字符串
    functionName:触发时调⽤用的⽅方法
    useCapture:⼀一般是false
Application Stauts 事件
    • foreground & background
    • pause event & resume event
    • 事件处理:数据库,⺴⽹网络,媒体播放...
	    	   	   function onDeviceReady() {
	    	   	   	   document.addEventListener("pause", processPause, false);
	    	   	   	   document.addEventListener("resume", processResume, false);
	    	   	   }
	    	   	   function processPause() {
	    	   	   	   pi.innerHTML = "Application paused.";
	    	   	   	   startTime = new Date();
	    	   	   }

	    	   	   function processResume() {
	    	   	   	   if(firstTime == true) {
	    	   	   	   	   firstTime = false;
	    	   	   	   	   pi.innerHTML = "Skipping first Resume.";
	    	   	   	   } else {
	    	   	   	   	   endTime = new Date();
	    	   	   	   	   timeDiff = (endTime - startTime) / 1000;
Network Status 事件
• online event
• offline event
 function onDeviceReady() {
   alert("onDeviceReady");
   document.addEventListener("online", isOnline, false);
   document.addEventListener("offline", isOffline, false);
 }

 function isOnline() {
   var d = new Date();
   $('#networkInfo').prepend("Online: " + d.toLocaleString() + "<br />");
 }

 function isOffline() {
   var d = new Date();
   $('#networkInfo').prepend("Offline: " + d.toLocaleString() + "<br />");
 }
Button 事件
物理按钮

back
menu
search
startcall
endcall
volumedown
volumeup
Button Event DemoCode
     if((pName == "Android") || (pName == "3.0.0.100")) {
       eventCount += 2;
       //Android & BlackBerry only events
       document.addEventListener("backbutton", onBackButton, false);
       document.addEventListener("menubutton", onMenuButton, false);
     }

     if(pName == "Android") {
       eventCount += 1;
       //Android only event
       document.addEventListener("searchbutton", onSearchButton, false);
     }

     if(pName == "3.0.0.100") {
       eventCount += 4;
       //BlackBerry only events
       document.addEventListener("startcallbutton", onStartCallButton, false);
       document.addEventListener("endcallbutton", onEndCallButton, false);
       document.addEventListener("volumedownbutton", onVolumeUpButton, false);
       document.addEventListener("volumeupbutton", onVolumeDownButton, false);
     }

     //did we register any event listeners?
     if(eventCount < 1) {
       //0, must be running on an iOS device
       alert("Must be running on an iOS device.nNo event listeners registered");
     } else {
       //Android or BlackBerry
       alert("Registered " + eventCount + " event listeners.");
     }
 }
Files
File API简介
PhoneGap File API 提供给应⽤用程序对移动设备上的
临时⽂文件或者持久化⽂文件系统进⾏行访问的⽅方法。包
括:
locate, read , write, copy, move以及remove。
PhoneGap File API 基于部分W3C File API 规范实
现:Directories and System specification。
只提供了开发者最常⽤用的功能,并没有完全实现
W3C规范。
File API Demo
可⽤用的存储类型
• temporary storage location
 • 从⺴⽹网上可以直接下载到的
 • 应⽤用⽣生成的临时⽂文件
 • ...
• persistent storage
 • ⽤用户⽣生成的内容
 • 应⽤用的配置信息
 • ...
Accessing the Device’s File System
function processDir(fileSystemType) {
  alert("processDir: " + fileSystemType);
  window.requestFileSystem(fileSystemType, 1024 * 1024,
onGetFileSystemSuccess, onFileError);
}




         <p>
          选择⽂文件系统:
          <input type="button" value="临时⽂文件"
onclick="processDir(LocalFileSystem.TEMPORARY);">
          <input type="button" value="持久存储"
onclick="processDir(LocalFileSystem.PERSISTENT);">
        </p>
Reading Directory Entries

var theFileSystem;

function processDir(fileSystemType) {
  alert("processDir: " + fileSystemType);
  window.requestFileSystem(fileSystemType, 1024 *
1024, onGetFileSystemSuccess, onFileError);
}

function onGetFileSystemSuccess(fs) {
  alert("onGetFileSystemSuccess: " + fs.name);
  //保存返回的⽂文件系统句柄
  theFileSystem = fs;
  //创建⼀一个Directory Reader
  var dr = fs.root.createReader();
  // 读取根⺫⽬目录内容
  dr.readEntries(onDirReaderSuccess, onFileError);
}

                      DirectoryReader
onDirReaderSuccess
function onDirReaderSuccess(dirEntries) {
                                              FileEntry or DirectoryEntry数组
  theEntries = dirEntries;
  var i, fl, len;
  len = theEntries.length;
  if(len > 0) {
    for( i = 0; i < len; i++) {
      if(theEntries[i].isDirectory == true) {
        fl += '<li><a href="#" onclick="processEntry(' + i + ');">⺫⽬目录: ' +
theEntries[i].name + '</a></li>';
      } else {
        fl += '<li><a href="#" onclick="processEntry(' + i + ');">⽂文件: ' +
theEntries[i].name + '</a></li>';
      }
    }
  } else {
    fl = "<p>No entries found</p>";
    $('#dirEntries').html(fl);
  }
}
Accessing FileEntry and DirectoryEntry Properties

 • isFile
 • isDirectory
 • name
 • fullPath
function processEntry(entryIndex) {
  theEntry = theEntries[entryIndex];
  //FileInfo variable
  var fi = "";
  fi += startP + '<b>Name</b>: ' + theEntry.name + endP;
  fi += startP + '<b>Full Path</b>: ' + theEntry.fullPath + endP;
  fi += startP + '<b>URI</b>: ' + theEntry.toURI() + endP;
  if(theEntry.isFile == true) {
    fi += startP + 'The entry is a file' + endP;
  } else {
    fi += startP + 'The entry is a directory' + endP;
  }
MetaData
function onGetMetadataSuccess(metadata) {
  // alert("onGetMetadataSuccess");
  var md = '';
  for(aKey in metadata) {
    md += '<b>' + aKey + '</b>: ' + metadata[aKey] + br;
  }
  md += hr;
  $('#fileMetadata').html(md);
}
Writing Files
function writeFile() {
  //随机⽣生成⼀一个⽂文件名
  var theFileName = createRandomString(8) + '.txt';
  theFileSystem.root.getFile(theFileName, {
    create : true
  }, onGetFileSuccess, onFileError);
}

function onGetFileSuccess(theFile) {
  theFile.createWriter(onCreateWriterSuccess, onFileError);
}

function onCreateWriterSuccess(writer) {
  writer.onwritestart = function(e) {
console.log("Write start");
  };
  writer.onwriteend = function(e) {
     console.log("Write end");
  };
  writer.onwrite = function(e) {
console.log("Write completed");
  };
  writer.onerror = function(e) {
     console.log("Write error: " + e.toString() + br);
  };
  writer.write("File created by PHoneGap File API: ");
  writer.write("This is another line of text ");
  writer.write(createRandomStory(25));
}
Reading Files
function viewFile() {
  theEntry.file(onFileReaderSuccess, onFileError);
}

function onFileReaderSuccess(file) {
  var reader = new FileReader();
  reader.onloadend = function(e) {
     $('#readInfo').append("加载完成" + br);
     $('#fileContents').text(e.target.result);
  };
  reader.onloadstart = function(e) {
     $('#readInfo').append("开始加载" + br);
  };
  reader.onloaderror = function(e) {
     $('#readInfo').append("加载错误: " + e.target.error.code + br);
  };
  reader.readAsText(file);
}
Deleting Files or Directories


function removeFile() {
  theEntry.remove(onRemoveFileSuccess, onFileError);
}

function onRemoveFileSuccess(entry) {
  alert("Successfully removed " + entry.name);
}
Copying Files or Directories
 theEntry.copyTo(parentEntry, newName,
 onSuccessFunction,
 onErrorFunction);
 parentEntry: 要拷⻉贝的⽂文件或⺫⽬目录
 newName: ⺫⽬目标
Moving Files or Directories
 theEntry.copyTo(parentEntry, newName,
 onSuccessFunction,
 onErrorFunction);
Uploading Files to a Server
 var ft = new FileTransfer();
 ft.upload(fileURI, serverURL,
 onUploadSuccess, onUploadError,
 fileUploadOptions);
扩展阅读
• HTML5⽂文件的拖拽
Geolocation
Geolocation API简介
PhoneGap Geolocation API 允许设备利⽤用移动设备
上的GPS能⼒力来判断设备在地球表⾯面上的位置。
应⽤用可以直接⼿手动获取当前位置,也可以设置⼀一个
观察者,当位置变化时可以周期性的通知应⽤用。
Geolocation API Demo
Getting a Device’s Current Location
Get Current Position
    使⽤用Position对象返回⼀一个设备的当前位置
    navigator.geolocation.getCurrentPosition(
       onGeolocationSuccess,
       [onGeolocationError],
       [geolocationOptions]);
    参数:
•   onGeolocationSuccess: 成功时使⽤用当前位置回调
•   onGeolocationError: 可选,出错时调⽤用
•   geolocationOptions: 可选,geolocation选项
    说明:
    geolocation.getCurrentPosition是⼀一个异步调⽤用的函数。将设备的当前位置
    作为⼀一个Position参数返回给geolocationSuccess函数。出错的时候,使⽤用
    ⼀一个PositionError对象回调geolocationError回调函数。
onGeolocationSuccess
      Position                                  Coordinates
                                                位置的地理坐标的⼀一系列属性的描述
      包含Position坐标和时间戳,由                        属性:
      geolocation API⽣生成。                       latitude: ⼗十进制的纬度(Number)
                                                longitude: ⼗十进制表⽰示的精度(Number)
      属性:
                                                altitude: 地⾯面海拔(Number)
      coords:地理位置坐标的集合                          accuracy: 经纬度坐标的精度,以⽶米为单位(Number)
      (Coordinates)                             altitudeAccuracy: 以⽶米为单位的海拔坐标;
                                                heading: 顺时针计数的正北⽅方向⾓角度
      timestamp:coords⽣生成的时间戳                   speed: 设备当前的地⾯面速度。
      (Date)                                    说明:
                                                Coordinates对象有Cordova创建,附加到Position对象。
                                                注意:对于Android,海拔精度⺫⽬目前还不⽀支持。

      function onLocationSuccess(loc) {
        alert("onLocationSuccess");
        var d = new Date(loc.timestamp);
        lc.innerHTML = '<b>当前位置</b><hr /><b>纬度</b>: ' + loc.coords.latitude + '<br /
><b>经度</b>: ' + loc.coords.longitude + '<br /><b>⾼高度</b>: ' + loc.coords.altitude +
'<br /><b>精度</b>: ' + loc.coords.accuracy + '<br /><b>海拔精确度</b>: ' +
loc.coords.altitudeAccuracy + '<br /><b>航向</b>: ' + loc.coords.heading + '<br /><b>速度
</b>: ' + loc.coords.speed + '<br /><b>时间戳</b>: ' + d.toLocaleString();
      }
onGolocationError
PositionError对象
出错时,⼀一个PositionError对象会返回给geolocationError回调函数
属性:
   code:预定义的错误码
   message:对错误码的详细描述
常量:
   PositionError.PERMISSION_DENIED, ⽤用户不允许使⽤用位置信息。
   PositionError.POSITION_UNAVAILABLE, ⽆无法取得位置信息,⽐比如设备没有GPS功能,
   或者没有⺴⽹网络连接。
   PositionError.TIMEOUT:指定的时间内⽆无法取得位置信息。


   function onLocationError(e) {
     alert("Geolocation error: #" + e.code + "n" + e.message);
   }
geolocationOptions
  ⾃自定义抓取位置的选项
  { maximumAge: 3000, timeout: 5000, enableHighAccuracy: true}
  选项:
  enableHighAccuracy: 要求设备返回最精确的结果。默认情况下,设备会尝试使⽤用基于⺴⽹网络的
  ⽅方法返回Position。设置这个参数为true来告诉框架使⽤用更精确地⽅方法,⽐比如卫星定位系统。
  timeout: 允许geolocation.getCurrentPosition和geolocation.watchPosition的最⻓长时间。如果在
  指定时间内,geolocationSuccess回调没有被调⽤用,则geolocationError会被调⽤用,带有⼀一个
  PositionError.TIMEOUT的错误码。和watchPosition⽅方法结合使⽤用的话,会每timeout时间调⽤用⼀一
  次geolocationError回调。
  maximumAge:不超过指定时间毫秒数的位置缓存。

          var locOptions = {
             timeout : 5000,
             enableHighAccuracy : true
          };
          //获得当前位置
          navigator.geolocation.getCurrentPosition(onLocationSuccess,
onLocationError, locOptions);
Watching a Device Location
Setting a Watch
  var watchId = navigator.geolocation.watchPosition(
     geolocationSuccess,
     [geolocationError],
     [geolocationOptions]);
  观察设备当前位置的变化
  参数:
• geolocationSuccess: 成功带着当前位置回调;
• geolocationError: 可选,出错时回调;
• geolocationOptions: 可选,geolocation选项
  返回:
  String:返回⼀一个watch id,是watch position interval观察位置间隔的引⽤用。应该和
  geolocation.clearWatch⼀一起使⽤用来停⽌止观察位置变化。
  说明:
  geolocation.watchPosition是⼀一个异步函数。当检测到位置变化时会返回设备的当前
  位置。当设备取得⼀一个新的位置,geolocationSuccess回调被调⽤用,带着⼀一个Position
  对象作为参数。如果出错了,geolocationError回调被调⽤用,带着PositionError对象。
Code of setting and canceling a Watch

        //Geolocation Options
        var locOptions = {
           maximumAge : 10000,
           timeout : 5000,
           enableHighAccuracy : true
        };
        //增加观察者
        watchID = navigator.geolocation.watchPosition(onLocationSuccess,
onLocationError, locOptions);




     function cancelWatch() {
       navigator.geolocation.clearWatch(watchID);
       watchID = null;
     }
Media
Media API简介
PhoneGap Media API提供了在设备上录⾳音和播放⾳音
频⽂文件的能⼒力。
提⽰示:当前Media API的实现并没有遵循W3C的媒体
捕捉的规范,只是提供了⼀一个实现供⼤大家⽅方便使
⽤用。未来的实现将会遵循W3C有关媒体捕捉的规
范,并且有可能会弃⽤用现在的API。也就是上⾯面列
出来的这个。
Media API Demo
The Media Object
创建⼀一个Media对象
var media = new Media(mediaFileURI, onMediaSuccess,
[mediaError], [mediaStatus];
注意:这⾥里的onMediaSuccess不会在new Media完成后执⾏行,⽽而是会在
每次播放或者录⾳音完成后调⽤用。
new Media完成后,可以对media判断时⻓长或者读设当前位置,但是这些
操作都不会得到任何值,除⾮非已经开始播放。



//     var fileName = "http://192.168.1.103/~tom/dan.mp3";
     var fileName = "/android_asset/www/eye.mp3";

  theMedia = new Media(fileName, onMediaSuccess, onMediaError,
onMediaStatus);
File URI
• ⽂文件既可以是本地⽂文件系统⽂文件,
• 也可以是located在⽂文件服务器的⽂文件;
• 或者是项⺫⽬目中的⽂文件。
  var fileName = "/android_asset/www/eye.mp3";




  var fileName = "http://192.168.1.103/~tom/dan.mp3";
MediaError
 出错时⼀一个MediaError对象被返回给mediaError回调函数。
 属性:
        code:下⾯面列出的⼀一个预定义的错误码;
        message:详细描述错误的错误消息。

 常量:
        MediaError.MEDIA_ERR_ABORTED
        MediaError.MEDIA_ERR_NETWORK
        MediaError.MEDIA_ERR_DECODE
        MediaError.MEDIA_ERR_NONE_SUPPORTED

 function onMediaError(e) {
  var msgText = "Media error: " + e.message + "(" + e.code + ")";
  console.log(msgText);
  navigator.notification.alert(msgText, null, "Media Error");
}
statusCode
• 0: Media.MEDIA_NONE
• 1: Media.MEDIA_STARTING
• 2: Media.MEDIA_RUNNING
• 3: Media.MEDIA_PAUSED
• 4: Media.MEDIA_STOPPED
function onMediaStatus(statusCode) {
  console.log("Status: " + statusCode);
  alert("Status: " + statusCode);
}
Duration
返回⾳音频⽂文件的⻓长度
media.getDuration()
说明
  如果能获得⾳音频⽂文件⻓长度的话,media.getDuration函
  数是⼀一个同步函数,返回以秒为单位的⾳音频⽂文件的⻓长
  度。
  如果获得不了的话(⽐比如当前没有正在播放),会返
  回-1.
Current Position
    返回声⾳音⽂文件内的当前位置
    media.getCurrentPosition(mediaSuccess, [mediaError]);
    参数
         mediaSuccess:带着以秒为单位的当前位置进⾏行回调。
         mediaError:可选,出错时调⽤用。                    需要设置⼀一个定时器来获取当前位置

    说明:media.getCurrentPosition函数是⼀一个返回Media对象底层声⾳音⽂文件的当前位置的异
    步函数。同时更新Media对象的_position参数。
function updateUI() {
  console.log("updateUI");
  theMedia.getCurrentPosition(onGetPosition, onMediaError);
}

function onGetPosition(filePos) {
  console.log("onGetPosition");
  //We won't have any information about the file until it's
  // actually played. Update the counter on the page
  $('#pos').html('时间: ' + Math.floor(filePos) + ' , 共: ' +
theMedia.getDuration() + ' seconds');
}
释放media对象
media.release(), 释放底层声⾳音⽂文件资源。
• 说明:释放下层操作系统声⾳音⽂文件的同步函数。这
个函数对Android系统尤为重要,因为针对媒体播
放的OpenCore实例有数量限制。

   var my_media = new Media(src, onSuccess, onError);

   my_media.play();
   my_media.stop();
   my_media.release();
Playing Audio Files
Play
theMedia.play();
没有回调函数!
因此要获得当前播放位置并在界⾯面上更新的话,要
⾃自⼰己设置定时器。
function doPlay() {
  if(theMedia) {
    console.log("doPlay");
    //开始播放
    theMedia.play();
    //设置计时器更新UI
    theTimer = setInterval(updateUI, 1000);
  } else {
    alert("No media file to play");
  }
}
Pause
 theMedia.pause();
 暂停语⾳音播放的同步函数。
 Notes: 如果在当前没有播放的Media对象上调⽤用
 pause,不会报错。

function doPause() {
  if(theMedia) {
    console.log("doPause");
    //Pause media play
    theMedia.pause();
    window.clearInterval(theTimer);
  }
}
Stop
  theMedia.stop();
  停⽌止播放声⾳音的同步⽂文件
  Note: 和pause⼀一样,在没有正在播放的Media对象上调⽤用
  stop,也不会报错。



function doStop() {
  if(theMedia) {
    console.log("doStop");
    //停掉计时器
    theTimer = null;
    //停⽌止播放
    theMedia.stop();
  }
}
Seek
theMedia.seekTo(milliseconds);
设置⼀一个语⾳音⽂文件的当前位置。
• 说明:异步更新当前位置的函数。同时也更新
_position参数。


  var my_media = new Media(src, onSuccess, onError);
  my_media.play();

  setTimeout(function() {
  my_media.seekTo(1000);
  }, 5000);
Recording Audio Files
Start Recording
theMedia.startRecord();
开始录制语⾳音⽂文件的同步函数。
Note: 和play同样的问题,没有回调函数。⾃自⼰己设置定时器,获
取时⻓长,更新UI。出错时创建Media对象时的onError会被调⽤用。
   function recordAudio() {
      var src = “myrecording.mp3”;
      var mediaRec = new Media(src,
        function() {
          console.log(“recordAudio(): Audio success!”);
   },
   function() {
      console.log(“recordAudio(): Audio.Error: ” + err.code);
   });

   // Record audio
   mediaRec.startRecord();
   }
Stop Recording
theMedia.stopRecord();
停⽌止录制声⾳音⽂文件的同步函数。
Notes: 同样没有回调函数,出错时onError会被调⽤用。



 PhoneGap Capture API 提供的能⼒力更适合于录
              制⾳音频!!!
Notification
Notification API简介
PhoneGap Notification API 允许应⽤用向⽤用户提供可
视化,触觉化或者可听⻅见的反馈。
 • notification.alert
 • notification.confirm
 • notification.beep
 • notification.vibrate
Notification API Demo
Visual Alerts(Alert and Confirm)
notification.alert




                                      显
                                       ⽰示
                                         ⼀一
                                           个
                                              按
                                               钮
 显⽰示⼀一个⾃自定义的alert或者对话框。 对于这个功能⼤大
 多数的Cordova的实现使⽤用⼀一个本地的对话框。然⽽而,有些
 平台简单的使⽤用浏览器的alert功能,这些alert的可定制性就
 稍微差⼀一些。
 navigator.notification.alert(message_t
 ext, callback_function, [“title”],
 [“button_text”])
  • message: 对话框消息(String)
  • alertCallback:当对话框消息释放的时候调⽤用的回调⽅方
   法(Function)
  • title: 对话框标题(String)(可选,默认是:”Alert”)
  • buttonName: 按钮名称(String)(可选,默认:”OK”)
alert sample
      <div data-role="fieldcontain">
        <label for="msgText">消息⽂文本:</label>
        <input type="text" name="msgText" id="msgText" value="这是
⼀一条⽂文本消息!" />
        <div data-role="controlgroup" data-type="horizontal">
          <input type="button" value="Alert" onclick="doAlert();">
          <input type="button" value="Confirm"
onclick="doConfirm();">
        </div>
      </div>




        function doAlert() {
         msgText = document.getElementById('msgText').value;
         navigator.notification.alert(msgText, onDoAlert,
"Alert⽰示例", "Click Me!");
      }

      function onDoAlert() {
        alert("Click Me Button!");
      }
显
notification.confirm




                                                     ⽰示
                                                        ⼀一
                                                          个
                                                           或
                                                              多
                                                               个
 显⽰示⼀一个⾃自定义的确认对话框




                                                                按
                                                                  钮
 navigator.notification.confirm(message_text,
 callback_confirm, [“title”], [“button_text_array”])
  •   message: 对话框消息(String)
  •   confirmCallback: 回调⽅方法,带着被按下按钮的索引(1,2,或3)(Function)
  •   title: 对话框标题(String)(可选,默认是:“Confirm”)
  •   buttonLabels:逗号分割的按钮标签字符串(String)(可选,默认是:“OK,
      Cancel”)

• 说明
  •   notification.confirm函数显⽰示⼀一个⽐比浏览器的确认框更具定制化的本地对话框。
  •   confirmCallback
      •   当⽤用户按下了确认框的按钮之⼀一时confirmCallback会被调⽤用。

      •   这个回调函数带有⼀一个buttonIndex(数值)参数,是被按下按钮的索引。需要指出的是这
          ⾥里使⽤用的索引是以1开始的,所以这⾥里的值是1,2,3这样。
confirmation代码


      function doConfirm() {
        msgText =
document.getElementById('msgText').value;
        navigator.notification.confirm(msgText,
onDoConfirm, "Confirmation⽰示例", "Yes, No, Maybe");
      }

     function onDoConfirm(btnNum) {
       if(btnNum == "1") {
         alert("Thanks for saying yes!");
       } else {
         alert("Too bad, you said no.");
       }
     }
notification.beep
设备将会发出⼀一声蜂鸣声。
navigator.notification.beep(times)
times: 重复beep的次数(Number)

   function doBeep() {
     beepCount = document.getElementById('beepSlider').value;
     navigator.notification.beep(beepCount);
   }
平台差异
• iOS: 第⼀一iOS会忽略beep次数参数,也就是说只
beep⼀一次;第⼆二,因为iOS没有native的beep
API,所以:
• Cordova使⽤用media API通过播放⼀一个声⾳音⽂文件的⽅方式
 实现了beep功能;
• ⽤用户必须提供⼀一个beep的声⾳音⽂文件;
• 声⾳音⽂文件必须少于30秒,要放在www/根⺫⽬目录下,并
 且必须命名为beep.wav。

• Windows Phone 7:WP7的Cordova库包含了⼀一个通⽤用
 的beep⽂文件。在lib/windows-phone/templates/
 standalone/cordovalib⺫⽬目录下。
notification.vibrate
 使设备震动指定时⻓长
 navigator.notification.vibrate(millis
 econds)
 time: 使设备震动的毫秒数,数值类型。
 例⼦子:navigator.notification.vibrate(2500)
• 平台差异
  • iPhone:会忽略震动时⻓长参数,使⽤用⾃自⾝身预设的震动
   时⻓长。       function doVibe() {
                vibeCount = document.getElementById('vibeSlider').value;
                navigator.notification.vibrate(vibeCount);
              }
Storage
Storage API简介
• ⼤大多数HTML5兼容的浏览器都提供给Web
 Application从本地存储设施读写key/value键值对
 的能⼒力,以及从本地SQL 数据库读写数据的能
 ⼒力。这两种能⼒力都不是HTML直接提供的,⽽而是通
 过在浏览器内运⾏行⽀支持的JavaScript代码实现的。
• PhoneGap Storage API 是基于 W3C Web SQL
 Database 规范以及 W3C Web Storage API 规范。有
 些设备已经提供了这个规范的⼀一个实现。对于这
 些设备,使⽤用其内置的⽀支持⽽而不是使⽤用Cordova的
 实现来替代。对于不⽀支持存储的设备,Cordova的
 实现是兼容W3C规范的。
localStorage Demo
localStorage - UI

     <section id="config" data-role="page" >
       <header data-role="header">
         <h1>MT 配置</h1>
       </header>
       <div data-role="content">
         <div data-role="fieldcontain">
           <legend>
             每⽇日清除旧的记录吗?
           </legend>
           <label for="purgeStatus">启⽤用清除</
label>
           <input type="checkbox"
name="purgeStatus" id="purgeStatus" />
           <label for="purgeInterval">清除间隔</
label>
           <input type="number"
id="purgeInterval" name="purgeInterval" />
           天
         </div>
         <input type="button" value="保存配置"
onclick="saveConfig();">
localStorage - setItem



function saveConfig() {
  //将配置设置写⼊入localStorage
  window.localStorage.setItem("purgeStatus",
document.getElementById("purgeStatus").checked);
  window.localStorage.setItem("purgeInterval",
document.getElementById("purgeInterval").value);
  //切换回主界⾯面
  $.mobile.changePage("#main", "flip", false, false);
}
localStorage - getItem



  purgeStatus =
window.localStorage.getItem("purgeStatus");
  purgeInterval =
window.localStorage.getItem("purgeInterval");
  if(purgeStatus == "true") {
    $("#purgeStatus").attr("checked", true);
    $("#purgeInterval").attr('value',
purgeInterval);
    doPurge(purgeInterval);
  }
localStorage
localStorage提供了到W3C Storage接⼝口的接⼝口;允
许以key-value形式保存数据。



 // 写⼊入配置
 window.localStorage.setItem("key", "value");
 // 读取配置
 var value = window.localStorage.getItem("key");
 // 返回指定位置key的名称
 var keyname = window.localStorage.key(0);
 // 删除key指定的位置的项
 window.localStorage.removeItem("key");
 // 删除所有键值对
 window.localStorage.clear();
浏览器调试⼯工具
SQL Database
Storage Demo
openDatabase
  var dbShell = window.openDatabase(database_name, database_version, database_displayname, database_size);



   这个⽅方法将创建⼀一个新的 SQLite 数据库,并且返回⼀一个Database对
   象。使⽤用这个Database对象来操作数据。

 • 参数
      •   database_name:数据库名(写⼊入设备内存的数据库⽂文件名)

      •   database_version:数据库版本(应⽤用可以据此进⾏行升级操作)

      •   database_displayname:数据库显⽰示名

      •   database_size:分配给数据库的空间⼤大⼩小(字节)

  //创建或者打开数据库
  console.log("Opening database");
  theDB = window.openDatabase("mtDB", "1.0", "Mileage Tracker", 3 * 1024 *
1024);
  console.log("Checking theDB");
  if(theDB) {
Database对象
 包含允许⽤用户操作数据库的⽅方法

• ⽅方法
      •   transaction: 运⾏行⼀一个数据库事务;

      •   changeVersion: 允许脚本在更新schema的同时⾃自动地确认版本号并且更
          改。

• 说明
      •   Database对象从window.openDatabase()的调⽤用返回。

      function saveRecord() {
       console.log("Entering saveRecord");
       //这⾥里可以做⼀一些数据验证⼯工作,⽐比如⽇日期要有效,numMiles > 0
       //保存记录
       theDB.transaction(insertRecord, onTxError, onTxSuccess);
       console.log("Leaving saveRecord");
  }
SQLTransaction
• 包含允许⽤用户对数据库执⾏行SQL语句的⽅方法
• ⽅方法
 • executeSql:执⾏行⼀一条SQL语句
• 说明:当你调⽤用Database对象事务⽅方法时,它的
 回调⽅方法会被调⽤用,带着⼀一个SQLTransaction对
 象。⽤用户可以通过调⽤用executeSql⽅方法多次来构建
 ⼀一个数据库事务。
executeSql
function insertRecord(tx) {
  console.log("Entering insertRecord");
  //创建⼀一个新的Date对象来持有⽤用户输⼊入的⽇日期
  var tmpDate = new Date.fromString(document.getElementById("editDate").value);
  console.log("Date: " + tmpDate.valueOf());
  var tmpMiles = document.getElementById("editNumMiles").value;
  console.log("Miles: " + tmpMiles);
  var tmpNotes = document.getElementById("editNotes").value;
  console.log("Notes: " + tmpNotes);
  var sqlStr = 'INSERT INTO MILEAGE (tripDate, miles, notes) VALUES (?, ?, ?)';
  console.log(sqlStr);
  tx.executeSql(sqlStr, [tmpDate.valueOf(), tmpMiles, tmpNotes], onSqlSuccess,
onSqlError);

    // 使⽤用jQuery重置表单的输⼊入值
    var blankVal = {
       value : ''
    };
    $("#editNumMiles").attr(blankVal);
    $("#editNotes").attr(blankVal);
    console.log("Leaving insertRecord");
}
SQLResultSet
 当⼀一个SQLTransaction的executeSql⽅方法被调⽤用时,会带着
 SQLResultSet对象调⽤用它的回调函数。

• 属性
  •   insertId:SQLResultSet对象的SQL语句插⼊入到数据库中的⾏行的⾏行编号。

  •   rowsAffected: 被SQL语句影响的数据库记录的⾏行数。如果该语句没有影响到
      任何⾏行,rowsAffected会被设置为0。

  •   rows: 表⽰示返回的⾏行的SQLResultSetRowList。如果没有⾏行被返回,这个对
      象为空。

• 说明:如果Insert语句成功执⾏行的话,insertId是插⼊入⾏行的编号。如果
 这条SQL语句不是insert语句,insertId属性不会被设置。对于insert或
 update语句⽽而⾔言,会返回受影响的记录数。最后⼀一个属性的类型是
 SQLResultSetList,包含的是SQL的select语句返回的数据。
SQLResultSet - insert
function onSqlSuccess(tx, res) {
  console.log("SQL: success");
  if(res) {
    console.log(res);
    alert("insertId = " + res.insertId);
    alert("rowsAffected = " + res.rowsAffected);
  }
}

function onSqlError(tx, err) {
  console.log("Entering onSqlError");
  var msgText;
  if(err) {
    msgText = "SQL: " + err.message + " (" + err.code + ")";
  } else {
    msgText = "SQL: Unknown error";
  }
  console.error(msgText);
  alert(msgText);
  console.log("Leaving onSqlError");
}
SQLResutSetList
 SQLResultSetList包含由SQL查询语句返回的数据。
 这个对象包含⼀一个⻓长度属性能让你知道select语句
 返回了多少⾏行。为了得到⼀一个⾏行数据,你应该通过
 指定⼀一个索引来调⽤用item⽅方法。item⽅方法返回⼀一个
 JavaScript对象,这个对象的属性就是⾏行记录的列数
 据。
• 属性
  • length: 由SQL查询返回的⾏行数
• ⽅方法
  • item:返回由JavaScript对象表⽰示的指定索引的⾏行。
SQLResultSetList - query
function onQuerySuccess(tx, results) {
  console.log("Entering onQuerySuccess");
  if(results.rows) {
    console.log("Rows: " + results.rows);
    var htmlStr = "";
    var len = results.rows.length;
    if(len > 0) {
      for(var i = 0; i < len; i++) {
        var theDate = new Date(results.rows.item(i).tripDate);
        htmlStr += '<b>⽇日期:</b> ' + theDate.toDateString() + '<br />';
        var numMiles = results.rows.item(i).miles;
        if(numMiles > 1) {
          htmlStr += '<b>英⾥里:</b> ' + numMiles + ' miles<br />';
        } else {
          htmlStr += '<b>英⾥里:</b> 1 mile<br />';
        }
        //检查是否有备注
        var theNotes = results.rows.item(i).notes;
        if(theNotes.length > 0) {
          htmlStr += '<b>备注:</b> ' + theNotes + '<br />';
        }
        htmlStr += '<hr />';
      }
SQLError
 当操作数据库有错误发⽣生时抛出SQLError错误。
• 属性
  •   code:下⾯面列出来的预定义错误之⼀一

  •   message: 错误描述

• 常量
  •   SQLError.UNKNOWN_ERR,未知错误

  •   SQLError.DATABASE_ERR,数据库错误

  •   SQLError.VERSION_ERR,版本错误

  •   SQLError.TOO_LARGE_ERR,超⼤大

  •   SQLError.QUOTA_ERR,超限

  •   SQLError.SYNTAX_ERR,语法错误

  •   SQLError.CONSTRAIN_ERR,限制错误

  •   SQLError.TIMEOUT_ERR,超时错误
标准现状



W3C Web SQL Database

                                Still valid!



                       Web Storage
扩展阅读
• PersistenceJS - persistencejs.org
• lawnchair - http://brian.io/lawnchair/
• DOM Storage - https://developer.mozilla.org/en-US/
 docs/DOM/Storage
Thank you!

Contenu connexe

Plus de Tom Fan

Semantics
SemanticsSemantics
SemanticsTom Fan
 
Multimedia
MultimediaMultimedia
MultimediaTom Fan
 
Intro to-html5
Intro to-html5Intro to-html5
Intro to-html5Tom Fan
 
Html5 history
Html5 historyHtml5 history
Html5 historyTom Fan
 
Geolocation
GeolocationGeolocation
GeolocationTom Fan
 
File api
File apiFile api
File apiTom Fan
 
Webstorage
WebstorageWebstorage
WebstorageTom Fan
 
Html5 最重要的部分
Html5 最重要的部分Html5 最重要的部分
Html5 最重要的部分Tom Fan
 
AT&T 的 HTML5 策略和应用现状
AT&T 的 HTML5 策略和应用现状AT&T 的 HTML5 策略和应用现状
AT&T 的 HTML5 策略和应用现状Tom Fan
 
HTML5 生态系统和应用架构模型
HTML5 生态系统和应用架构模型HTML5 生态系统和应用架构模型
HTML5 生态系统和应用架构模型Tom Fan
 
18 NSUserDefaults
18 NSUserDefaults18 NSUserDefaults
18 NSUserDefaultsTom Fan
 
17 Localization
17 Localization17 Localization
17 LocalizationTom Fan
 
16 CoreData
16 CoreData16 CoreData
16 CoreDataTom Fan
 
15 Subclassing UITableViewCell
15 Subclassing UITableViewCell15 Subclassing UITableViewCell
15 Subclassing UITableViewCellTom Fan
 
14 Saving Loading and Application States
14 Saving Loading and Application States14 Saving Loading and Application States
14 Saving Loading and Application StatesTom Fan
 
13 UIPopoverController and Modal View Controller
13 UIPopoverController and Modal View Controller13 UIPopoverController and Modal View Controller
13 UIPopoverController and Modal View ControllerTom Fan
 
12 Camera
12 Camera12 Camera
12 CameraTom Fan
 
11 UINavigationController
11 UINavigationController11 UINavigationController
11 UINavigationControllerTom Fan
 
10 Editing UITableView
10 Editing UITableView10 Editing UITableView
10 Editing UITableViewTom Fan
 

Plus de Tom Fan (20)

Semantics
SemanticsSemantics
Semantics
 
Multimedia
MultimediaMultimedia
Multimedia
 
Intro to-html5
Intro to-html5Intro to-html5
Intro to-html5
 
Html5 history
Html5 historyHtml5 history
Html5 history
 
Geolocation
GeolocationGeolocation
Geolocation
 
File api
File apiFile api
File api
 
Css3
Css3Css3
Css3
 
Webstorage
WebstorageWebstorage
Webstorage
 
Html5 最重要的部分
Html5 最重要的部分Html5 最重要的部分
Html5 最重要的部分
 
AT&T 的 HTML5 策略和应用现状
AT&T 的 HTML5 策略和应用现状AT&T 的 HTML5 策略和应用现状
AT&T 的 HTML5 策略和应用现状
 
HTML5 生态系统和应用架构模型
HTML5 生态系统和应用架构模型HTML5 生态系统和应用架构模型
HTML5 生态系统和应用架构模型
 
18 NSUserDefaults
18 NSUserDefaults18 NSUserDefaults
18 NSUserDefaults
 
17 Localization
17 Localization17 Localization
17 Localization
 
16 CoreData
16 CoreData16 CoreData
16 CoreData
 
15 Subclassing UITableViewCell
15 Subclassing UITableViewCell15 Subclassing UITableViewCell
15 Subclassing UITableViewCell
 
14 Saving Loading and Application States
14 Saving Loading and Application States14 Saving Loading and Application States
14 Saving Loading and Application States
 
13 UIPopoverController and Modal View Controller
13 UIPopoverController and Modal View Controller13 UIPopoverController and Modal View Controller
13 UIPopoverController and Modal View Controller
 
12 Camera
12 Camera12 Camera
12 Camera
 
11 UINavigationController
11 UINavigationController11 UINavigationController
11 UINavigationController
 
10 Editing UITableView
10 Editing UITableView10 Editing UITableView
10 Editing UITableView
 

PhoneGap 2.0 开发

  • 1. PhoneGap API Getting Started 范圣刚,princetoad@gmail.com, www.tfan.org
  • 3. What we will learn? • 三维⽅方位解析 • 设备⽅方位查询 • 加速度检测
  • 5. 轴向⽰示例 • 平放桌⾯面:X:0, Y:0, Z:10 • 沿左边竖⽴立:X:10, Y:0, Z:0 • 沿底边竖⽴立:X:0, Y:10, Z:0 • 沿顶边倒⽴立:X:0, Y:-10, Z:0
  • 8. accelerometer.getCurrentAcceleration • 说明:使⽤用该⽅方法查询设备的当前⽅方位 • 参数: • onAccelSuccess:当加速度计数据有效时调⽤用; • onAccelFailure:提取加速度计数据出错时调⽤用;
  • 9. Acceleration对象 • 回调onSuccess时会传递⼀一个acceleration对象作为 参数 • 四个属性值: • x:在x轴⽅方向上的加速度量(m/s^2) • y: 在y轴⽅方向上的加速度量(m/s^2) • z: 在z轴⽅方向上的加速度量(m/s^2) • timestamp:以毫秒计的时间戳
  • 13. accelerometer.watchAcceleration • 说明: • 定期获得移动设备的加速度。 • 每次获得⼀一个Acceleration对象时,onAccelSuccess回调函数就会被 调⽤用。 • 通过设置acceleratorOptions的frequency参数指定间隔时间,以毫 秒计。
  • 15. Accelerometer注意问题 • 加速度计的返回值问题:操作系统不同,返回值 的范围也有差异 • 加速度计硬件检测问题 • accelOptions的默认值:如果accelOptions参数被 忽略,那么默认每10秒中测量⼀一次加速度计数 据。(accelerometerOptions只有⼀一个选项: frequency) • iPhone Quirks
  • 17. Camera API简介 PhoneGap Camera API提供给应⽤用处理照⽚片的能 ⼒力,可以直接从摄像头采集或者从设备的相册获取 照⽚片。 当提取照⽚片时,API可以返回指向设备⽂文件系统上 的image⽂文件URI,或者以base64编码字符串的⽅方式 返回image⽂文件内容。 Camera API只提供了⼀一个⽅方法: navigator.camera.getPicture。但是getPicture的 cameraOptions参数提供了⾮非常丰富的配置选项!
  • 18. 访问照⽚片(拍照,相⽚片库) navigator.camera.getPicture( onCameraSuccess, onCameraError, [ cameraOptions ] ); • 说明: • 同样需要传⼊入两个函数:onCameraSuccess, onCameraError。成功得到照⽚片的时候调⽤用 onCameraSuccess函数;⽤用户取消或者获取照⽚片失败的 时候会调⽤用onCameraError函数。 • cameraOptions是⼀一个可选的配置选项。(后⾯面会详细 介绍)
  • 19. Camera API Demo1 - 拍照
  • 20. getPicture代码⽰示例 <!DOCTYPE html> <html> <head> <title>Example Camera</title> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <meta name="viewport" id="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" /> <script type="text/javascript" charset="utf-8" src="cordova-2.0.0.js"></script> <script type="text/javascript" charset="utf-8"> function onBodyLoad() { alert("onBodyLoad"); document.addEventListener("deviceready", onDeviceReady, false); } function onDeviceReady() { navigator.notification.alert("onDeviceReady"); } function takePhoto() { //alert("takePhoto"); navigator.camera.getPicture(onCameraSuccess, onCameraError, { quality: 50, destinationType: Camera.DestinationType.FILE_URI }); // navigator.camera.getPicture(onCameraSuccess, onCameraError); } function onCameraSuccess(imageURL) { navigator.notification.alert("onCameraSuccess: " + imageURL); } function onCameraError() { navigator.notification.alert("onCameraError"); } </script> </head> <body onload="onBodyLoad()"> <h1>Example Camera-1</h1> <p> 使⽤用 PhoneGap Camera API <br /> <input type="button" value="拍张照⽚片" onclick="takePhoto();"> </p> </body> </html>
  • 22. Camera API Demo 2 - 拍照并在⻚页⾯面显⽰示 和前⼀一个例⼦子的主要代码差异 function onCameraSuccess(imageURL) { navigator.notification.alert("onCameraSuccess: " + imageURL); //得到⽤用于显⽰示图⽚片的div的id ic = document.getElementById('imageContainer'); //使⽤用从camera程序得到的URL写⼀一个img标签,并且输出到刚才得到的div。 ic.innerHTML = '<img src="' + imageURL + '" width="50%" />'; }
  • 24. cameraOptions - quality { quality : 75, destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; quality:保存相⽚片的质量。范围[0, 100](Number)
  • 25. quality参数的使⽤用和注意事项 • 采⽤用多⾼高质量 • 保存为⽂文件时,采⽤用多⾼高的照⽚片质量?⽂文件⼤大⼩小,设 备内存,⺴⽹网络传输...... ⼀一般50%-100%。 • 使⽤用base64字符串返回时,采⽤用多⾼高的照⽚片质量?字 符串⻓长度,JS的处理能⼒力。⼀一般50%及以下。 • BlackBerry会忽略quality参数
  • 26. cameraOptions - destinationType { quality : 75, destinationType : Camera.DestinationType.FILE_URI, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; destinationType: 返回的格式。在 navigator.camera.DestinationType中定义(Number)     Camera.DestinationType = {         DATA_URL : 0,                // 以base64编码字符串格式返回照⽚片内容         FILE_URI : 1                 // 返回image⽂文件的URI     };
  • 27. destinationType的使⽤用场景 • FILE_URI 巨⻓长的滚动条 • 在⻚页⾯面上显⽰示; • 保存到相册; • 拷⻉贝到其他位置。 • DATA_URL • 保存到数据库; • 上传到服务器。
  • 28. cameraOptions - sourceType { quality : 75, 从相册选取的图⽚片 destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; sourceType: 设置照⽚片源。在 navigator.camera.PictureSourceType中定义(Number) Camera.PictureSourceType = {     PHOTOLIBRARY : 0,     CAMERA : 1,     SAVEDPHOTOALBUM : 2 };
  • 29. sourceType注意事项 • 如果不设置sourceType参数,默认会使⽤用camera 抓取照⽚片; • 在⼤大多数平台上,设置sourceType为 PHOTOLIBRARY或SAVEDPHOTOALBUM效果是⼀一样 的; • BlackBerry会忽略这个参数。
  • 30. cameraOptions - allowEdit { quality : 75, destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; allowEdit: 选取前是否允许简单的编辑。(Boolean)
  • 31. allowEdit注意事项 • 适⽤用平台 • iOS可以在确定选取前对相⽚片进⾏行移动和缩放; • Android等都不⽀支持。
  • 32. cameraOptions - encodingType { quality : 75, destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; encodingType: 选择返回image⽂文件的编码。在 navigator.camera.EncodingType中定义(Number) Camera.EncodingType = { JPEG : 0, // 以JPEG格式编码image PNG : 1 // 以PNG格式编码image };
  • 34. cameraOptions - targetWidth & targetHeight { quality : 75, destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 1024, targetHeight: 768, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; targetWidth: 设定照⽚片宽度,以像素为单位。(Number) targetHeight: 设定照⽚片⾼高度,以像素为单位。(Number)
  • 35. 宽⾼高⽐比的注意事项 • 可以单独指定宽度或者⾼高度,照⽚片会相应的缩放。如果两个都同 时指定,照⽚片会按照最⼩小的宽⾼高⽐比设置。 • 例如: 原⽐比例是1000:500(1/2), 设置500:300, ⾼高度⽐比1/2, 宽度⽐比3/5, 结 果是按照较⼩小的1/2缩放。也就是500:250。 • 不管怎么设定,⾼高宽⽐比会被保持。 • 在拍照前,没有办法以编程的⽅方式判断camera的分辨率,以及⽀支 持的宽⾼高⽐比。因此除了推测及在每款⽀支持的设备上进⾏行测试以 外,没有⽅方法能够在应⽤用内⾮非常精确的设定这些值。
  • 36. cameraOptions - mediaType { quality : 75, destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.PHOTOLIBRARY, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100, mediaType: Camera.MediaType.PICTURE, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; mediaType: 设置从哪类媒体中选择。仅在 PictureSourceType为PHOTOLIBRARY或SAVEDPHOTOALBUM 时有效。在navigator.camera.MediaType中定义。 Camera.MediaType = {     PICTURE: 0,             // 只能选择静态图⽚片。返回格式由destinationType字段确定。     VIDEO: 1,               // 只能选择视频。以FILE_URI格式返回。     ALLMEDIA : 2            // 可以从所有的媒体类型中选择
  • 37. cameraOptions - correctOrientation { quality : 75, destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100, correctOrientation: true, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; correctOrientation: 采集时针对设备⽅方向翻转图⽚片。(Boolean)
  • 38. cameraOptions - saveToPhotoAlbum { quality : 75, destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100, correctOrientation: true, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; saveToPhotoAlbum: 抓取 后是否保存到设备相册。 (Boolean)
  • 39. cameraOptions - popoverOptions { quality : 75, destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100, correctOrientation: true, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false }; popoverOptions: 指定在iPad上popover的位置。(Boolean) 仅适⽤用于iOS平台。
  • 40. 平台相关的注意事项 • Android • 忽略allowEdit参数 • Camera.PictureSourceType.PHOTOLIBRARY和 Camera.PictureSourceType.SAVEDPHOTOALBUM显⽰示同样的 相册。 • iOS • 在某些设备上设置quality⼩小于50以避免内存错误。 • 当设置使⽤用destinationType.FILE_URI时,照⽚片被保存到应⽤用 的临时⺫⽬目录。开发者可以使⽤用navigator.fileMgr API删除这些 ⽂文件以进⾏行空间管理。(参⻅见iOS⽂文件指南) • 或者使⽤用camera.cleanup
  • 41. 平台相关的注意事项(续) • BlackBerry • 忽略quality参数 • 忽略sourceType参数 • 忽略allowEdit参数 • 忽略correctOrientation参数 • 应⽤用必须具有injection权限以在拍照后关闭本地Camera应⽤用 • 不⽀支持Camera.MediaType • Windows Phone 7 • 忽略allowEdit参数 • 忽略correctOrientation参数
  • 42. camera.cleanup • 仅适⽤用于iOS • 清理camera⽣生成的临时⽂文件 navigator.camera.cleanup(onSuccess, onFail); function onSuccess() { console.log("Camera cleanup success.") } function onFail(message) { alert('Failed because: ' + message); }
  • 45. What we will learn? • 图⽚片,视频,⾳音频采集的基本⽅方法 • 采集选项的指定:次数,时⻓长... • 采集⽂文件数组的遍历和⽂文件属性 • 获取采集⽂文件的格式相关信息
  • 46. Capture API简介 • PhoneGap Capture API允许应⽤用程序使⽤用移动设备 上合适的内置应⽤用进⾏行audio,video和image的采 集。 • 设备默认的camera应⽤用被⽤用来采集image和 video,同样设备默认的voice recorder应⽤用被⽤用来 采集⾳音频剪辑。 • PhoneGap Capture API的实现基于W3C Media Capture API规范。但是PhoneGap对于规范并没有 提供完全的⽀支持,有⼀一些选项还没有实现。
  • 47. Camera vs. Capture Q: Camera和Capture都可以采集图⽚片,功能为什么会重 叠呢? A: 1.Camera API的实现在PhoneGap采纳W3C Capture API之 前,PhoneGap保留Camera API是为了和现有的应⽤用保持 向下兼容。 2.虽然两个API都可以采集image,但是以不同的⽅方式进⾏行 操作。Camera API只能采集图⽚片,但是既⽀支持从camera 拍照,⼜又可以从相册获取;Capture API只能直接从 camera拍照,并且⽀支持从⼀一个单独的API调⽤用进⾏行多个 采集。
  • 48. 使⽤用Capture API • 采集⼀一个或多个audio⽂文件: navigator.device.capture.captureAudio(onCaptureSuccess , onCaptureError, captureOptions); • 采集⼀一个或多个image⽂文件: navigator.device.capture.captureImage(onCaptureSuccess , onCaptureError, captureOptions); • 采集⼀一个或多个video⽂文件: navigator.device.capture.captureVideo(onCaptureSuccess , onCaptureError, captureOptions);
  • 49. Capture演⽰示 - ⾳音频采集 选择⾳音频 录⾳音机 保存结果 采集完成
  • 50. Capture演⽰示 - 图⽚片采集 选择图⽚片 相机 确定使⽤用 采集完成
  • 51. Capture演⽰示 - 视频采集 选择视频 开始摄像 完成 摄像完成
  • 52. Capture 演⽰示 - 采集多个
  • 53. Capture API 代码实例讲解 function doCapture() { //清空前⾯面的结果 res.innerHTML = "采集初始化..."; //从⻚页⾯面读取数量,时⻓长等参数 var numItems = document.getElementById("numItems").value; var capDur = document.getElementById("duration").value; //搞定采集类型 var captureType = document.getElementById("captureType").selectedIndex; switch(captureType) { case 0: //⾳音频采集 navigator.device.capture.captureAudio(onCaptureSuccess, onCaptureError, { duration : capDur, limit : numItems }); break; case 1: //图⽚片采集 navigator.device.capture.captureImage(onCaptureSuccess, onCaptureError, { limit : numItems }); break; case 2: //视频采集 navigator.device.capture.captureVideo(onCaptureSuccess, onCaptureError, { duration : capDur, limit : numItems }); break; } }
  • 55. captureOptions对象 - 属性 var captureOptions = {duration: 5, limit: 3}; • duration:时⻓长 • limit:采集次数限制 • mode:模式 不同采集类型的可⽤用选项 Capture选项 Capture类型 Duration Limit Mode Audio X X X Image X X Video X X X
  • 56. duration • duration属性只能应⽤用于⾳音频和视频采集,⽤用于控 制⼀一个特定媒体采集的⻓长度(以秒为单位)。允 许应⽤用指定⾳音视频剪辑的最⼤大秒数。 • 当在应⽤用中使⽤用时,⽤用户可以可以录制短于,但 是不能⻓长于这个属性设置的秒数。 • 注意:⺫⽬目前为⽌止,duration采集选项在Android和 BlackBerry上还不被⽀支持,只在iOS上录制⾳音频时 ⽀支持。由于这些限制,现在最好不要在PhoneGap 应⽤用上使⽤用这个选项。
  • 59. onCaptureSuccess的处理过程 function onCaptureSuccess(fileList) { var i, len, htmlStr; len = fileList.length; //确保采集成功。如果成功的话,length应该 > 0 if(len > 0) { htmlStr = "<p>Results:</p><ol>"; for( i = 0, len; i < len; i += 1) { alert(fileList[i].fullPath); htmlStr += '<li><a href="' + fileList[i].fullPath + '">' + fileList[i].name + '</a></li>'; } htmlStr += "</ol>"; //这是result内容 res.innerHTML = htmlStr; } } 采集结果是⼀一个MediaFile数组,遍历以获得所有采集结果。
  • 60. MediaType对象 • 对象属性 • name: ⽂文件名(⽆无路径信息)(DOMString) • fullPaht: ⽂文件全路径,包括⽂文件名(DOMString) • type: mime type(DOMString) • lastModifiedDate: 最后修改的⽇日期和时间(Date) • size: ⽂文件⼤大⼩小(以字节计)(Number) • ⽅方法 • MediaFile.getFormatData: 获得媒体⽂文件的格式信息。
  • 61. getFormatData⽅方法 mediaFile.getFormatData(     MediaFileDataSuccessCB successCallback,     [MediaFileDataErrorCB errorCallback] ); 成功的话,回调successCallBack,并传⼊入⼀一个 MediaFileData对象。
  • 62. MediaFileData对象 • 封装了有关媒体⽂文件的格式信息 • 属性: • codecs: ⾳音视频⽂文件的真实格式。(DOMString) • bitrate: 内容的平均⽐比特率。如果是图⽚片的话,这个属 性值为0。(Number) • height: 图⽚片或视频的⾼高度(像素)。如果是⾳音频剪辑的 话,这个属性值为0。(Number) • width: 图⽚片或视频的宽度(像素)。 如果是⾳音频剪辑的 话,这个属性值为0。(Number) • duration: ⾳音视频⽂文件的时⻓长(秒)。如果是图⽚片的话这 个值为0。
  • 63. onCaptureError的处理 function onCaptureError(e) { var msgText; //采集失败的话,清空前⾯面⽣生成的内容。 res.innerHTML = ""; //根据API返回的错误码构建⼀一个消息字符串 switch(e.code) { case CaptureError.CAPTURE_INTERNAL_ERR: msgText = "内部错误, 摄像头或者⻨麦克⻛风采集图⽚片或⾳音频失败。"; break; case CaptureError.CAPTURE_APPLICATION_BUSY: msgText = "摄像头应⽤用或者录⾳音机程序正在被其他采集请求使⽤用。"; break; case CaptureError.CAPTURE_INVALID_ARGUMENT: msgText = "传递给API的参数⽆无效。"; break; case CaptureError.CAPTURE_NO_MEDIA_FILES: msgText = "⽤用户可能取消了采集过程。"; break; case CaptureError.CAPTURE_NOT_SUPPORTED: msgText = "该设备不⽀支持请求的操作。"; break; default: //针对其他错误⽣生成⼀一个常规回复 msgText = "未知错误 (" + e.code + ")"; } //使⽤用alert通知⽤用户 navigator.notification.alert(msgText, null, "采集出错了!"); } 错误码定义及其含义
  • 65. What we will learn? • 罗盘原理及地磁轴和实际南北极的差别 • 通过API获得设备朝向 • 设置朝向变更⾃自动通知 • 使⽤用jQuery图⽚片旋转扩展和 Compass API 开发⼀一个 HTML5的指南针应⽤用
  • 66. Compass API简介 • Compass API 允许PhoneGap应⽤用通过⼀一个⼤大致对应 于地球表⾯面的⼆二维平⾯面来获得设备的朝向。⼤大多数 的智能⼿手机都装有⼀一个物理的罗盘传感器(芯⽚片), API就是简单的对芯⽚片进⾏行⼀一个查询,然后返回⼀一个0 到360度的⼀一个⾓角度来表⽰示设备所指的⽅方向。 • ⾓角度和⽅方向 • 0度 - 正北(N) • 90度 - 正东(E) • 180度 - 正南(S) • 270度 - 正⻄西(W)
  • 67. Compass API简介(续) • Compass API的⼯工作⽅方式和Accelerometer类似,既 可以⼿手动查询设备的朝向,也可以设定⼀一个watch 让API以⼀一个指定的频率在设备朝向变化超过设定 的最⼩小的阀值时向应⽤用报告朝向。 • 注意:不是所有的智能机都具有物理罗盘。 iPhone 3GS及以后都有,BlackBerry知道7 OS设备 才有。
  • 68. Compass 使⽤用演⽰示 得到当前朝向 设置观察者(每秒报告4次),使⽤用jQuery根据罗盘⽅方向⾃自动旋转图⽚片。 ⼀一个简单的HTML5的指南针应⽤用
  • 69. 获得设备朝向 • 查询设备朝向的API⽅方法: navigator.compass.getCurrentHeading( onSuccess, onError); function getHeading() { //alert("getHeading"); if(pgr == true) { if(hasCompass == true) { //清空当前的朝向内容, //输出提⽰示信息,以防读取数据耗时较⻓长 hc.innerHTML = "正在从罗盘获取当前朝向..."; //得到当前朝向 navigator.compass.getCurrentHeading(onHeadingSuccess, onHeadingError); } else { alert("没有找到罗盘。"); } } else { alert("请稍侯,PhoneGap 尚未就绪。"); } }
  • 70. onHeadingSuccess • 查询设备朝向成功时调⽤用 function onHeadingSuccess(heading) { var d = new Date(heading.timestamp); hc.innerHTML = "<b>Magnetic Heading:</b> " + heading.magneticHeading + "<br /><b>True Heading:</b> " + heading.trueHeading + "<br /><b>Heading Accuracy:</b> " + heading.headingAccuracy + "<br /><b>Timestamp:</b> " + d.toLocaleString(); }
  • 71. onHeadingError • 查询设备朝向失败时调⽤用 function onHeadingError(compassError) { //alert("onHeadingFailure"); if(compassError.code == CompassError.COMPASS_NOT_SUPPORTED) { hc.innerHTML = "Compass not available." alert("Compass not supported."); hasCompass == false; } else if(compassError.code == CompassError.COMPASS_INTERNAL_ERR) { alert("Compass Internal Error"); } else { alert("Unknown heading error!"); } }
  • 72. 设置观察者 • 设置罗盘朝向观测的API⽅方法: navigator.compass.watchHeading(onHeading Success, onHeadingError, watchOptions); function onDeviceReady() { alert("onDeviceReady"); //设置观察者 //每秒四次读取罗盘数据 (250 milliseconds, .25 seconds) var watchOptions = { frequency : 250 }; watchID = navigator.compass.watchHeading(onHeadingSuccess, onHeadingError, watchOptions); }
  • 73. compassOptions对象 • ⾃自定义读取罗盘数据选项的参数 • 属性 • frequency:毫秒计的获取罗盘数据间隔时⻓长(默认: 100)(Number) • filter:引发⼀一次watchHeading成功回调的最⼩小度数变 化。(Number)
  • 74. onHeadingSuccess • 读取罗盘数据成功时回调 function onHeadingSuccess(heading) { //alert("onHeadingSuccess"); var hv = Math.round(heading.magneticHeading); hi.innerHTML = "<b>Heading:</b>" + hv + " degrees"; $("#compass").rotate(-hv); }
  • 75. compassHeading对象 • 读取罗盘数据成功时传⼊入的数据对象 • magneticHeading:地磁轴的⽅方向,0-355.99度。 • trueHeading:地球转轴(地理南北极连线)的真正⽅方 向。【地磁轴和实际的南北极并不⼀一致,相交约11.5 度】 • headingAccuracy:报告的度数和实际度数之差。 • timestamp:获得数据时的时间戳。
  • 76. onHeadingError • 读取罗盘数据出错时回调 function onHeadingError(compassError) { //alert("onHeadingFailure"); //出错时移除观察者。 navigator.compass.clearWatch(watchID); //从⻚页⾯面上清空朝向数据。 hi.innerHTML = ""; //错误提醒。 if(compassError.code == CompassError.COMPASS_NOT_SUPPORTED) { alert("不⽀支持罗盘功能。"); } else if(compassError.code == CompassError.COMPASS_INTERNAL_ERR) { alert("罗盘内部错误!"); } else { alert("未知的朝向错误!"); } }
  • 77. watchOptions • 查询设备观测的API⽅方法: navigator.compass.watchHeading(onHeading Success, onHeadingError, watchOptions); function onDeviceReady() { alert("onDeviceReady"); //设置观察者 //每秒四次读取罗盘数据 (250 milliseconds, .25 seconds) var watchOptions = { frequency : 250 }; watchID = navigator.compass.watchHeading(onHeadingSuccess, onHeadingError, watchOptions); }
  • 79. Connection API简介 • PhoneGap Connection 对象提供给应⽤用程序当前 应⽤用可⽤用⺴⽹网络连接的相关信息。
  • 81. connection.type • Connection对象包含⼀一个单⼀一的属性: connection.type,具有下列常量值: • Connection.UNKNOWN • Connection.ETHERNET • Connection.WIFI • Connection.CELL_2G • Connection.CELL_3G • Connection.CELL_4G • Connection.NONE
  • 82. Connection 代码⽰示例 function onDeviceReady() { navigator.notification.alert("PhoneGap 就绪!"); //Add the online event listener document.addEventListener("online", isOnline, false); //Add the offline event listener document.addEventListener("offline", isOffline, false); } function isOnline() { //alert("isOnline"); var d = new Date(); $('#networkInfo').prepend("在线 (" + getConnectionTypeStr() + ")<br />"); } function isOffline() { //alert("isOffline"); var d = new Date(); $('#networkInfo').prepend("离线<br />"); } function getConnectionTypeStr() { //得到⺴⽹网络状态 var networkState = navigator.network.connection.type; alert(networkState); //返回表⽰示⺴⽹网络状态的字符串 //return states[networkState]; return networkState; }
  • 85. Contacts API简介 • PhoneGap Contacts API 为应⽤用提供了⼀一个到设备 联系⼈人数据库的访问接⼝口,可以被⽤用来从设备的 本地“联系⼈人”应⽤用创建,定位,编辑,拷⻉贝以及 删除联系⼈人记录。 • PhoneGap的Contacts API是W3C Contacts API 规范 的⼀一个实现。
  • 86. Contacts 演⽰示 - 创建新联系⼈人
  • 87. 创建⼀一个联系⼈人 • 返回⼀一个新的Contact对象 function addContact() { alert("Adding " + contactInfo.FullName + " to contacts application"); var contact = navigator.contacts.create(); contact.displayName = contactInfo.FullName; contact.nickname = contactInfo.FullName; var tmpName = new ContactName(); tmpName.givenName = contactInfo.FirstName; tmpName.familyName = contactInfo.LastName; tmpName.formatted = contactInfo.FullName; contact.name = tmpName; var phoneNums = [2]; phoneNums[0] = new ContactField('work', contactInfo.OfficePhone, false); phoneNums[1] = new ContactField('mobile', contactInfo.MobilePhone, true); contact.phoneNumbers = phoneNums; var emailAddresses = [1]; emailAddresses[0] = new ContactField('home', contactInfo.EmailAddress, true); contact.emails = emailAddresses; // 保存到设备 contact.save(onContactSaveSuccess, onContactSaveError); }
  • 88. Contact对象 • id: A globally unique identifier. (DOMString) • displayName: The name of this Contact, suitable for display to end-users. (DOMString) • name: An object containing all components of a persons name. (ContactName) • nickname: A casual name to address the contact by. (DOMString) • phoneNumbers: An array of all the contact's phone numbers. (ContactField[]) • emails: An array of all the contact's email addresses. (ContactField[]) • addresses: An array of all the contact's addresses. (ContactAddress[]) • ims: An array of all the contact's IM addresses. (ContactField[]) • organizations: An array of all the contact's organizations. (ContactOrganization[]) • birthday: The birthday of the contact. (Date) • note: A note about the contact. (DOMString) • photos: An array of the contact's photos. (ContactField[]) • categories: An array of all the contacts user defined categories. (ContactField[]) • urls: An array of web pages associated to the contact. (ContactField[])
  • 89. 成功和失败的回调函数 function onContactSaveSuccess() { alert(contactInfo.FullName + " 已经成功保存到设备联系⼈人数据库。"); } function onContactSaveError(e) { var msgText; switch(e.code) { case ContactError.UNKNOWN_ERROR: msgText = "An Unknown Error was reported while saving the contact."; break; case ContactError.INVALID_ARGUMENT_ERROR: msgText = "An invalid argument was used with the Contact API."; break; case ContactError.TIMEOUT_ERROR: msgText = "Timeout Error."; break; case ContactError.PENDING_OPERATION_ERROR: msgText = "Pending Operation Error."; break; case ContactError.IO_ERROR: msgText = "IO Error."; break; case ContactError.NOT_SUPPORTED_ERROR: msgText = "Not Supported Error."; break; case ContactError.PERMISSION_DENIED_ERROR: msgText = "Permission Denied Error.";
  • 90. Contacts 演⽰示 - 联系⼈人搜索
  • 91. 搜索联系⼈人 navigator.contacts.find(contactFields, contactSuccess, contactError, contactFindOptions); function searchContacts() { alert("searchContacts"); $('#contacts').html('<p>Search Results</p>'); var searchStr = document.getElementById("editSearch").value; var searchScope = document.getElementById("searchScope").selectedIndex; var contactFields = []; switch(searchScope) { case 1: contactFields = ['displayName', 'name', 'nickname']; break; case 2: contactFields = ['streetAddress', 'locality', 'region', 'postalCode', 'country']; break; case 3: contactFields = ['note']; break; default: contactFields = ['*']; } //Populate the search options object var searchOptions = { filter : searchStr, multiple : true, }; //Execute the search navigator.contacts.find(contactFields, onContactSearchSuccess, onContactSearchError, searchOptions);
  • 92. onContactSearchSuccess function onContactSearchSuccess(contacts) { var i, len, theList; contactList = contacts; len = contacts.length; if(len > 0) { theList = '<ul data-role="listview">'; for( i = 0, len; i < len; i += 1) { if(contacts[i].displayName == null) { theList += '<li><a onclick="showContact(' + i + ');">' + contacts[i].name.familyName + ", " + contacts[i].name.givenName + '</a></li>'; } else { theList += '<li><a onclick="showContact(' + i + ');">' + contacts[i].displayName + '</a></li>'; } } theList += '</ul>'; $('#contacts').replaceWith(theList); $.mobile.changePage("#contactList", "slide", false, true); } else { navigator.notification.alert('Search returned 0 results', null, 'Contact Search'); } }
  • 93. 克隆联系⼈人 var contact2 = contact1.clone(); 返回调⽤用Contact对象的拷⻉贝
  • 96. Device API简介 PhoneGap Device 对象允许应⽤用访问关于应⽤用和运 ⾏行⼀一个PhoneGap应⽤用的设备的有限数量的信息。 device.name: 根据平台的不同,有可能是设备⼚厂商 分配的名称或者是⼿手机⽤用户设置的名称. device.cordova:构建应⽤用的PhoneGap的版本号; device.platform: 移动设备平台的的名称; device.uuid: universally unique identifier device.version: 操作系统版本号
  • 97. Device API Demo function onDeviceReady() { //得到要操作的DOM元素 var element = document.getElementById("deviceInfo"); //替换成使⽤用设备信息 element.innerHTML = "<b>device.name: " + device.name + br + "<b>device.cordova:</b> " + device.cordova + br + "<b>device.platform:</b> " + device.platform + br + "<b>device.uuid:</b> " + device.uuid + br + "<b>device.version:</b> " + device.version + br; }
  • 99. Events API简介 PhoneGap Events API 可以让应⽤用程序为发⽣生在⽀支持 的smartphone设备上的不同的事件注册事件监听 器。 • deviceready 事件 • Application status 事件 • Network 事件 • Button 事件
  • 101. deviceready Event function onBodyLoad() { document.addEventListener("deviceready", onDeviceReady, false); } function onDeviceReady() { navigator.notification.alert("PhoneGap就绪!"); } document.addEventListener(“eventName”, functionName, useCapture); eventName: 事件名字符串 functionName:触发时调⽤用的⽅方法 useCapture:⼀一般是false
  • 102. Application Stauts 事件 • foreground & background • pause event & resume event • 事件处理:数据库,⺴⽹网络,媒体播放... function onDeviceReady() { document.addEventListener("pause", processPause, false); document.addEventListener("resume", processResume, false); } function processPause() { pi.innerHTML = "Application paused."; startTime = new Date(); } function processResume() { if(firstTime == true) { firstTime = false; pi.innerHTML = "Skipping first Resume."; } else { endTime = new Date(); timeDiff = (endTime - startTime) / 1000;
  • 103. Network Status 事件 • online event • offline event function onDeviceReady() { alert("onDeviceReady"); document.addEventListener("online", isOnline, false); document.addEventListener("offline", isOffline, false); } function isOnline() { var d = new Date(); $('#networkInfo').prepend("Online: " + d.toLocaleString() + "<br />"); } function isOffline() { var d = new Date(); $('#networkInfo').prepend("Offline: " + d.toLocaleString() + "<br />"); }
  • 105. Button Event DemoCode if((pName == "Android") || (pName == "3.0.0.100")) { eventCount += 2; //Android & BlackBerry only events document.addEventListener("backbutton", onBackButton, false); document.addEventListener("menubutton", onMenuButton, false); } if(pName == "Android") { eventCount += 1; //Android only event document.addEventListener("searchbutton", onSearchButton, false); } if(pName == "3.0.0.100") { eventCount += 4; //BlackBerry only events document.addEventListener("startcallbutton", onStartCallButton, false); document.addEventListener("endcallbutton", onEndCallButton, false); document.addEventListener("volumedownbutton", onVolumeUpButton, false); document.addEventListener("volumeupbutton", onVolumeDownButton, false); } //did we register any event listeners? if(eventCount < 1) { //0, must be running on an iOS device alert("Must be running on an iOS device.nNo event listeners registered"); } else { //Android or BlackBerry alert("Registered " + eventCount + " event listeners."); } }
  • 106. Files
  • 107. File API简介 PhoneGap File API 提供给应⽤用程序对移动设备上的 临时⽂文件或者持久化⽂文件系统进⾏行访问的⽅方法。包 括: locate, read , write, copy, move以及remove。 PhoneGap File API 基于部分W3C File API 规范实 现:Directories and System specification。 只提供了开发者最常⽤用的功能,并没有完全实现 W3C规范。
  • 109. 可⽤用的存储类型 • temporary storage location • 从⺴⽹网上可以直接下载到的 • 应⽤用⽣生成的临时⽂文件 • ... • persistent storage • ⽤用户⽣生成的内容 • 应⽤用的配置信息 • ...
  • 110. Accessing the Device’s File System function processDir(fileSystemType) { alert("processDir: " + fileSystemType); window.requestFileSystem(fileSystemType, 1024 * 1024, onGetFileSystemSuccess, onFileError); } <p> 选择⽂文件系统: <input type="button" value="临时⽂文件" onclick="processDir(LocalFileSystem.TEMPORARY);"> <input type="button" value="持久存储" onclick="processDir(LocalFileSystem.PERSISTENT);"> </p>
  • 111. Reading Directory Entries var theFileSystem; function processDir(fileSystemType) { alert("processDir: " + fileSystemType); window.requestFileSystem(fileSystemType, 1024 * 1024, onGetFileSystemSuccess, onFileError); } function onGetFileSystemSuccess(fs) { alert("onGetFileSystemSuccess: " + fs.name); //保存返回的⽂文件系统句柄 theFileSystem = fs; //创建⼀一个Directory Reader var dr = fs.root.createReader(); // 读取根⺫⽬目录内容 dr.readEntries(onDirReaderSuccess, onFileError); } DirectoryReader
  • 112. onDirReaderSuccess function onDirReaderSuccess(dirEntries) { FileEntry or DirectoryEntry数组 theEntries = dirEntries; var i, fl, len; len = theEntries.length; if(len > 0) { for( i = 0; i < len; i++) { if(theEntries[i].isDirectory == true) { fl += '<li><a href="#" onclick="processEntry(' + i + ');">⺫⽬目录: ' + theEntries[i].name + '</a></li>'; } else { fl += '<li><a href="#" onclick="processEntry(' + i + ');">⽂文件: ' + theEntries[i].name + '</a></li>'; } } } else { fl = "<p>No entries found</p>"; $('#dirEntries').html(fl); } }
  • 113. Accessing FileEntry and DirectoryEntry Properties • isFile • isDirectory • name • fullPath function processEntry(entryIndex) { theEntry = theEntries[entryIndex]; //FileInfo variable var fi = ""; fi += startP + '<b>Name</b>: ' + theEntry.name + endP; fi += startP + '<b>Full Path</b>: ' + theEntry.fullPath + endP; fi += startP + '<b>URI</b>: ' + theEntry.toURI() + endP; if(theEntry.isFile == true) { fi += startP + 'The entry is a file' + endP; } else { fi += startP + 'The entry is a directory' + endP; }
  • 114. MetaData function onGetMetadataSuccess(metadata) { // alert("onGetMetadataSuccess"); var md = ''; for(aKey in metadata) { md += '<b>' + aKey + '</b>: ' + metadata[aKey] + br; } md += hr; $('#fileMetadata').html(md); }
  • 115. Writing Files function writeFile() { //随机⽣生成⼀一个⽂文件名 var theFileName = createRandomString(8) + '.txt'; theFileSystem.root.getFile(theFileName, { create : true }, onGetFileSuccess, onFileError); } function onGetFileSuccess(theFile) { theFile.createWriter(onCreateWriterSuccess, onFileError); } function onCreateWriterSuccess(writer) { writer.onwritestart = function(e) { console.log("Write start"); }; writer.onwriteend = function(e) { console.log("Write end"); }; writer.onwrite = function(e) { console.log("Write completed"); }; writer.onerror = function(e) { console.log("Write error: " + e.toString() + br); }; writer.write("File created by PHoneGap File API: "); writer.write("This is another line of text "); writer.write(createRandomStory(25)); }
  • 116. Reading Files function viewFile() { theEntry.file(onFileReaderSuccess, onFileError); } function onFileReaderSuccess(file) { var reader = new FileReader(); reader.onloadend = function(e) { $('#readInfo').append("加载完成" + br); $('#fileContents').text(e.target.result); }; reader.onloadstart = function(e) { $('#readInfo').append("开始加载" + br); }; reader.onloaderror = function(e) { $('#readInfo').append("加载错误: " + e.target.error.code + br); }; reader.readAsText(file); }
  • 117. Deleting Files or Directories function removeFile() { theEntry.remove(onRemoveFileSuccess, onFileError); } function onRemoveFileSuccess(entry) { alert("Successfully removed " + entry.name); }
  • 118. Copying Files or Directories theEntry.copyTo(parentEntry, newName, onSuccessFunction, onErrorFunction); parentEntry: 要拷⻉贝的⽂文件或⺫⽬目录 newName: ⺫⽬目标
  • 119. Moving Files or Directories theEntry.copyTo(parentEntry, newName, onSuccessFunction, onErrorFunction);
  • 120. Uploading Files to a Server var ft = new FileTransfer(); ft.upload(fileURI, serverURL, onUploadSuccess, onUploadError, fileUploadOptions);
  • 123. Geolocation API简介 PhoneGap Geolocation API 允许设备利⽤用移动设备 上的GPS能⼒力来判断设备在地球表⾯面上的位置。 应⽤用可以直接⼿手动获取当前位置,也可以设置⼀一个 观察者,当位置变化时可以周期性的通知应⽤用。
  • 125. Getting a Device’s Current Location
  • 126. Get Current Position 使⽤用Position对象返回⼀一个设备的当前位置 navigator.geolocation.getCurrentPosition( onGeolocationSuccess, [onGeolocationError], [geolocationOptions]); 参数: • onGeolocationSuccess: 成功时使⽤用当前位置回调 • onGeolocationError: 可选,出错时调⽤用 • geolocationOptions: 可选,geolocation选项 说明: geolocation.getCurrentPosition是⼀一个异步调⽤用的函数。将设备的当前位置 作为⼀一个Position参数返回给geolocationSuccess函数。出错的时候,使⽤用 ⼀一个PositionError对象回调geolocationError回调函数。
  • 127. onGeolocationSuccess Position Coordinates 位置的地理坐标的⼀一系列属性的描述 包含Position坐标和时间戳,由 属性: geolocation API⽣生成。 latitude: ⼗十进制的纬度(Number) longitude: ⼗十进制表⽰示的精度(Number) 属性: altitude: 地⾯面海拔(Number) coords:地理位置坐标的集合 accuracy: 经纬度坐标的精度,以⽶米为单位(Number) (Coordinates) altitudeAccuracy: 以⽶米为单位的海拔坐标; heading: 顺时针计数的正北⽅方向⾓角度 timestamp:coords⽣生成的时间戳 speed: 设备当前的地⾯面速度。 (Date) 说明: Coordinates对象有Cordova创建,附加到Position对象。 注意:对于Android,海拔精度⺫⽬目前还不⽀支持。 function onLocationSuccess(loc) { alert("onLocationSuccess"); var d = new Date(loc.timestamp); lc.innerHTML = '<b>当前位置</b><hr /><b>纬度</b>: ' + loc.coords.latitude + '<br / ><b>经度</b>: ' + loc.coords.longitude + '<br /><b>⾼高度</b>: ' + loc.coords.altitude + '<br /><b>精度</b>: ' + loc.coords.accuracy + '<br /><b>海拔精确度</b>: ' + loc.coords.altitudeAccuracy + '<br /><b>航向</b>: ' + loc.coords.heading + '<br /><b>速度 </b>: ' + loc.coords.speed + '<br /><b>时间戳</b>: ' + d.toLocaleString(); }
  • 128. onGolocationError PositionError对象 出错时,⼀一个PositionError对象会返回给geolocationError回调函数 属性: code:预定义的错误码 message:对错误码的详细描述 常量: PositionError.PERMISSION_DENIED, ⽤用户不允许使⽤用位置信息。 PositionError.POSITION_UNAVAILABLE, ⽆无法取得位置信息,⽐比如设备没有GPS功能, 或者没有⺴⽹网络连接。 PositionError.TIMEOUT:指定的时间内⽆无法取得位置信息。 function onLocationError(e) { alert("Geolocation error: #" + e.code + "n" + e.message); }
  • 129. geolocationOptions ⾃自定义抓取位置的选项 { maximumAge: 3000, timeout: 5000, enableHighAccuracy: true} 选项: enableHighAccuracy: 要求设备返回最精确的结果。默认情况下,设备会尝试使⽤用基于⺴⽹网络的 ⽅方法返回Position。设置这个参数为true来告诉框架使⽤用更精确地⽅方法,⽐比如卫星定位系统。 timeout: 允许geolocation.getCurrentPosition和geolocation.watchPosition的最⻓长时间。如果在 指定时间内,geolocationSuccess回调没有被调⽤用,则geolocationError会被调⽤用,带有⼀一个 PositionError.TIMEOUT的错误码。和watchPosition⽅方法结合使⽤用的话,会每timeout时间调⽤用⼀一 次geolocationError回调。 maximumAge:不超过指定时间毫秒数的位置缓存。 var locOptions = { timeout : 5000, enableHighAccuracy : true }; //获得当前位置 navigator.geolocation.getCurrentPosition(onLocationSuccess, onLocationError, locOptions);
  • 130. Watching a Device Location
  • 131. Setting a Watch var watchId = navigator.geolocation.watchPosition( geolocationSuccess, [geolocationError], [geolocationOptions]); 观察设备当前位置的变化 参数: • geolocationSuccess: 成功带着当前位置回调; • geolocationError: 可选,出错时回调; • geolocationOptions: 可选,geolocation选项 返回: String:返回⼀一个watch id,是watch position interval观察位置间隔的引⽤用。应该和 geolocation.clearWatch⼀一起使⽤用来停⽌止观察位置变化。 说明: geolocation.watchPosition是⼀一个异步函数。当检测到位置变化时会返回设备的当前 位置。当设备取得⼀一个新的位置,geolocationSuccess回调被调⽤用,带着⼀一个Position 对象作为参数。如果出错了,geolocationError回调被调⽤用,带着PositionError对象。
  • 132. Code of setting and canceling a Watch //Geolocation Options var locOptions = { maximumAge : 10000, timeout : 5000, enableHighAccuracy : true }; //增加观察者 watchID = navigator.geolocation.watchPosition(onLocationSuccess, onLocationError, locOptions); function cancelWatch() { navigator.geolocation.clearWatch(watchID); watchID = null; }
  • 133. Media
  • 134. Media API简介 PhoneGap Media API提供了在设备上录⾳音和播放⾳音 频⽂文件的能⼒力。 提⽰示:当前Media API的实现并没有遵循W3C的媒体 捕捉的规范,只是提供了⼀一个实现供⼤大家⽅方便使 ⽤用。未来的实现将会遵循W3C有关媒体捕捉的规 范,并且有可能会弃⽤用现在的API。也就是上⾯面列 出来的这个。
  • 137. 创建⼀一个Media对象 var media = new Media(mediaFileURI, onMediaSuccess, [mediaError], [mediaStatus]; 注意:这⾥里的onMediaSuccess不会在new Media完成后执⾏行,⽽而是会在 每次播放或者录⾳音完成后调⽤用。 new Media完成后,可以对media判断时⻓长或者读设当前位置,但是这些 操作都不会得到任何值,除⾮非已经开始播放。 // var fileName = "http://192.168.1.103/~tom/dan.mp3"; var fileName = "/android_asset/www/eye.mp3"; theMedia = new Media(fileName, onMediaSuccess, onMediaError, onMediaStatus);
  • 138. File URI • ⽂文件既可以是本地⽂文件系统⽂文件, • 也可以是located在⽂文件服务器的⽂文件; • 或者是项⺫⽬目中的⽂文件。 var fileName = "/android_asset/www/eye.mp3"; var fileName = "http://192.168.1.103/~tom/dan.mp3";
  • 139. MediaError 出错时⼀一个MediaError对象被返回给mediaError回调函数。 属性: code:下⾯面列出的⼀一个预定义的错误码; message:详细描述错误的错误消息。 常量: MediaError.MEDIA_ERR_ABORTED MediaError.MEDIA_ERR_NETWORK MediaError.MEDIA_ERR_DECODE MediaError.MEDIA_ERR_NONE_SUPPORTED function onMediaError(e) { var msgText = "Media error: " + e.message + "(" + e.code + ")"; console.log(msgText); navigator.notification.alert(msgText, null, "Media Error"); }
  • 140. statusCode • 0: Media.MEDIA_NONE • 1: Media.MEDIA_STARTING • 2: Media.MEDIA_RUNNING • 3: Media.MEDIA_PAUSED • 4: Media.MEDIA_STOPPED function onMediaStatus(statusCode) { console.log("Status: " + statusCode); alert("Status: " + statusCode); }
  • 141. Duration 返回⾳音频⽂文件的⻓长度 media.getDuration() 说明 如果能获得⾳音频⽂文件⻓长度的话,media.getDuration函 数是⼀一个同步函数,返回以秒为单位的⾳音频⽂文件的⻓长 度。 如果获得不了的话(⽐比如当前没有正在播放),会返 回-1.
  • 142. Current Position 返回声⾳音⽂文件内的当前位置 media.getCurrentPosition(mediaSuccess, [mediaError]); 参数 mediaSuccess:带着以秒为单位的当前位置进⾏行回调。 mediaError:可选,出错时调⽤用。 需要设置⼀一个定时器来获取当前位置 说明:media.getCurrentPosition函数是⼀一个返回Media对象底层声⾳音⽂文件的当前位置的异 步函数。同时更新Media对象的_position参数。 function updateUI() { console.log("updateUI"); theMedia.getCurrentPosition(onGetPosition, onMediaError); } function onGetPosition(filePos) { console.log("onGetPosition"); //We won't have any information about the file until it's // actually played. Update the counter on the page $('#pos').html('时间: ' + Math.floor(filePos) + ' , 共: ' + theMedia.getDuration() + ' seconds'); }
  • 145. Play theMedia.play(); 没有回调函数! 因此要获得当前播放位置并在界⾯面上更新的话,要 ⾃自⼰己设置定时器。 function doPlay() { if(theMedia) { console.log("doPlay"); //开始播放 theMedia.play(); //设置计时器更新UI theTimer = setInterval(updateUI, 1000); } else { alert("No media file to play"); } }
  • 146. Pause theMedia.pause(); 暂停语⾳音播放的同步函数。 Notes: 如果在当前没有播放的Media对象上调⽤用 pause,不会报错。 function doPause() { if(theMedia) { console.log("doPause"); //Pause media play theMedia.pause(); window.clearInterval(theTimer); } }
  • 147. Stop theMedia.stop(); 停⽌止播放声⾳音的同步⽂文件 Note: 和pause⼀一样,在没有正在播放的Media对象上调⽤用 stop,也不会报错。 function doStop() { if(theMedia) { console.log("doStop"); //停掉计时器 theTimer = null; //停⽌止播放 theMedia.stop(); } }
  • 148. Seek theMedia.seekTo(milliseconds); 设置⼀一个语⾳音⽂文件的当前位置。 • 说明:异步更新当前位置的函数。同时也更新 _position参数。 var my_media = new Media(src, onSuccess, onError); my_media.play(); setTimeout(function() { my_media.seekTo(1000); }, 5000);
  • 150. Start Recording theMedia.startRecord(); 开始录制语⾳音⽂文件的同步函数。 Note: 和play同样的问题,没有回调函数。⾃自⼰己设置定时器,获 取时⻓长,更新UI。出错时创建Media对象时的onError会被调⽤用。 function recordAudio() { var src = “myrecording.mp3”; var mediaRec = new Media(src, function() { console.log(“recordAudio(): Audio success!”); }, function() { console.log(“recordAudio(): Audio.Error: ” + err.code); }); // Record audio mediaRec.startRecord(); }
  • 153. Notification API简介 PhoneGap Notification API 允许应⽤用向⽤用户提供可 视化,触觉化或者可听⻅见的反馈。 • notification.alert • notification.confirm • notification.beep • notification.vibrate
  • 156. notification.alert 显 ⽰示 ⼀一 个 按 钮 显⽰示⼀一个⾃自定义的alert或者对话框。 对于这个功能⼤大 多数的Cordova的实现使⽤用⼀一个本地的对话框。然⽽而,有些 平台简单的使⽤用浏览器的alert功能,这些alert的可定制性就 稍微差⼀一些。 navigator.notification.alert(message_t ext, callback_function, [“title”], [“button_text”]) • message: 对话框消息(String) • alertCallback:当对话框消息释放的时候调⽤用的回调⽅方 法(Function) • title: 对话框标题(String)(可选,默认是:”Alert”) • buttonName: 按钮名称(String)(可选,默认:”OK”)
  • 157. alert sample <div data-role="fieldcontain"> <label for="msgText">消息⽂文本:</label> <input type="text" name="msgText" id="msgText" value="这是 ⼀一条⽂文本消息!" /> <div data-role="controlgroup" data-type="horizontal"> <input type="button" value="Alert" onclick="doAlert();"> <input type="button" value="Confirm" onclick="doConfirm();"> </div> </div> function doAlert() { msgText = document.getElementById('msgText').value; navigator.notification.alert(msgText, onDoAlert, "Alert⽰示例", "Click Me!"); } function onDoAlert() { alert("Click Me Button!"); }
  • 158. 显 notification.confirm ⽰示 ⼀一 个 或 多 个 显⽰示⼀一个⾃自定义的确认对话框 按 钮 navigator.notification.confirm(message_text, callback_confirm, [“title”], [“button_text_array”]) • message: 对话框消息(String) • confirmCallback: 回调⽅方法,带着被按下按钮的索引(1,2,或3)(Function) • title: 对话框标题(String)(可选,默认是:“Confirm”) • buttonLabels:逗号分割的按钮标签字符串(String)(可选,默认是:“OK, Cancel”) • 说明 • notification.confirm函数显⽰示⼀一个⽐比浏览器的确认框更具定制化的本地对话框。 • confirmCallback • 当⽤用户按下了确认框的按钮之⼀一时confirmCallback会被调⽤用。 • 这个回调函数带有⼀一个buttonIndex(数值)参数,是被按下按钮的索引。需要指出的是这 ⾥里使⽤用的索引是以1开始的,所以这⾥里的值是1,2,3这样。
  • 159. confirmation代码 function doConfirm() { msgText = document.getElementById('msgText').value; navigator.notification.confirm(msgText, onDoConfirm, "Confirmation⽰示例", "Yes, No, Maybe"); } function onDoConfirm(btnNum) { if(btnNum == "1") { alert("Thanks for saying yes!"); } else { alert("Too bad, you said no."); } }
  • 160. notification.beep 设备将会发出⼀一声蜂鸣声。 navigator.notification.beep(times) times: 重复beep的次数(Number) function doBeep() { beepCount = document.getElementById('beepSlider').value; navigator.notification.beep(beepCount); }
  • 161. 平台差异 • iOS: 第⼀一iOS会忽略beep次数参数,也就是说只 beep⼀一次;第⼆二,因为iOS没有native的beep API,所以: • Cordova使⽤用media API通过播放⼀一个声⾳音⽂文件的⽅方式 实现了beep功能; • ⽤用户必须提供⼀一个beep的声⾳音⽂文件; • 声⾳音⽂文件必须少于30秒,要放在www/根⺫⽬目录下,并 且必须命名为beep.wav。 • Windows Phone 7:WP7的Cordova库包含了⼀一个通⽤用 的beep⽂文件。在lib/windows-phone/templates/ standalone/cordovalib⺫⽬目录下。
  • 162. notification.vibrate 使设备震动指定时⻓长 navigator.notification.vibrate(millis econds) time: 使设备震动的毫秒数,数值类型。 例⼦子:navigator.notification.vibrate(2500) • 平台差异 • iPhone:会忽略震动时⻓长参数,使⽤用⾃自⾝身预设的震动 时⻓长。 function doVibe() { vibeCount = document.getElementById('vibeSlider').value; navigator.notification.vibrate(vibeCount); }
  • 164. Storage API简介 • ⼤大多数HTML5兼容的浏览器都提供给Web Application从本地存储设施读写key/value键值对 的能⼒力,以及从本地SQL 数据库读写数据的能 ⼒力。这两种能⼒力都不是HTML直接提供的,⽽而是通 过在浏览器内运⾏行⽀支持的JavaScript代码实现的。 • PhoneGap Storage API 是基于 W3C Web SQL Database 规范以及 W3C Web Storage API 规范。有 些设备已经提供了这个规范的⼀一个实现。对于这 些设备,使⽤用其内置的⽀支持⽽而不是使⽤用Cordova的 实现来替代。对于不⽀支持存储的设备,Cordova的 实现是兼容W3C规范的。
  • 166. localStorage - UI <section id="config" data-role="page" > <header data-role="header"> <h1>MT 配置</h1> </header> <div data-role="content"> <div data-role="fieldcontain"> <legend> 每⽇日清除旧的记录吗? </legend> <label for="purgeStatus">启⽤用清除</ label> <input type="checkbox" name="purgeStatus" id="purgeStatus" /> <label for="purgeInterval">清除间隔</ label> <input type="number" id="purgeInterval" name="purgeInterval" /> 天 </div> <input type="button" value="保存配置" onclick="saveConfig();">
  • 167. localStorage - setItem function saveConfig() { //将配置设置写⼊入localStorage window.localStorage.setItem("purgeStatus", document.getElementById("purgeStatus").checked); window.localStorage.setItem("purgeInterval", document.getElementById("purgeInterval").value); //切换回主界⾯面 $.mobile.changePage("#main", "flip", false, false); }
  • 168. localStorage - getItem purgeStatus = window.localStorage.getItem("purgeStatus"); purgeInterval = window.localStorage.getItem("purgeInterval"); if(purgeStatus == "true") { $("#purgeStatus").attr("checked", true); $("#purgeInterval").attr('value', purgeInterval); doPurge(purgeInterval); }
  • 169. localStorage localStorage提供了到W3C Storage接⼝口的接⼝口;允 许以key-value形式保存数据。 // 写⼊入配置 window.localStorage.setItem("key", "value"); // 读取配置 var value = window.localStorage.getItem("key"); // 返回指定位置key的名称 var keyname = window.localStorage.key(0); // 删除key指定的位置的项 window.localStorage.removeItem("key"); // 删除所有键值对 window.localStorage.clear();
  • 173. openDatabase var dbShell = window.openDatabase(database_name, database_version, database_displayname, database_size); 这个⽅方法将创建⼀一个新的 SQLite 数据库,并且返回⼀一个Database对 象。使⽤用这个Database对象来操作数据。 • 参数 • database_name:数据库名(写⼊入设备内存的数据库⽂文件名) • database_version:数据库版本(应⽤用可以据此进⾏行升级操作) • database_displayname:数据库显⽰示名 • database_size:分配给数据库的空间⼤大⼩小(字节) //创建或者打开数据库 console.log("Opening database"); theDB = window.openDatabase("mtDB", "1.0", "Mileage Tracker", 3 * 1024 * 1024); console.log("Checking theDB"); if(theDB) {
  • 174. Database对象 包含允许⽤用户操作数据库的⽅方法 • ⽅方法 • transaction: 运⾏行⼀一个数据库事务; • changeVersion: 允许脚本在更新schema的同时⾃自动地确认版本号并且更 改。 • 说明 • Database对象从window.openDatabase()的调⽤用返回。 function saveRecord() { console.log("Entering saveRecord"); //这⾥里可以做⼀一些数据验证⼯工作,⽐比如⽇日期要有效,numMiles > 0 //保存记录 theDB.transaction(insertRecord, onTxError, onTxSuccess); console.log("Leaving saveRecord"); }
  • 175. SQLTransaction • 包含允许⽤用户对数据库执⾏行SQL语句的⽅方法 • ⽅方法 • executeSql:执⾏行⼀一条SQL语句 • 说明:当你调⽤用Database对象事务⽅方法时,它的 回调⽅方法会被调⽤用,带着⼀一个SQLTransaction对 象。⽤用户可以通过调⽤用executeSql⽅方法多次来构建 ⼀一个数据库事务。
  • 176. executeSql function insertRecord(tx) { console.log("Entering insertRecord"); //创建⼀一个新的Date对象来持有⽤用户输⼊入的⽇日期 var tmpDate = new Date.fromString(document.getElementById("editDate").value); console.log("Date: " + tmpDate.valueOf()); var tmpMiles = document.getElementById("editNumMiles").value; console.log("Miles: " + tmpMiles); var tmpNotes = document.getElementById("editNotes").value; console.log("Notes: " + tmpNotes); var sqlStr = 'INSERT INTO MILEAGE (tripDate, miles, notes) VALUES (?, ?, ?)'; console.log(sqlStr); tx.executeSql(sqlStr, [tmpDate.valueOf(), tmpMiles, tmpNotes], onSqlSuccess, onSqlError); // 使⽤用jQuery重置表单的输⼊入值 var blankVal = { value : '' }; $("#editNumMiles").attr(blankVal); $("#editNotes").attr(blankVal); console.log("Leaving insertRecord"); }
  • 177. SQLResultSet 当⼀一个SQLTransaction的executeSql⽅方法被调⽤用时,会带着 SQLResultSet对象调⽤用它的回调函数。 • 属性 • insertId:SQLResultSet对象的SQL语句插⼊入到数据库中的⾏行的⾏行编号。 • rowsAffected: 被SQL语句影响的数据库记录的⾏行数。如果该语句没有影响到 任何⾏行,rowsAffected会被设置为0。 • rows: 表⽰示返回的⾏行的SQLResultSetRowList。如果没有⾏行被返回,这个对 象为空。 • 说明:如果Insert语句成功执⾏行的话,insertId是插⼊入⾏行的编号。如果 这条SQL语句不是insert语句,insertId属性不会被设置。对于insert或 update语句⽽而⾔言,会返回受影响的记录数。最后⼀一个属性的类型是 SQLResultSetList,包含的是SQL的select语句返回的数据。
  • 178. SQLResultSet - insert function onSqlSuccess(tx, res) { console.log("SQL: success"); if(res) { console.log(res); alert("insertId = " + res.insertId); alert("rowsAffected = " + res.rowsAffected); } } function onSqlError(tx, err) { console.log("Entering onSqlError"); var msgText; if(err) { msgText = "SQL: " + err.message + " (" + err.code + ")"; } else { msgText = "SQL: Unknown error"; } console.error(msgText); alert(msgText); console.log("Leaving onSqlError"); }
  • 179. SQLResutSetList SQLResultSetList包含由SQL查询语句返回的数据。 这个对象包含⼀一个⻓长度属性能让你知道select语句 返回了多少⾏行。为了得到⼀一个⾏行数据,你应该通过 指定⼀一个索引来调⽤用item⽅方法。item⽅方法返回⼀一个 JavaScript对象,这个对象的属性就是⾏行记录的列数 据。 • 属性 • length: 由SQL查询返回的⾏行数 • ⽅方法 • item:返回由JavaScript对象表⽰示的指定索引的⾏行。
  • 180. SQLResultSetList - query function onQuerySuccess(tx, results) { console.log("Entering onQuerySuccess"); if(results.rows) { console.log("Rows: " + results.rows); var htmlStr = ""; var len = results.rows.length; if(len > 0) { for(var i = 0; i < len; i++) { var theDate = new Date(results.rows.item(i).tripDate); htmlStr += '<b>⽇日期:</b> ' + theDate.toDateString() + '<br />'; var numMiles = results.rows.item(i).miles; if(numMiles > 1) { htmlStr += '<b>英⾥里:</b> ' + numMiles + ' miles<br />'; } else { htmlStr += '<b>英⾥里:</b> 1 mile<br />'; } //检查是否有备注 var theNotes = results.rows.item(i).notes; if(theNotes.length > 0) { htmlStr += '<b>备注:</b> ' + theNotes + '<br />'; } htmlStr += '<hr />'; }
  • 181. SQLError 当操作数据库有错误发⽣生时抛出SQLError错误。 • 属性 • code:下⾯面列出来的预定义错误之⼀一 • message: 错误描述 • 常量 • SQLError.UNKNOWN_ERR,未知错误 • SQLError.DATABASE_ERR,数据库错误 • SQLError.VERSION_ERR,版本错误 • SQLError.TOO_LARGE_ERR,超⼤大 • SQLError.QUOTA_ERR,超限 • SQLError.SYNTAX_ERR,语法错误 • SQLError.CONSTRAIN_ERR,限制错误 • SQLError.TIMEOUT_ERR,超时错误
  • 182. 标准现状 W3C Web SQL Database Still valid! Web Storage
  • 183. 扩展阅读 • PersistenceJS - persistencejs.org • lawnchair - http://brian.io/lawnchair/ • DOM Storage - https://developer.mozilla.org/en-US/ docs/DOM/Storage