## Web API 简介

### 以 Firefox OS 为例

尤睿, ryou@mozilla.com

* 以 Firefox OS 为例，侧重介绍能在 Firefox OS 上运行的 * 但不代表 Web API 只能在 Firefox OS 上运行 * 讲的时候不光要讲怎么用，还要讲这个 API 有什么用，在哪些场合能用 * 演示是在nightly中进行的，演讲前要提一下这一点，并且要用gaia作为profile，这样可以方便地演示app在手机上的运行效果（当然传感器很难演示了）

## 演示使用说明

- 请在最新版 Firefox Nightly 中打开本页面
- 快捷键：`h`, `j`, `k`, `l`, `0`, `$`, `Space`, `Shift+Space`, `PageDown`, `PageUp`, `Home`, `End`, `Esc`
- https://github.com/hakimel/reveal.js
- http://mca.testno.de/slides

## Web API

- 生态系统: 大量的 Web 开发者，丰富的框架 / 资源 / 文档
- 优势: 学习成本 / 开发成本 / 迁移成本 / 维护成本
- 前端技术: html, css, javascript
- 跨平台: Web API 与 原生 API
- 标准化: Web API 与 专有 API
- 应用形式: Web Page 与 Web App

The Web is the platform.

* 跨平台的意思是使用前端技术，可以运行在不同的操作系统上。这里提一下几个桌面系统，几个移动系统，以表示系统之多，学习每一个平台的成本和跨平台的重要性。 * 标准化的意思是将API提交到w3c讨论形成Web API标准，而不能像Web OS那样只能在自家的设备上使用 * 前端技术的好处之一是对页面的标准定义，将UI与内容的描述方式统一。css将内容与样式分离，js非常适合处理交互逻辑。 * 最大的好处是人多, Mozilla Engineer VP Johnathan Nightingale 2013: There's a 200,000 iOS developers, 600,000 Android developers and there's 8 million web developers out there. If you're not betting on HTML 5, you're making a mistake. 数据可能有疑问，但加起来十倍这个可以毫无疑问地说（想想Web那么久的历史） * 对API的要求：第一是稳定，不要老变，不要被废弃；第二是易用，不要看完文档和示例还整不明白；第三是跨平台，不用每加一个设备/系统就要重新学习一套API The Web is the platform. 暗含的是: Not Mozilla, not the firefox, but the web. 这里可以突出Mozilla与其他公司的不同，即其非盈利性和以Web为使命。 以后添加下不同操作系统的图标，桌面一排，移动一排，可以只弄主要的，也可以弄全点 different platforms: Browser, Web App/Desktop OS, Mobile OS, Web OS 可以大概说一下对Web的质疑：标准推进，平台支持(moz-, webkit-, ms-)，功能不够全面，性能不够强大，并针对性地回应这些质疑。但这不是重点，不用展开讲。

### 用途

- 玩游戏：Canvas, WebGL, FullScreen
- 图像处理：Canvas
- 视频聊天： WebRTC
- 录像录音： WebRTC
- 看视频：Video
- 听音乐：Audio
- 地理定位：Geolocation
- 打电话：Contact, Telephony
- 发短信：Contact, SMS

More Web APIs are coming ...

## 体验交互类

更好的用户体验，更流畅的人机交互

- Page Visibility
- Fullscreen
- Geolocation

## Page Visibility

检测页面可见性

    document.addEventListener('visibilitychange', function() {
      if (document.hidden) {
        myVideo.pause();
      } else {
        myVideo.play();
      }
    }, false);

- 用途: 避免不必要的绘制、计算与播放。用于动画、游戏、视频、音频等。
- 说明: `requestAnimationFrame` 会自动停止。Audio 和 Video 不会。
- Demo: 自动静音

* 动画停止播放，音乐停止播放，游戏暂停，显示的相关东西可以不再耗资源 * 与此相反，后台计算的部分则可以利用这个时间进行一些密集运算 * 切换 tab 和最小化窗口会导致可见性变化，被其他窗口覆盖则不会 * 曲子是巴赫的《G弦上的咏叹调》，可以提一下 * 这里可以提一下Audio，后面要讲到 * 从这个API开始，下面的基本尽量在Firebug中试下，Demo也右键查看下页面源码

## Fullscreen

全屏显示页面或某个元素

    // detect whether Fullscreen mode is supported
    if (document.mozFullScreenEnabled) {
        // Fullscreen on whole document
        document.body.mozRequestFullScreen();
        // Fullscreen on one element
        document.getElementById('fullscreen-code').mozRequestFullScreen();
    }

- 说明: 需要添加 `moz` 前缀，需要获取用户同意。
- Tip 1: 使用 `document.fullScreenElement` 来检测全屏状态，获取全屏元素。
- Tip 2: 在 CSS 和 Events 里使用 pseudo tag (`:fullscreen`, `:-moz-full-screen`) 来设置针对全屏模式的样式。
- 用途: 在游戏、视频中获得沉浸式体验。

