[Firefox OS][FxOS]toast的なものを出すコード

丸山です。

Firefox OS勉強会でちらほらお話させて頂いてますが、
Firefox OSでtoastっぽいものを表示するコードについて、
改めて記載します。
(スライド記載分のみでは見にくいかと思いますので)

htmlファイル

<head>
<link rel="stylesheet" type="text/css" href="res/status.css">
</head>
<section role="status" id="toast" hidden>
	<p><progress></progress>  Connectiong<BR>      Server...</p>
</section>

上記で使用している「status.css」は以下よりダウンロードしてください。
http://buildingfirefoxos.com/building-blocks/status.html

jsファイル

function toastManager() {
}

toastManager.prototype = {
/**
 * 4秒後にToastを消す
 */
scheduleToast : function() {
	window.setTimeout(function() {
		document.getElementById("toast").hidden = true;
	}, 4000);
},

/**
 * closeするまで表示しっぱなし
 * (サーバ処理中などに使用)
 */
showToast : function() {
	document.getElementById("toast").hidden = false;
},

/**
 * 4秒後に消えるToastを表示
 */
showToastSchedule : function() {
	document.getElementById("toast").hidden = false;
	toastManager.prototype.scheduleToast();
},

/**
 * Toastの消去
 */
closeToast : function() {
	document.getElementById("toast").hidden = true;
},

/**
 * Toast内の文章を変更
 */
changeToastMessage : function(string) {
	var toast = document.getElementById("toast");
	while(toast.firstChild){toast.removeChild(toast.firstChild);}
	var text = document.createElement("p");
	text.innerHTML = string;
	toast.appendChild(text);
}
}

なお、発表に使用したスライドのURLは以下です。

[Firefox OS][FxOS] Firefox OS Simulator 4.0使ってみた

FirefoxOS Simulatorの4.0がリリースされていたので使用してみました。
レイアウトが変更されているようで、
左側にあった「Console」チェックボックスがありません。

ログ出力等の確認を行う場合は、
アプリごとのボタンとして用意されている「Connect」ボタンを押下して
Webコンソールで確認を行うようになっています。
(今までは別窓が立ち上がってました)

また、「Connect」ボタンの隣にある
「Refresh」ボタンを使うことで、アプリの再インストールができるようです。

総合的に見て使い勝手が上がっているように感じました。
まだバージョンアップしていない方はしておくことをお勧めします。

 

20130719_ScreenShot_001

 

[Firefox OS][FxOS]サーバアクセスについて

Firefox OSでアプリを作る際、
サーバアクセスを行いたい場合も出てきます。

JavaScriptでサーバアクセスを行うならば、
XMLHttpRequestを使うのが簡単かと思われます。

但し、XMLHttpRequestをFirefox OSで用いる場合には
2点ほど注意があります。

1.webappファイルのpermissionsに追加が必要
2.インスタンス生成時に引数を与えてやる必要がある

具体的には、
1.

"type": "privileged",
"permissions": {
 "systemXHR": {
 "description": "xhr"
 }
}

をwebappファイルに追加する

2.

var req = new XMLHttpRequest({mozSystem: true});

と書く(引数を空にしない)

上記を怠った場合、
レスポンスのステータスは0となります
(正常ならば200)

以下サイト様を参考にさせて頂きました。
http://hirooka.pro/?p=1724

[FirefoxOS][FxOS]UI作成

FxOSでは、アプリのUIについてもhtml+JavaScriptで作成できます。
自力でcss等駆使して任意のUIを作成することもできますが、
簡単に作成するなら以下のサイトが参考になります。

http://buildingfirefoxos.com/building-blocks/confirm/

サイト内にcssとコード例が用意されておりますので、
cssをダウンロードして変更を加えればUIが作成できます。
(勿論そのまま使うこともできます)

例えば以下のような手順です。
1. サイトよりcssダウンロード
2. webapp, html, ダウンロードしたcssをフォルダに纏める
3. サイト内を参考に、フォルダ内の構成を反映してhtmlファイルを編集する
4. FirefoxOSSimulatorでwebappファイルを読み込み、試す

[Firefox OS][FxOS] API使用手続きについて

