Skip to content

PWAの根幹技術、Notifications APIの使い方

アプリでは当たり前になっているプッシュ通知ですが、Webブラウザ向けにはNotifications APIが用意されています。スマートフォンではまだ実装されていませんが、デスクトップ向けであれば十分使える状態になっています(Notifications APIはPush APIとは別です)。

今回はNotifications APIの実装方法を紹介します。

Notifications APIとPush APIの違い

Push APIはサーバからブラウザに対してプッシュ通知を送る仕組みで、Service Workerを利用します。Notifications APIはサーバサイドが不要で使えますが、Webブラウザがそのサイトを表示している時にしか使えません。

許可状態を知る

まず大事なのがユーザが通知を受け取ると許可しているかどうかです。それを調べるには Notification.permission を使います。値は3つあります。

  • default
    まだ許可を求めていません(初期値)
  • granted
    通知を許可しています
  • denied
    明確に拒否しています

そのため、deniedの時には処理を行わないというのが基本になるでしょう。

許可を得る

許可を得るのは Notification.requestPermission(); で行います。

grantedが得られれば許可を得た状態です。

通知を作成する

通知はこんな形で簡単に作成できます。

通知を閉じる

表示した通知を閉じる場合は、通知オブジェクトのcloseを使います。

通知のイベント

通知には幾つかのイベントが設定されています。

  • onclick

    通知をクリックした時に呼ばれます

  • onerror

    エラーが出た時に呼ばれます

  • onclose

    閉じた際に呼ばれます

  • onshow

    表示した時に呼ばれます

使いどころ

Notifications APIはWebページを表示している時にしか使えません。そのため、アプリのプッシュ通知のように使っていないユーザを呼び起こすのには向きません。むしろ時間がかかる処理でユーザを待たせてしまう時に完了をお知らせしたり、チャットなどで別ページを開いている時にお知らせすると言った使い方になるでしょう。

まとめ

WebSocketなどと組み合わせればサーバから通知を出したい時に命令を出すと言った使い方はできそうです。とは言え、基本的にはWebページ上で起きた変化をユーザに気付かせると言った目的で使うのが良さそうです。

JavaScriptの新しいAPI、ジェネレータの使い方

ES6で新しく追加されたJavaScript APIにジェネレータがあります。使い方次第で新しいJavaScriptの書き方が可能です。ES6 GeneratorはIE11を除くモダンなブラウザではサポートされていますので、ES6が利用できるのであれば使わない手はないでしょう。

ジェネレータの基本形

ジェネレータは function* という形で記述します。そしてyieldという形で値を返却します。このyieldが呼ばれる度にジェネレータの呼び出し元に値が送られます。

呼び出す際には関数を実行します。

さらに このジェネレータ(g)のnextメソッドを呼び出すとyieldと書かれた部分まで処理が進みます。返り値はオブジェクトで、valueキーに値が、doneキーにyieldが終了したかどうかが入ってきます。

nextメソッドではなく、for of を使うこともできます。この場合はvがvalueキーの内容になります。

オブジェクトを返せば複数の値を渡すこともできます。

nextを使う場合、yieldに対して引数を送ることができます。この値は yield の返り値として受け取れるものになります。

配列にeachWithIndexを実装する

例えば配列を順番に処理する場合、for を使います。

この毎回 value = ary[i] というのを書くのが面倒です。逆に for of を使った場合にはインデックスがないので不便な時もあります(回避する方法としてentriesを使う手もあります)。

そこでeachWithIndexメソッドを作って、インデックスも返ってくるイテレータを作ってみます。これはArrayのprototypeに作ります。

後はこのメソッドをfor ofの中で呼び出します。 eachWithIndex は関数であり、それを実行すると処理が開始されるので注意してください。

クラスにイテレーションを追加する

もし自作クラスにイテレーションを追加したい場合には、 Symbol.iterator を定義します。

これを実行します。

こちらはJSFiddleにデモを掲載しています。


イテレーションを使うことで、ループ処理であったり、段階を踏んで処理するようなところが書きやすくなります。JavaScriptはシングルスレッドで非同期処理が面倒ですが、イテレーションを使えば処理が完了してから次の処理に移動すると言ったことも書けるでしょう。

