この記事は、Angularをテーマとした日本初のカンファレンス 「ng-japan」のイベントレポート(第2回目)です。
はじめに
HTML5ハイブリッドアプリケーションとは、内部の実装にHTML5が利用されているモバイルアプリケーションです。アプリの内部実装にHTML5を使うことでクロスプラットフォーム対応が可能になりますが、その代わり問題となるのがUIとパフォーマンスです。このセッションでは、Angularの上に構築されたUIフレームワークであるOnsen UIを紹介しながら、Angularでどうすれば高速かつ快適なUIを持つモバイルアプリを作れるかについて話します。
AngularとOnsen UIで作る最高のHTML5ハイブリッドアプリ – 久保田 光則
久保田光則氏は、アシアル株式会社でUI/UXデザイナー兼ソフトウェアエンジニアとして活動されています。今回お話するOnsen UIのリード開発者としても活動していて、専門でハイブリットアプリを開発しています。本日お話する内容はAngularの上に作られたOnsen UIというライブラリの内容になります。Onsen UIはonsen.ioというドメインで日本語版/英語版が公開されているオープンソースです。
特徴としては
- HTML5ハイブリットアプリ用のUIフレームワーク
- Angularをベースにしている
- iOS, Androidをサポートしている
- 高速な動作
今回は次のことに焦点を当てて、お話します。
- HTML5ハイブリットアプリとは
- ハイブリッドアプリ開発にどんな問題があるか?
- なぜAngularとOnsen UIが必要なのか?
- 少しだけOnsen UIの紹介
HTML5ハイブリットとはどのようなものか、ハイブリットアプリケーションを開発するときにどのような問題があるのか、AngularやOnsen UIがハイブリットアプリケーションを作成するためになぜ必要なのか、そして最後にOnsen UIのお話をしたいと思います。
HTML5ハイブリットアプリとは
HTML5ハイブリットアプリとは、ネイティブアプリとWebアプリの両方を書き合わせたアプリケーションになっています。実装の中身はHTML5で書かれています。WebViewというものがありその部分でHTMLを利用します。
HTML5ハイブリットアプリの何がよいのかというと、
- クロスプラットフォーム制
- Webの知識が活かせる
- ストアで配布できる
- ネイティブの呼び出しがJavaScriptから機能を呼び出しできる
ネイティブアプリケーションではそのプラットフォームの流儀に合わせて作る必要がありますが、HTML5の部分はプラットフォームには依存しないので、クロスプラットフォーム化しやすいというメリットがあります。
そして、Webの知識がそのままモバイル開発に活かせるということも、メリットの一つです。ネイティブ機能の呼び出しがなぜできるかというと、通常のWebViewではできず、セキュリティ的にも難しいところがありますが、Cordovaを使うことによってHTML5をアプリケーション内部でパッケージ化し、OSとのやり取りもAPIを通じて一本化できJavaScriptを通じて利用することが可能になります。
具体的には
- ファイルストレージ
- カメラ
- コンパス
- 加速度センサー
- コンタクトリスト
- ネットワーク
- Bluetooth通信
- などなど
さらにCordovaプラグインを作ることで、幅が広がっていきます。
「HTML5でモバイル・アプリが作れる」ということで、多くのフロント・エンジニアがHTML5ハイブリットアプリケーションに取り組んできました。あまりうまくいかなかったのが現実だったと思います。三年程前になりますが、Facebookは一部分の機能をHTML5で構築しましたが、結果として「HTML5に賭けたのは失敗だった」とし、ネイティブで書きなおすということが発生しました。しかし数年前に比べ、現在状況は改善してきています。
- 端末スペックの向上
- AndroidでのWebViewのChromiumの採用
- 利用できるHTML5 APIの増加
- Android2.3系のシェア低下
- CrossWalkの登場
- Android5からAndroid System WebViewの登場
- HTML5ハイブリットアプリケーションの事例増加
- BYODの一般化
最近だとRailsの作成なども昔はスペックが低かったのですが、最近はだいぶよくなってきたという認識があるようです。しかし、ネイティブに比べあまりよくないという印象があります。ではよくないというのは、何が問題なのかを考えます。
- パフォーマンスや安定性がよくない
- UIコンポーネントをいちいち作らないといけない
パフォーマンスに関しては、チューニングすればいいという話ですが。実際にはチューニングの方法に関しては、あまり興味ないという人が多いようです。特にフロントエンド開発者の多くが、HTML, CSS, JavaScriptの書き方は理解しているが、チューニング方法に関してはあまり関心がないということがあるようです。
そこでチューニングのやり方について、少しお話しようと思います。
効率的なチューニング
まず、どこがボトルネックになっているのかを調べる必要があります。これはハイブリットアプリケーションを開発する人だけではなく、一般のWebアプリケーション開発者に取っても必要になる事柄です。
- インスペクタのTimelineタブで計測
- AndroidではChrome
- iOSではSafari
実機で開発しているときにも、このインスペクタを使って測定することが可能です。インスペクタのTimelineで取れるカテゴリは4つあります。
- Loading
- Scripting
- Rendering
- Painting
このLoading, Scripting, Rendering, Paintingという流れがありますが、これを1frameと呼びます。描画が始まってから終わるまでが1frameで、この1frameを16ms以下に抑えればよいということになります。Timelineを使って測定した後、どこにボトルネックがあるかでチューニングが変わります。
Loading
Loadingは、リソースの読み込みやパースが行われます。ハイブリッドでは、Webアプリケーションよりも消費する時間は短いです。理由としては、リソースがローカルにあるからです。通常のWebアプリケーションは、リソースの取得もこのLoadingに含まれます。
Scripting
次に、Scriptingになります。これは、JavaScriptの実行時間になります。
今のJavaScriptの実行時間としては、純粋な計算は速いと考えてよく、基本的には問題ならないです。ただし、canvasへの描画などは遅くなる場合があります。チューニングに関しては、簡単で単純にでき、Profilesタブでどのコードが遅いかを確認すればよいということになります。
Rendering
ここから話が少しややこしくなります。Renderingであるレイアウト処理は、大きく2つの処理があります。
- Recalculate Style – 要素に当たるCSSルールの計算
- Layout – Render Treeの生成
Recalculate Styleがどのような計算をするかというと、個別のDOM要素に対して該当するスタイル(プロパティ)を計算します。CSSがレンダリング内部でパースされるとCSS OMという形になり参照して
DOM要素の数 × CSSルール
数分のマッチング処理が行われます。チューニングの一つとしてCSSの使ってないルールは削除するというものがありますが、この数式に由来しています。ルールが一つ減るだけでも、DOM要素の数分処理が減るということになるためです。さらに、重たいCSSの書き方を減らすということを行うと、より効果的です。
その次のLayoutというフェーズでは、すべてのDOM要素のレイアウト情報を計算します。計算された結果として、視覚的なオブジェクトツリーのことをRenderTreeと言います。そして、CSSの書き方やDOM要素の数を工夫することで、レスポンス改善することができます。
Painting
4つのうちの最後の処理ですが、さらに3つの工程があります。
- Paint – Display Listの生成
- Rasterize – Display Listを実行してピクセル化
- Composite Layers – レイヤの合成
雑多なチューニングテクニック小話
translate3d(0, 0, 0)が速いのはなぜ?
これは、GPUで描画されるので速いという話がありますが、実は半分正解で、半分は間違っています。GPUで描画され、transform CSSプロパティを変更しても、Composite Layersのみが起こるためです。同時に別処理でLayoutを引き起こしたりすると、効果が薄れます。
どのCSSプロパティを変更すると、何が起こるのかというところは不明瞭な部分が多い。ある程度パターンはあり次の区分けで分類できます。
- 要素の大きさが変わるような場合
- Layoutから処理が始まる
- transformやopacityたとComposite Layersのみ実行
- CSSプロパティによる変更では事象が異なる
CSS Triggersというサイトがあるので、ぜひ参考にして欲しいと思います。CSSプロパティを変更すると、インスペクタのTimelineで取れるカテゴリの何が実行されるかを示した表になっています。
http://csstriggers.com/ の紹介
DOMリークを防ぐ
DOM要素が誤って参照されたまま、開放されないという現象です。見た目よりも深刻で、DOM要素の参照は親要素への参照も子要素への参照も持っているので、DOMリークが起こるとすべてリークになります。detached DOMツリーとそれに参照されているリソースが、すべてリークするということがあります。その中に画像が入っているとそういった部分もリークします。
ディスクトップではあまり意識しなくてもよかったのですが、iOS, Androidだとメモリスワッピングが弱く設計されていて、アプリケーションの利用を破棄するといったことが起こります。そのためにモバイルだと、メモリーの管理を余計にしないといけなくなります。
reflowを起こさないようにする
Reflowを起こさないためには
- 画像のサイズは必ず指定
- DOMツリーから切り離して操作
画像がまだ読み込まれていない時に、サイズとして仮指定する場合があります。画像を描画し、本当のサイズにレンダリングすることになりますが、DOM要素の大きさが変わるため、Layoutの処理が再度はじめから行われるということになります。
GPUバウンド
CPUよりもGPUの方で時間がかかっている状態のことを、GPUバウンドと言います。先ほどtranslate3d(0, 0, 0)が速いという話がありましたが、これはComposite Layersだけが走っているためです。しかしこれを使いすぎると、GPUバウンドが発生します。
GPUバウンドなページを作ることは簡単で、多くな領域を持つ要素にtransform: translate3d(0, 0, 0)を当てて多く生成し、アニメーションさせれば作られます。
チューニングの罠
こういったチューニングの大部分のところは、レンダリングエンジンに依存しています。どうしてもわからないときは、レンダリングエンジンのソースを読んだりします。ただ、なぜHTML5のコードを書くのに、ここまでやる必要があるのか。なぜ単にCSS書いているだけなのに、GPUのVRAMへの転送速度を気にしなければならないのか、という疑問があります。実際にアプリケーション開発中にここまでチューニングする余裕はないはずだし、こういったチューニングをすべて把握することを、開発者に求めてよいのかということもあります。
ごく一部の人間でないと、高速なHTML5ハイブリットアプリケーションは開発できないのでしょうか。今のHTML5アプリケーションの課題としては、アプリケーションアーキテクチャの構築方法の不在ということや、チューニングされて高速に動作するUI基盤がないということが言えると思います。ネイティブだとUIフレームワークがあるが、HTML5ハイブリットアプリケーションだとUIフレームワークがないというのが現実です。
Onsen UI
そこでOnsen UIです。この目的は、開発者がアプリの開発そのものに注力できるようにすることです。
Angularをベースにして構築しています。Angularの持つ機能を利用しHTMLを拡張することで、アプリケーションを記述することができ、大規模なアプリケーションでも耐えられるアーキテクチャを作ることができます。Angularの持っているディレクティブを使うことで、UIを構築することもできる。Onsen UIでは「ons-」を使っています。そして、Adobeの超高速CSSフレームワークtopcoteを利用しテーマを開発しています。またOnsen UIでは多くのコンポーネントを用意しています。
Onsen UIが目指すものとして、誰でもHTML5で高速に動作するモバイル・アプリケーションを作ることができる世界を提供したいと考えています。さらに、UIをどうチューニングするかではなく、アプリケーションの本質的な機能の開発にフォーカスすることができる基盤も提供したい。今後は、Onsen UIはMaterial Designs、Angular2のサポートを行っていくつもりです。
CodeIQとの連動企画!
AngularJS雑学、豆知識を問う問題です。腕試しに、もしくは理解度チェックに是非ご活用ください!こちらから問題にチャレンジ!
問題:知ってる?AngularJS雑学
プレゼンテーション資料
このセッションのプレゼンテーション資料は下記になります。合わせてご覧ください。
セッション動画
当日のセッションはYouTubeで公開されています。ぜひご覧ください!