FirefoxOSでは、アプリをHTML+JavaScriptで作成できます。
その際、JavaScriptから、
FirefoxOS上に用意されたAPIを使用できます。
今回はFirefoxOS上でAPIを使用するための手続きについて述べます。

1. webappファイル

FirefoxOSから、アプリとして認識させる為、webappファイルを作成する必要があります。
ここへの記載内容に応じて、アプリ内で使用できるAPIも変化します。
以下では、使用APIに関連するパラメータと、webappファイルへの記載方法について記載します。

1-1.type

  "type": "certified",

typeには、以下の種類があります。
web:通常のアプリ。最低限のWebAPIのみ。
privileged:特権アプリ。審査を経て承認される。
certified:通話やシステム設定等のシステム機能を備えたアプリ。

web < privileged < certified
の順番で、使用できるAPIは増えていきます。
尚、type指定を行わなかった場合、”web”typeとして扱われます。

1-2.premissions

  "permissions": {
    "mobileconnection":{},
    "wifi-manage":{},
    "geolocation" : {},
    "desktop-notification": {},
    "systemXHR": {
      "description": "xhr"
    },

privileged以上の権限レベルに属するAPIには、
permissionの設定が必要となります。
それぞれのAPI毎に設定項目は異なります。
項目毎の詳細については以下を参照してください。
https://developer.mozilla.org/ja/docs/Web/Apps/App_permissions

2. jsファイル

webappファイルへの記載が正常であれば、
特に設定等必要なく、
javaScript内で該当APIを使用できます。

※実行時にエラーコンソール内で「TypeError: *** is undefined.」と表示されている場合、
1の設定を誤っている可能性があります。
但し、Firefox OS Simulatorでは、これら設定を行っていても一部のAPIは動作しないようです。

[Firefox OS Simulator3.0.1で動作しないAPI]

bluetooth
wifiManager
mozMobileConnection

[Firefox OS][B2G][FxOS] gecko層への機能拡張について

Firefox OSとは、スマートフォンとタブレットで動作するオープンソースOSです。
簡単に説明致しますと、以下のような構成となっております。

レイヤー名 主な機能 主な使用言語
Gaia アプリ, UI HTML, JavaScript
Gecko ランタイム JavaScript, C++
Gonk OS, HAL C++

アプリ層の開発に関しては検索をかければ幾つかヒットします。
そこでこの記事では、ランタイム層に関して新たに機能を実装し、
確認を行う手順について記載します。

大まかな手順
以下の手順に関して、順を追って説明してゆきます。
・環境準備
・Gecko層へソースファイル実装
・Gaia層へソースファイル実装
・動作確認

環境準備
アプリのみを作成する場合は必要ありませんが、
ライブラリや実行環境に手を加える場合、
ソースファイルを取得し、変更を加える必要があります。
環境構築及び取得方法は以下のサイトに詳しく記載されているので参照してください。
https://developer.mozilla.org/ja/docs/Mozilla/Boot_to_Gecko/Building_and_installing_Firefox_OS

Gecko層へソースファイル実装
デバイス等に依存しない、webでの動作のみのアプリを作る場合であれば、
Gecko層への実装は必要ありません。
また、元々FirefoxOS上で準備されているWebAPIを使用してアプリを作る場合についても、Gecko層への実装は必要ありません。
Gecko層に対して新たな機能を実装し、アプリ層から呼び出したい場合に、
以下の手順を踏む必要があります。
以下では例として、足し算をして結果を返すプログラムを作成します。

1.必要ファイル
以下のファイルを新規作成/修正する必要があります。
[新規作成ファイル]
・/gecko/dom/myCalc
・/gecko/dom/myCalc/Makefile.in
・/gecko/dom/myCalc/MyCalcManager.js
・/gecko/dom/myCalc/MyCalcManager.manifest
・/gecko/dom/myCalc/nsIDOMMyCalcManager.idl

[修正ファイル]
・/gecko/dom/Makefile.in
・/gecko/dom/dom-config.mk
・/gecko/b2g/installer/package-manifest.in

/gecko/dom/myCalc/Makefile.in

DEPTH       = @DEPTH@
topsrcdir   = @top_srcdir@
srcdir      = @srcdir@
VPATH       = @srcdir@

include $(DEPTH)/config/autoconf.mk

MODULE              = dom
XPIDL_MODULE        = dom_mycalc
LIBRARY_NAME        = dommycalc_s
LIBXUL_LIBRARY      = 1
FORCE_STATIC_LIB    = 1
GRE_MODULE          = 1
FAIL_ON_WARNINGS := 1

include $(topsrcdir)/dom/dom-config.mk

EXPORTS_NAMESPACES = mozilla/dom/mycalc

EXTRA_COMPONENTS =       \
  MyCalcManager.js       \
  MyCalcManager.manifest \
  $(NULL)

EXTRA_JS_MODULES = \
  $(NULL)

XPIDLSRCS =               \
  nsIDOMMyCalcManager.idl \
  $(NULL)

EXPORTS_mozilla/dom/mycalc = \
  $(NULL)

CPPSRCS =             \
  $(NULL)

include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk

XPIDL_FLAGS += \
  -I$(topsrcdir)/dom/interfaces/base \
  $(NULL)

/gecko/dom/myCalc/MyCalcManager.js

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* static functions */
const DEBUG = true;

function debug(aStr) {
  if (DEBUG)
    dump("MyCalcManager: " + aStr + "\n");
}

const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
Cu.import("resource://gre/modules/ObjectWrapper.jsm");

const MYCALCMANAGER_CONTRACTID = "@mozilla.org/MyCalcManager;1";
const MYCALCMANAGER_CID        = Components.ID("{682f9ea0-8a24-11e2-9f07-000c2921e8d6}");
const nsIDOMMozMyCalcManager   = Ci.nsIDOMMozMyCalcManager;
const nsIClassInfo             = Ci.nsIClassInfo;

function MyCalcManager()
{
  debug("Constructor");
}

MyCalcManager.prototype = {

  __proto__: DOMRequestIpcHelper.prototype,

  classID : MYCALCMANAGER_CID,

  QueryInterface : XPCOMUtils.generateQI([nsIDOMMozMyCalcManager, Ci.nsIDOMGlobalPropertyInitializer]),

  classInfo : XPCOMUtils.generateCI({ classID: MYCALCMANAGER_CID,
                                      contractID: MYCALCMANAGER_CONTRACTID,
                                      classDescription: "MyCalcManager",
                                      interfaces: [nsIDOMMozMyCalcManager],
                                      flags: nsIClassInfo.DOM_OBJECT }),

  add: function add(a, b) {
    debug("add()");
    debug(a);
    debug(b);
    return a + b;
  },

  receiveMessage: function receiveMessage(aMessage) {
    debug("receiveMessage(): " + aMessage.name);

    let json = aMessage.json;
    let request = this.getRequest(json.requestId);

    if (!request) {
      debug("No request stored! " + json.requestId);
      return;
    }

    switch (aMessage.name) {
      case "MyCalcManager:Add:Return:OK":
        Services.DOMRequest.fireSuccess(request, json.id);
        break;
      default:
        debug("Wrong message: " + aMessage.name);
        break;
    }
    this.removeRequest(json.requestId);
   },

  // nsIDOMGlobalPropertyInitializer implementation
  init: function init(aWindow) {
    debug("init()");

    // Set navigator.mozAlarms to null.
//    if (!Services.prefs.getBoolPref("dom.mozmycalc.enabled"))
//      return null;

    this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);

    // Add the valid messages to be listened.
    this.initHelper(aWindow, ["MyCalcManager:Add:Return:OK"]);

    // Get the manifest URL if this is an installed app
    let appsService = Cc["@mozilla.org/AppsService;1"]
                        .getService(Ci.nsIAppsService);
 //   this._pageURL = principal.URI.spec;
 //   this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
    this._window = aWindow;
  },

  // Called from DOMRequestIpcHelper.
  uninit: function uninit() {
    debug("uninit()");
  },
}