WebAssembly が書ける言語まとめ

Webブラウザ上でコンパイルされたコードが動作するWebAssembly。モダンなブラウザではほぼ実装されており、実用段階に入ってきています。現在の仕様ではDOM操作ができませんので、主にCanvasやWebGLを使う場合であったり、重たい計算処理を行う際に使われるでしょう。

そんなWebAssemblyの魅力の一つがJavaScript以外のプログラミング言語でWebブラウザ上で動くプログラムが書けるということです。今回はWebAssemblyを作ることができるプログラミング言語を紹介します。

C/C++

C言語やC++はEmscriptenを使ってWebAssemblyに変換できます。

asm.js

JavaScriptを高速にした(WebAssemblyの一世代前とも言えるかも知れません)asm.jsはWebAssembly/binaryen: Compiler infrastructure and toolchain library for WebAssembly, in C++でWebAssemblyに変換できます。

Rust

Mozillaの開発するプログラミング言語、Rustは元々Emscriptenが必要でしたが、開発版においてrustcだけでWebAssemblyにコンパイルできるようになっています。

C\

.NETのC#はlrz/mono-wasmを使ってWebAssemblyを生成します。また、UnityであればWebGLとして出力することでWebAssemblyを生成することも可能です。ただしランタイム全体が含まれていますのでC#の特定の機能だけをコンパイルできるという訳ではありません。

Swift/Objective-C

こちらは未検証なのでご注意ください Emscriptenを使った場合、LLVMであればWebAssemblyにできるそうです。そのためLLVMに対応した言語であればWebAssemblyに変換できるということになります。


現在、すべての言語においてすべてのライブラリが問題なく動作するという訳ではありません。サードパーティー製のライブラリはもちろん、言語標準の機能であっても動かないケースがあります。情報もまだ多くはないので、試行錯誤しながら実装していくことになるでしょう。

今後Webアプリケーションが大型化したり、リッチ化していく中でWebAssemblyは欠かせない技術になります。公開できないコード(秘密鍵など)を扱う場合にも有効な技術になります。ぜひお試しください。

JavaScriptのProxyを使いこなそう

最近、ReactやVueなどVirtualDOMを使った技術がトレンドになっています。VirtualDOMの特徴として、DOMの状態を管理から開放されて、変数を変えるだけで自動的に表示に反映される仕組みがあります。

変数の変更を感知し、表示に反映するために使われるのがProxyになります。VirtualDOMに限らず使える場面が多いオブジェクトなので、ぜひ使い方を覚えましょう。

基本的な使い方

Proxyはオブジェクトまたは配列に対してしか使えません。単なる数字や文字列では使えないので注意してください。以下はごく基本的なコードです。

まずProxyは既存の変数にとハンドラーを引数に取ります。

handlerはget/setを基本としたオブジェクトになります。値を追加した時にset、アクセスした際にgetがコールされます。targetは元のオブジェクト(obj)で、nameはアクセスしようとしたメソッド名(またはキー)になります。そしてvalueとして適用しようとした値が送られます。

getはターゲットと実行するメソッド名(またはキー)が送られてきます。

配列の場合

Proxyはオブジェクトだけでなく配列にも使えます。

使い方はオブジェクトの時と変わりません。ただし、配列の中にオブジェクトがあった場合、そのオブジェクトの中を変えても通知されないので注意が必要です。

他のオブジェクト

他のオブジェクト(関数、クラス)などに対してもProxyが使えます。ただしクラスなどでインスタンスに対して適用したい場合は、クラスではなくインスタンスに対してProxyを適用する必要があります。


Proxyを使うと、データを更新した時に関連するデータや表示をまとめて更新するといったことが簡単にできます。また、値を判別して例外を出すことで入力チェックのように使うこともできます。

ぜひProxyを使って関連する処理をまとめてみてください。

JavaScriptを安全に実行するためのnonce導入法

Webサイトでは不特定多数の人たちがサービスに触れます。その結果、悪意を持ったユーザによってWebページを改ざんされたり、不用意なJavaScriptを実行したりするリスクが発生します。

運営側で予期していないJavaScriptの実行を制限するのに使えるのがnonceです。CSP(コンテンツセキュリティポリシー)によって実行できるJavaScriptを制限できます。