## Geolocation

追踪用户的位置和运动

    navigator.geolocation.getCurrentPosition(function(position) {
        var coords = position.coords;
        // decimal degrees
        console.log(coords.latitude + ", " + coords.longitude);
        console.log(coords.altitude + "meters");
    }, function(error) {
        if (error.code == 1) {
            console.log("Permission denied");
        } else {
            console.log(error.code);
        }
    }, {maximumAge: 500});

- 说明: 使用 `watchPosition` 和 `clearWatch` 来 开启 / 关闭 追踪。
- Tip: 开启追踪容易耗尽电池。
- 用途: LBS

## 多媒体篇

音乐，摄影，摄像，电影，动漫，游戏……

- Canvas
- WebGL
- WebRTC
- Audio
- DeviceStorage

## Canvas

2D 像素级绘制，硬件加速支持

    var canvas = document.getElementById('rect');
    var context = canvas.getContext('2d');
    context.fillStyle = 'rgb(200,0,0)';
    context.fillRect (10, 10, 300, 300);
    context.fillStyle = 'rgba(0, 0, 200, 0.5)';
    context.fillRect (140, 140, 300, 300);

- 说明: 与 Video 等 API 可以很好地协同使用。
- Tip: 对于矢量图形绘制，SVG可能更为合适。
- Demo 1: 矩形的绘制与填充
- Demo 2: Happy Trails

* 以前像素级绘制需要 flash 来完成 * fillRect的后两个参数是长宽的意思，不是对角坐标

### 2D游戏

Electronic Arts: Lord of Ultima

## WebGL

OpenGL 的 Web 版本, canvas 的 3D 绘制环境

- Tip: 对 OpenGL 不熟悉的开发者可以尝试使用封装库
- Demo: CrystalSkull

* 以前在网页中运行 3D 需要 VML 或者 Plugin * 桌面端使用 OpenGL，移动端使用 GLES

### Banana Bread (Emscripten)

### HexGL (Three.js)

## Audio

加载、播放、合成音频数据

    // Load dynamically
    var audio = new Audio();
    audio.src = '../demos/visibility/johann_sebastian_bach_air.ogg';
    audio.addEventListener('MozAudioAvailable', function(event) {
      console.log(event.time + "s");
    }, false);
    audio.play();

- Tip: 在Firefox OS上和Android的Firefox浏览器上都支持`MP3`。

## WebRTC: getUserMedia

录制、处理音频流和视频流

    var video = document.getElementById('my-video');

    navigator.getUserMedia({'video': true}, function(mediaStream) {
      video.src = URL.createObjectURL(mediaStream);
      video.play();
    }, function(error) {
      console.error('Video capture error: ', error.code);
    });

    // Capture
    var ctx = myCanvas.getContext('2d');
    ctx.drawImage(video, 0, 0);

* Flash for webcam access - Record and mash up camera and audio

### Demo

## Device Storage

在预定义的目录中读写图片、音乐、视频等

    var name = "my-cat-with-80s-camera-filter.png",
      storage = navigator.getDeviceStorage("pictures"),
      request = storage.addNamed(myImageBlob, name);
    request.onsuccess = function() {
      console.log('%d saved', this.result.name);
      // storage.delete(name)
    };
    request.onerror = function() {
      console.log('Could not save picture, #' + this.result.code);
    };

## 性能篇

越来越接近原生应用

- Web Workers
- Typed Array
- asm.js

## Web Workers

在后台独立运行任务

    // my_task.js will run in its background threads
    var worker = new Worker('my_task.js');
    worker.addEventListener('message', function(event) {
      console.log('Worker send a message back: ' + event.data);
    }, false);

    // Start the worker.
    worker.postMessage(JSON.stringify(myWorkerData));

- 说明: 没有DOM API，不能访问页面元素。
- 用途: 图像处理，物理引擎等密集计算。

## Typed Arrays

高效操作二进制数据

    // a buffer with 16 bytes
    var buffer = new ArrayBuffer(16);
    // a view treating the data as 32-bit signed integers
    var int32View = new Int32Array(buffer);
    // Access the fields in the array just like a normal array
    for (var i=0; i < int32View.length; i++) {
      int32View[i] = i*2;
      console.log(int32View[i]);
    }

- 说明: 为读取和遍历优化，初始化会比普通 `Array` 慢。
- 用途: 服务于 WebGL 和 Audio, Video, WebSockets, Canvas，以及二进制数据处理。

### Structured Cloning & Transferable Objects

与 `Web Workers` 进行数据交换的高效方式

    worker.postMessage = worker.webkitPostMessage || worker.postMessage;

    var bigData = new ArrayBuffer(1);
    // // New argument: postMessage(message, targetOrigin, transferables);
    worker.postMessage({other: 'data', data: bigData}, [bigData]);
    if (bigData.byteLength) {
      console.error('Transferables are not supported in your browser!');
    } else {
      // Buffer got reset, transferables are supported.
    }