this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MyCalcManager])

/gecko/dom/myCalc/MyCalcManager.manifest

component {682f9ea0-8a24-11e2-9f07-000c2921e8d6} MyCalcManager.js
contract @mozilla.org/MyCalcManager;1 {682f9ea0-8a24-11e2-9f07-000c2921e8d6}
category JavaScript-navigator-property mozMyCalc @mozilla.org/MyCalcManager;1

/gecko/dom/myCalc/nsIDOMMyCalcManager.idl

#include "domstubs.idl"

interface nsIDOMDOMRequest;

[scriptable, uuid(682f9ea0-8a24-11e2-9f07-000c2921e8d6)]
interface nsIDOMMozmyCalc : nsISupports
{
  nsIDOMDOMRequest add(in jsval a, in jsval b);
};

/gecko/dom/Makefile.in

PARALLEL_DIRS += \
  apps \
  base \
・
・
  alarm \
  mycalc \		←追加
  devicestorage \

/gecko/dom/dom-config.mk

DOM_SRCDIRS = \
  dom/base \
  dom/battery \
・
・
  dom/alarm \
  dom/mycalc \		←追加
  dom/src/events \

/gecko/b2g/installer/package-manifest.in

@BINPATH@/components/dom_contacts.xpt
@BINPATH@/components/dom_alarm.xpt
@BINPATH@/components/dom_mycalc.xpt			←追加
@BINPATH@/components/dom_core.xpt
@BINPATH@/components/dom_css.xpt
・
・
・
@BINPATH@/components/AlarmsManager.js
@BINPATH@/components/AlarmsManager.manifest
@BINPATH@/components/MyCalcManager.js
@BINPATH@/components/MyCalcManager.manifest		←追加
@BINPATH@/components/FeedProcessor.manifest		←追加
@BINPATH@/components/FeedProcessor.js

