この翻訳は不完全です。英語から この記事を翻訳 してください。
この文書は初心者向けの Firefox OS アプリチュートリアルです。Web 開発者とモバイルアプリ開発者に向けて、Firefox OS アプリの作成方法と、一般の Web サイトや Web アプリとの違いを解説しています。
Firefox OS のアプリは一般的な Web サイトや、Web アプリと本質的な違いはありません。HTML や CSS、JavaScript といったオープンな Web 標準技術で作成され、Web ブラウザによって実行されます。端末にインストールされオフラインでも実行される点、カメラやジャイロ、アドレス帳のような端末の持つ機能にアクセスするための API を利用できる点、そして無料および有料でアプリを配布するための Marketplace を含む開発者のための強固なエコシステムが用意されている点が異なります。オープンでクロスプラットフォームで動作する技術を利用して作成される一方、Firefox OS アプリはユーザにアプリ体験を提供します。
Firefox OS アプリは開発の敷居が低いことが特長です。特に Web 開発者や、モバイル開発者は開発を簡単に始められます。ネイティブアプリと比べて、プラットフォーム間での移植が簡単で、取りこめられていないことが特長です。
Firefox OS
Firefox OS (コードネームである Boot to Gecko や B2G と呼ばれることもあります) は Mozilla のオープンソースモバイル OS です。Linux カーネルが Gecko ベースのランタイムを起動し、そのランタイム上に オープン Web アプリをインストールし実行します。Gecko は Firefox ブラウザがコンテンツを描画するために利用するレンダリングエンジンです。
Firefox OS には Gaia と呼ばれるプリインストールアプリが含まれます。電話、設定、SMS、写真撮影といった電話の機能は Gaia として実現されています。
必要なスキル
上記のように Firefox OS のアプリは HTML、CSS、JavaScript といった Web 技術によって作成されています。そのため Web ページを作成したことがあれば、アプリ作成のための基本的スキルをすでにお持ちです。Web ページを作成した経験のない方でも、この文書を読めば基本を抑えることが可能です。またオープンな Web 技術を利用した開発についてより詳しく学ぶには 初心者向けチュートリアル をご覧ください
必要なツール
Firefox OS のアプリはシンプルでフリーなツールを使って作成できます。ご自身が慣れたツールを使っていただいても良いですし、次のツールを使っていただいてもよいでしょう:
- Sublime Text (無料で体験版を利用できます), Gedit (フリー), Notepad++ (フリー), Atom (フリー) or Brackets (フリー。このツール自身も HTML、CSS、JavaScript で作成されています)のようなシンプルなテキストエディタ。もしくは Eclipse (フリー)、 Netbeans (フリー)、 Dreamweaver のような IDE も利用できます。
- テストをするために利用する、Firefox のようなモダンブラウザ。Firefox には標準で搭載されているデバッグツールや、アプリマネージャが搭載されています。
作成したアプリを Firefox OS 端末で動作させたい場合は、開発者向け端末を利用するか、Nexus のような端末に Firefox OS をビルドしインストールすることになります。
最初のアプリ
この節では端末にインストールできるアプリの作成方法を解説し、アプリ作成の基礎を学ぶのがいかに簡単なのかを示します。ここでの説明には GitHub で公開されている quickstart starter template を利用します。こちらより zip 形式でダウンロードできます。
Quickstart app starter template
これから作成するものは、極めてシンプルなアプリです。Battery Status API を利用して、バッテリーの残量と充電中か否かを調査し、バイブレーション (Vibration API を利用) とシステム通知 (Notification API を利用) で状態を通知します。
テンプレートは以下の構造をしています:
- battery-quickstart-starter-template/
- index.html
- images/
- battery.svg
- icon-128.png
- icon-512.png
- scripts/
- battery.js
- install.js
- style/
- style.css
- .htaccess
- README.md
index.html
: アプリで表示するコンテンツや入力をもつドファイルです。images
:アプリの UI で利用されるアイコンと、Firefox Marketplace での公開時に利用されるアプリのアイコン、インストール時に表示されるアイコンがあるフォルダです。アイコンについては Icon implementation for apps ガイドをご覧ください。scripts
: Will contain the JavaScript code that defines the functionality of the app; currently there are two blank files —battery.js
andinstall.js
.style
: contains a stylesheet,style.css
, to provide the app with basic styling..htaccess
: A server config file that informs web servers of the mime type of the manifest file we are adding in the next section. This makes sure that servers don't throw an error if they don't recognise the manifest file type (which some might.)README.md
: Markdown-based readme file that Github uses to explain what this repo is all about.
Adding a manifest
Every open web app requires a manifest.webapp
file to be placed in the app's root folder: This provides important information about the app, such as version, name, description, icon location, locale strings, domains the app can be installed from, and much more.
Add the following into a new plain text file in your app's root. Name the file manifest.webapp
.
{ "name": "Battery", "description": "Battery provides a good template for an in-app battery/charge indicator with different visualization choices, plus ideas of what could be changed once battery level gets low.", "launch_path": "/index.html", "icons": { "128": "/images/icon-128.png", "512": "/images/icon-512.png" }, "developer": { "name": "Chris Mills", "url": "https://www.conquestofsteel.co.uk" }, "permissions": { "desktop-notification": { "description": "Needed for creating system notifications." } } }
Note: For more information on exactly what is going on here, consult our App Manifests reference.
Note: paths in manifest files should be relative to the origin of the server location. So for example, if my example's root is at https://www.mysite.com/myapp/
, and my icon is at https://www.mysite.com/myapp/myicon/icon.png
, the icon path would be /myapp/myicon/icon.png
, not
./myicon/icon.png
API permissions
There are a number of WebAPIs available that require permissions for that specific feature to be enabled. Installed apps have to register permission requests within the manifest.webapp
file as seen in the "permissions" field above, which requests permission to use the system notifications controlled by the Notification API.
Different APIs require different levels of permission to access them. The three levels of permission are as follows:
- Normal — APIs that don't need any kind of special access permissions.
- Privileged — APIs available to developers to use in their applications, as long as they set access permissions in the app manifest files, and distribute them through a trusted source.
- Certified — APIs that control critical functions on a device, such as the call dialer and messaging services. These are generally not available for third party developers to use.
Note: For more information on what APIs require what permissions, read App permissions.
Web API functionality
JavaScript APIs are being created and enhanced as quickly as devices are. Mozilla's WebAPI effort brings dozens of standard mobile features to JavaScript APIs.
Detecting support for features
One technique employed commonly in web development is JavaScript feature detection — it involves running code to make sure a feature is supported by the browser before you actually try to use that feature. If it doesn't, you can provide some kind of fallback experience. The following snippet provides a quick example (this doesn't need to be added into your example code):
// Let's check if the browser supports notifications if (!("Notification" in window)) { console.log("This browser does not support notifications."); }
Our code for the quickstart example functionality
Inside the scripts/battery.js
file, add the following code blocks one after the other, reading the code comments carefully as you go. First, we'll set up all the variables we need:
// fork the navigator.battery object depending on what prefix the viewing browser uses var battery = navigator.battery || navigator.mozBattery || navigator.webkitBattery; // grab the elements we need, and put them in variables var indicator1 = document.getElementById('indicator1'); var indicator2 = document.getElementById('indicator2'); var batteryCharge = document.getElementById('battery-charge'); var batteryTop = document.getElementById('battery-top'); var chargeIcon = document.getElementById('battery-charging'); // Flag to check if battery charged/not charged has already been notified once // 0 for first time of notification, // 1 means "charged" has already been notified, // 2 means "not charged" has already been notified // This is set to the opposite after each notification, so that you don't keep // getting repeat notifications about the same charge state. var chargingState = 0;
Next, we'll add the main updateBatteryStatus()
function, which is responsible for updating the displayed information about the battery's status whenever a battery-related event is fired:
function updateBatteryStatus() { // battery.level can be used to give us a percentage of bettery charge to report to // the app's user var percentage = Math.round(battery.level * 100); indicator1.innerHTML = "Battery charge at " + percentage + "%"; batteryCharge.style.width = percentage + '%'; if(percentage >= 99) { // report that the battery is fully charged, more or less ;-) batteryTop.style.backgroundColor = 'limegreen'; batteryCharge.style.backgroundColor = 'limegreen'; createNotification("Device battery fully charged."); } if(battery.charging) { // If the battery is charging if(chargingState == 1 || chargingState == 0) { // and if our chargingState flag is equal to 0 or 1 // alter the styling to show the battery charging batteryTop.style.backgroundColor = 'gold'; batteryCharge.style.backgroundColor = 'gold'; indicator2.innerHTML = "Battery is charging"; chargeIcon.style.visibility = 'visible'; // notify the user with a custom notification createNotification("Device battery now charging."); // flip the chargingState flag to 2 chargingState = 2; } } else if(!battery.charging) { // If the battery is NOT charging if(chargingState == 2 || chargingState == 0) { // and if our chargingState flag is equal to 0 or 2 // alter the styling to show the battery NOT charging batteryTop.style.backgroundColor = 'yellow'; batteryCharge.style.backgroundColor = 'yellow'; indicator2.innerHTML = "Battery not charging"; chargeIcon.style.visibility = 'hidden'; // notify the user with a custom notification createNotification("Device battery is not charging."); // flip the chargingState flag to 1 chargingState = 1; } } }
Now it's time to add in the createNotification()
function referenced above. When this is called, a system notification is fired containing the message passed in as its argument. This code seems a bit long-winded, but here we are both detecting support for Notifications, and handling bulletproof support for both Firefox and Chromium/Blink-based browsers.
function createNotification(message) { // Let's check if the browser supports notifications if (!("Notification" in window)) { console.log("This browser does not support notifications."); } // Let's check if the user is okay to get some notification else if (Notification.permission === "granted") { // If it's okay let's create a notification // show the notification var notification = new Notification('Battery status', { body: message }); // And vibrate the device if it supports vibration API window.navigator.vibrate(500); } // Otherwise, we need to ask the user for permission // Note, Chrome does not implement the permission static property // So we have to check for NOT 'denied' instead of 'default' else if (Notification.permission !== 'denied') { Notification.requestPermission(function (permission) { // Whatever the user answers, we make sure Chrome stores the information if(!('permission' in Notification)) { Notification.permission = permission; } // If the user is okay, let's create a notification if (permission === "granted") { // show the notification var notification = new Notification('Battery status', { body: message }); // And vibrate the device if it supports vibration API window.navigator.vibrate(500); } }); } }
Finally, we'll add event handlers to the battery
object to let us respond to changes in the battery's charging state and charge level (by running the updateBatteryStatus()
function), and then run updateBatteryStatus()
once to get the show started:
// Event handler to check whether the battery has started charging or stopped charging battery.addEventListener("chargingchange", updateBatteryStatus, false); // Event handler to check whether the battery charge level has changed battery.addEventListener("levelchange", updateBatteryStatus, false); // run the central function once when the app is first loaded updateBatteryStatus();
The comments should explain what the code does well enough, but the take home message is that it is easy to use hardware data and functionality via such APIs, with simple events and objects like chargingchange
, battery
, and Notification()
.
The JavaScript is watching for when the battery charge level changes, or when the battery stops or starts charging (the chargingchange
and levelchange
event listeners.) When one of these events happens, the updateBatteryStatus()
function is run, which decides what notification to tell the user, updates the visual display to suit, and runs createNotification()
.
This final function actually fires the system notification and makes the phone vibrate to give the user some extra system-wide feedback as to what the battery status is.
Note: Check the WebAPI page frequently to keep up to date with device API statuses.
Install API functionality
In our sample app template, we've implemented an install button that you can click when viewing the app as a standard Web page, to install that site on Firefox OS as an app. The button markup is nothing special:
<button id="install">Install app on device</button>
This button's functionality will be implemented using the Install API. Add the following into your example's scripts/install.js
file:
// get a reference to the install button var button = document.getElementById('install'); // if browser has support for installable apps, run the install code; it not, hide the install button if('mozApps' in navigator) { // define the manifest URL var manifest_url = location.href + 'manifest.webapp'; function install(ev) { ev.preventDefault(); // install the app var installLocFind = navigator.mozApps.install(manifest_url); installLocFind.onsuccess = function(data) { // App is installed, do something if you like }; installLocFind.onerror = function() { // App wasn't installed, info is in // installapp.error.name alert(installLocFind.error.name); }; }; // if app is already installed, hide button. If not, add event listener to call install() on click var installCheck = navigator.mozApps.checkInstalled(manifest_url); installCheck.onsuccess = function() { if(installCheck.result) { button.style.display = "none"; } else { button.addEventListener('click', install, false); }; }; } else { button.style.display = "none"; }
Again, the comments explain what's going on quite nicely, but in brief, we first check whether the mozApps object exists in the browser (if('mozApps' in navigator)
) — i.e. if the browser supports installable apps or not. If not, we just hide the install button.
Next, navigator.mozApps.checkInstalled
checks whether the app defined by the manifest at manifest_url
is already installed on the device. If the test returns a success, its success event is fired and the installCheck.onsuccess = function() { ... }
is run.
We then test for the existence of installCheck.result
; if it does exist, meaning that the app is installed, we hide the install button. If the app isn't installed, we add a click
event listener to the button, so the install()
function is run when the button is clicked.
When the button is clicked and the install()
function is run, we install the app using navigator.mozApps.install(manifest_url)
, storing a reference to that installation in the installLocFind
variable. You'll notice that this installation also fires success
and error
events, so you can run actions dependent on whether the install happened successfully or not.
Note: Installable open web apps used to have a "single app per origin" security policy, but this was lifted as of Firefox 34/Firefox OS 2.1 (read this FAQ entry for more information). If you still need to support older versions, consider hosting your apps at separate origins; one strategy is to create different subdomains for your apps.
Testing your app
At this point, your app should be finished, and you can start testing it in browsers. If the app does not seem to be working, you can find the finished source code to check against, or see the example running live. For example, it looks like this on a desktop computer:
Testing on Firefox desktop
The quickest way to test your app's basic functionality is to simply load it in Firefox desktop (open the index.html
file in the browser) — this supports most of the features we are talking about here. The notifications look like so on OS X:
And in Firefox Aurora/Nightly and Firefox for Android, you can test the install functionality — these browsers include the Firefox runtime that allows installable web apps to be installed on the desktop.
Testing in the Firefox OS simulator
You can also test the app in a Firefox OS simulator via our WebIDE tool. This will give you a more realistic idea of how it will look on a real device. In short, you need to:
- Open WebIDE (Tools > Web Developer > WebIDE)
- Install a simulator using Select Runtime > Install Simulator
- Open the simulator using Select Runtime > [name of simulator]
- Select Open App > Open packaged app then navigate to your app's local directory
- Click the "play" button to load it inside the Firefox OS Simulator
Testing on a Firefox OS device
The vibration API won't work on these options however. To fully test this you'll need to get hold of a real Firefox OS device. If you've got one, you can connect it to your computer and install apps contained on your local drive straight onto it via WebIDE. Here's a Firefox OS screenshot showing the app running, along with a system notification.
To install the app on your Firefox OS device via the App Manager:
- Open WebIDE (Tools > Web Developer > WebIDE)
- On your Firefox OS device, Select the ADB and Devtools option in the Remote Debugging developer setting
- Connect your phone to your desktop computer via USB
- Make sure you've got ADB installed on your computer, and that it is working (type the
adb devices
command into your terminal and see if it gives you an entry for your phone) - Click the option that represents your device inside the webIDE Select Runtime menu
- Inside WebIDE, select Open App > Open packaged app then navigate to your app's local directory
- Click the "play" button to install it on the Firefox OS Device