仕組み

JavaScriptのnonceはクライアントサイドだけでは実装できません。まずHTMLを出力する際にレスポンスヘッダーにてnonceを出力する必要があります。以下はnode/Expressで実装した場合です。

nonceは nonce- という文字列ではじまっている必要があります。

HTML側

HTML側ではそのnonce(今度はnonce-は不要です)をscriptタグのnonce要素として出力します。

例えば上記のように記述されていた場合、Unsafe JavaScriptというアラートは出ません。

開発者コンソールで見ると、Unsafeの方はCSPエラーが出ています。


このようにして実行できるJavaScriptを制御できます。なお、nonceは常にユニークである必要があるので、uuidを使ったり、ランダムな文字列を生成するライブラリと組み合わせて使うのがいいでしょう。

Content Security Policy Level 3

HTML5.2で追加されるリファラーポリシーについて

従来、Webサイト間はリンクでつながっており、リンクを辿った際にはリファラーが送信される仕組みになっていました。しかしプライバシーの保護であったり、URL中に機密情報が含まれていた場合に問題になるため、送信されないことも多々あります。

HTML5.2ではリファラーポリシーが追加され、リファラーの送信について細かく制御できるようになります。

リファラーポリシーの設定法

リファラーポリシーはHTMLのmetaタグで指定します。

リファラーポリシーの種類について

HTML5.2によって設定できるリファラーポリシーが増えています。これまでは以下の3パターンでした。

  • origin

    スキーマ、ドメインのみを送ります

  • no-referrer

    リファラーを送りません

  • no-referrer-when-downgrade

    HTTPSからHTTPへのアクセス時にはリファラーを送りません

  • same-origin

    同じドメインであればリファラーを送信します。サブドメインでは送信しません。

  • strict-origin

    HTTPS同士での同じドメイン(サブドメイン含む)へのアクセスにおいてリファラーを送信

  • origin-when-cross-origin

    同じオリジンであればURL全体を送信しますが、スキーマが異なる際にはオリジンしか送信しません

  • strict-origin-when-cross-origin

    同じオリジンであればURL全体を送信します。サブドメインではドメインしか送信しません。スキーマが異なる際にはリファラーを送信しません

  • unsafe-url

    HTTP/HTTPS関係なくリファラーを送信します。

同じドメインであるかどうか、スキーマがHTTPかHTTPSであるかによって送信する情報が異なってきます。

影響範囲

適用されるのはa/area/img/iframe/linkタグになります。


リファラーポリシーを適切に設定することで、Webアプリケーションをセキュアに運用できるようになります。すべて防いでしまえばセキュアになりますが、リファラーの値によって制御するといったことはできなくなります。外部リソースを使うのが当たり前になっている現在、リファラーポリシーを使って安全な運営に努めてください。

Referrer Policy(日本語訳)

hifiveの小さな便利機能、h5.apiの紹介「localStorage編」

hifiveには頻繁に使われるであろう機能をAPIとしてまとめており、h5.apiというネームスペースでアクセスできるようになっています。

今回はlocalStorageを便利にしてくれるh5.api.storageについて紹介します。

localStorageの利用可否を判定する

通常、WebブラウザがlocalStorageをサポートしているかどうかはwindow.localStorageという変数のあるなしで判定されます。

しかしこの方法の場合、iOS/macOSのSafariにおけるプライベートブラウジングを使っている際に問題があります。この時には window.localStorage という変数は存在するものの、実際に書き込みを行うと QuotaExceededError が発生します。

そうした場合を踏まえて h5.api.storage.isSupported を使うと正しく localStorage の利用可否を判定できます。

ループ処理をサポートするeachメソッド

この他、ちょっと便利なeachメソッドが用意されています。

セッションストレージも使えます。

オブジェクトの保存にも対応

保存時に serialize 、取得時に deserialize していますので文字列以外であっても扱えるようになっています。

幾つのキーがあるか判定できる getLength メソッド

これは localStorage.length を実行しているだけです。


機能自体は小粒ですが、頻繁に使われるであろう機能をまとめておくことで開発が効率的になります。ぜひお使いください。