## asm.js

编译模式与静态类型

    function DiagModule(stdlib) {
        "use asm";
        var sqrt = stdlib.Math.sqrt;
        function square(x) {
            x = +x;
            return +(x*x);
        }
        function diag(x, y) {
            x = +x;
            y = +y;
            return +sqrt(square(x) + square(y));
        }
        return { diag: diag };
    }
    var fast = DiagModule(window);     // produces AOT-compiled version
    console.log(fast.diag(3, 4));      // 5

- 语言: 定义JavaScript的子集与静态类型系统
- 特性: 静态类型系统，预编译，模块化
- 性能: c语言编译至asm.js的benchmarks与clang编译结果在同一数量级

* 最好能找到那张性能对比的图

### 编译链接流程

- 说明: 通过类型检查与链接后，编译得到可执行的二进制，否则以解释模式运行

## 手机篇

手机特有功能

- Telephony
- SMS
- Vibration

## Telephony

拨出、接听电话

    // First, obtain a telephony object.
    var telephony = navigator.mozTelephony;
    // Check if the speaker is enabled or phone is muted.
    concole.log(telephony.speakerEnabled, telephony.muted);
    // Then, we dial out.
    var outgoing = telephony.dial(myPhoneNumber);
    // Event handlers for the call.
    outgoing.onconnected = function(event) {
      /* Do something when the callee picks up the call. */
    };
    outgoing.ondisconnected = function(event) {
      /* Do something when the call finishes. */
    };

### 黑名单的简单实现

    // Receive an incoming call.
    telephony.onincoming = function onincoming(event) {
      var incoming = event.call;
      if (incoming.number == myBlockedNumber) {
        // Hang up
        incoming.hangUp();
        return;
      }
      // Answer the call.
      incoming.answer();
    };

## SMS

发送、接受短信

    var request = navigator.mozSms.send(myNumber, "Hello World!");
    request.onsuccess = function() {
      var message = request.result;
      console.log(
        message.delivery, // 'sent' or 'received'
        message.read // boolean
      );
    }
    request.onerror = function(error) {
      console.error('Could not send message: ' + error);
    }

## Vibration

振动设备

    // Single vibration
    navigator.mozVibrate(200);
    // Pattern
    navigator.mozVibrate([200, 100, 200, 100, 400]);
    // Cancel existing vibrations
    navigator.mozVibrate(0);

## 传感器篇

获取环境情况与设备状态

- Battery
- Orientation & Motion
- Proximity
- Ambient Light

## Battery

获取、追踪电池状态和充电水平

    var battery = navigator.battery;
    console.log('Battery charging: ', battery.charging); // true
    console.log('Battery level: ', battery.level); // 0.58
    console.log('Battery discharging time: ', battery.dischargingTime);

    // Listen to change events
    battery.addEventListener('chargingchange', function(e) {
      console.warn('Battery charge change: ', battery.charging);
    }, false);

- 用途: 在游戏中提醒电池电量低，在做密集运算之前提醒用户插上充电器。

### 全平台适用

## Screen Orientation (& Lock)

获取、改变屏幕方向

    console.log(window.screen.mozOrientation);
    if (window.screen.mozLockOrientation('landscape-primary')) {
        console.log('orientation was locked');
    } else {
        console.log('lock failed');
    }

- 说明: 只在全屏状态下有效
- Tip: 在`manifest.webapp`中使用`orientation`属性锁定方向。

* Adapt to every screen format - Make it work for one (games!)

## DeviceOrientation & DeviceMotion

访问加速传感器、陀螺仪与指南针

    window.addEventListener('deviceorientation',function(event){
      // left-to-right tilt in degrees, where right is positive
      var tiltLR = event.gamma;
      // front-to-back tilt in degrees, where front is positive
      var tiltFB = event.beta;
      // compass direction the device is facing in degrees
      var dir = event.alpha

      // call our orientation event handler
      rotateMyStuff(tiltLR, tiltFB, dir);
    }, false);

- 用途: 在游戏中常需要确定设备精确方向。

## Proximity Sensor

检测设备屏幕是否被覆盖

    window.addEventListener('userproximity', function(event) {
      console.log(event.near ? 'Hello' : 'Come closer!');
    }, true);

- 用途: 在贴近脸部打电话时暂停程序，关闭屏幕。

## Ambient Light

检测设备附近的光线强度。

    window.addEventListener('devicelight', function(event) {
      console.log('SI lux', event.value);
    }, true);

- 用途: 自动调节亮度，切换夜间/白天模式。

## 参考资料

- https://wiki.mozilla.org/Webapi
- http://www.w3.org/standards/webdesign/script
- https://developer.mozilla.org
- https://developer.mozilla.org/en-US/demos/
- http://hexgl.bkcore.com/
- http://asmjs.org/
- https://github.com/digitarald/mozcamp-apps-dissected
- 《Pro HTML5》

## 谢谢！