上記で使用したuuid(682f9ea0-8a24-11e2-9f07-000c2921e8d6)については、
固有の英数字を割り振る必要があります。
ターミナルで以下のコマンドを実行し、固有の英数字を取得し、使用してください。

uuidgen

2.ビルド確認
環境を展開したフォルダ(任意/b2g/)に移動し、
ターミナルから以下のコマンドを実行します。

./build.sh

ビルド完了まで待ち、エラーメッセージが出力されていなければ、
コンパイルできたことになります。
次に、動作確認のため、実装したGecko層機能を呼び出すアプリを作成します。

Gaia層へソースファイル実装
1.必要ファイル
以下のファイルを新規作成/ダウンロードする必要があります。

[新規作成ファイル]
・/gaia/apps/testcalc_api/index.html
・/gaia/apps/testcalc_api/manifest.webapps
・/gaia/apps/testcalc_api/js/test.js

[ダウンロードファイル]
・/gaia/apps/testcalc_api/js/lib/zepto.min.js

下記アドレスからzept.min.jsをダウンロードし、上記パスに格納して下さい。
http://zeptojs.com/

/gaia/apps/testcalc_api/index.html

<HTML>
<HEAD><meta charset="UTF-8"><TITLE>test add</TITLE></HEAD>
<script type="text/javascript" src="/js/lib/zepto.min.js"></script>
<SCRIPT type="application/javascript" src="js/testcalc.js">
</SCRIPT>
</HTML>

/gaia/apps/testcalc_api/manifest.webapps

{
  "name": "Test firefox api",
  "description": "test program",
  "launch_path": "/index.html",
  "developer": {
    "name": "FirefoxOS_tester",
    "url": "http://"
  },
  "icons": {
    "128": "/style/icons/test.png"
  }
}

/gaia/apps/testcalc_api/js/test.js

a = Math.round(Math.random()*10);
b = Math.round(Math.random()*10);
document.write(a);
document.write("
");
document.write(b);
document.write("
");
console.log("myCalcAdd start");
var myCalc = navigator.mozMyCalc;
var c = myCalc.add(a, b);
document.write(c);
document.write("
[end]");

2.ビルド確認
環境を展開したフォルダ(任意/b2g/)に移動し、
ターミナルから以下のコマンドを実行します。

./build.sh

ビルド完了まで待ち、エラーメッセージが出力されていなければ、
コンパイルできたことになります。
最後に動作確認を行い、想定した結果が出力されれば成功です。

動作確認
上記gecko, gaiaへの実装が完了したことを確認後、
環境を展開したフォルダ(任意/b2g/)に移動し、
以下のコマンドを実行します。

./run-emulator.sh

以下のような表示が出ていれば、正常に動作できています。
※但し、1行目、2行目の数字に関してはランダムです。3行目の数字について、1行目と2行目が足された値になっていればOKです。

4
9
13
[end]