Web API 简介

以 Firefox OS 为例

尤睿, ryou@mozilla.com

演示使用说明

  • 请在最新版 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.

用途

  • 玩游戏: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: 自动静音

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});
  • 说明: 使用 watchPositionclearWatch 来 开启 / 关闭 追踪。
  • 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);

2D游戏

Electronic Arts: Lord of Ultima

WebGL

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

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

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);

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属性锁定方向。

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》

谢谢!