Upload
takuo-kihira
View
8.599
Download
1
Embed Size (px)
DESCRIPTION
HTML5 Conference 2013で発表した資料です。
Citation preview
実践的な
モバイルHTML5テクニックTakuo KIHIRA
2013-11-30
2
Broadtail ConfidentialConfidential2
• 紀平拓男(きひら たくお)– 株式会社ディー・エヌ・エー
– HTML5 Chief Engineer
– @tkihira
• 会社を2つ設立したシリアルアントレプレナー
• HTML5によるFlash Runtime『ExGame』を製作
• DeNAにおいてHTML5の総括を担う
• 「インストール」が大嫌い。インストールの無い世界にしたい
自己紹介
3
Broadtail ConfidentialConfidential3
今回お話しする内容
今出来ること 将来出来ること
モバイル
ブラウザ
PCブラウザ
4
4
なぜ今、モバイルHTML5なのか
5
Broadtail ConfidentialConfidential5
• 世の中、ネイティブアプリ全盛期– パズドラからgmailまで、あらゆるアプリがネイティブアプ
リで登場
– HTML5で作成され、世界的に普及しているWebアプリは一つもない
• ネイティブアプリの開発が大変楽になっている– メジャーなOSが、iOSとAndroidの2種類のみ
– クロスプラットフォームなフレームワークもたくさん出来ている
• 大変遺憾ながら、
ネイティブアプリ >>> Webアプリ
モバイルの現状を、真摯に受け止める
6
Broadtail ConfidentialConfidential6
• 欠点が大いに目立つ– 作るのにコストがかかって本当に大変。エンジニアもあま
りいない
• しかし、皆様にはぜひとも、利点に目を向けて頂きたい
Webアプリの利点と欠点
利点 欠点
• インストールが不要
• あらゆるブラウザ搭載端末から、URLのみで起動できる
• リアルタイムアップデートが可能
• 実行速度が遅い
• 互換性がない
• 3D、音楽などのハードウェアに密着した処理が辛い
7
Broadtail ConfidentialConfidential7
モバイルWebアプリのメリット
まずゲームをプレイする
誰かと一緒に
プレイしたくなりツイッターで拡散する
友人がツイートを確認してURLをクリックする
よくてスクリーンショット、大抵はAppStore直送
8
Broadtail ConfidentialConfidential8
モバイルWebアプリのメリット
まずゲームをプレイする
誰かと一緒に
プレイしたくなりツイッターで拡散する
友人がツイートを確認してURLをクリックする
友人の現在のプレイが即座にそのまま見られる!
9
Broadtail ConfidentialConfidential9
• 格闘ゲームのコンボ
• 「シムシティ」「A列車で行こう」の街
• 最近だと、姓名判断アプリがバズった– ボタン一つで手軽にシェアできる
– URLをタップするだけですぐに確認できる
– シェアされた人がすぐに自分も体験できる
アプリでは、実現できない
モバイルWebアプリのメリット
10
Broadtail ConfidentialConfidential10
• ネイティブアプリでは実現できないメリットを活用したい– TwitterのURLをタップしたら、即座にアプリを起動
– 広告バナーをクリックしたら、即座にアプリを起動
– アプリの中からURLを発行して独自のシーンでアプリを起動
• 現在の最先端:Webアプリのデメリットを地道につぶす– 実行速度が遅い
– 互換性がない
– 3D、音楽などのハードウェアに密着した処理が辛い
• モバイルアプリをネイティブアプリに近づければ、Webアプリ「ならでは」のメリットを活用したアプリになる
まとめ:なぜ今、モバイルHTML5なのか
11
11
モバイルHTML5の基礎
12
Broadtail ConfidentialConfidential12
• PC Webにはブラウザがそんなにない– IE、Chrome、Firefox、Safari、Opera
• モバイルWebにはブラウザがもっとない– Mobile Safari、Android Legacy Browser、Android Chromeくらい
– しかもその全てがWebkitベース
• なので対応がとても楽
…というのは大嘘!
モバイルWebとPC Webの違い
13
Broadtail ConfidentialConfidential13
• Androidは、メーカーがある程度自由にソースをいじれる– Androidは比較的オープンであり、各社が自社の端末にあわ
せて最適化したAndroidを搭載するのが一般的
• ブラウザのベンチマークスコアは、重要な差別化要因– ブラウザがぬるぬる動くことが競争力に繋がる
• 各ベンダーがブラウザのソースコードに手を加えて最適化– そしてバグを埋め込む
• 結果として、端末の数だけ独自ブラウザがある状況に
Androidの互換性問題
14
Broadtail ConfidentialConfidential14
• Androidの対応は、IE6の対応より大変です
残念なお知らせ
15
Broadtail ConfidentialConfidential15
HTML5でリッチな表現を作るときに、主に2通りのやり方がある
• Canvas
– HTML5のCanvasと呼ばれるお絵かき機能を駆使し、画面上の全てのピクセルを自前で描画する方式
– ExGame、LWF、CreateJS、ImpactJS等
• CSS (+ DOM)
– 元々のHTMLの伝統的な形式であるDOMとCSSを駆使し、ブラウザの助けを最大限利用しながら描画する方式
– Swiffy、Sencha、Bootstrap、jQuery mobile
CanvasとCSS
16
Broadtail ConfidentialConfidential16
• 両方を使いわけるスタイルも普及しつつある
CanvasとCSSの利点と欠点
利点 欠点
Canvas
• 互換性バグを踏みにくい
• 細かい最適化を自力で頑張ることが出来る
• 表示のためのコード量が大変多くなる(真っ当な人間の書くものではない)
• ブラウザのサポートが得にくい
CSS + DOM
• デザイナーが慣れ親しんだ形式
• ブラウザの高速化施策の恩恵を受けられることが多い
• 互換性に大変問題が多い
• 細かい問題を自力で解決することが出来ない
17
Broadtail ConfidentialConfidential17
• ちょっとしたアプリを作るのであればCSSが適している– デザイナー志向のツールの存在
• Sencha Animator、jQuery Mobile
– CSS自体の豊富な機能• CSS Animations、CSS Transforms、CSS Filters
– ブラウザのコントロールにゆだねることが出来る• フレームスキップ、非表示時の処理軽減
• 作りこんだアプリの場合はCanvasの方が優れる– (CSSに比べれば)高い互換性
– いくつかのサポートツールの登場
– 全てを自前でコントロールすることが出来る
• CSSも実用に耐えうるようになりつつあるが、Canvasがまだ主流
CanvasとCSSのどちらを使うか
18
18
Canvas Tech
19
Broadtail ConfidentialConfidential19
• 何度も描画に利用する部分をメモリ上に退避し、それを描画に利用する
– Offscreen Canvas, On Memory Canvas等と呼ばれる
– キャッシュを確保すればその分のメモリが消費される
– とくに複雑な描画をする場合には、いかに綺麗にキャッシュに乗せるかが高速化のポイントになる
オンメモリCanvasの利用
var img = document.getElementById("data");var cache = document.createElement("canvas"); // キャッシュ用Canvascache.width = img.width * 2; cache.height = img.height * 2;var cacheCtx = canvas.getCotext("2d");cacheCtx.transform(2, 0, 0, 2, 0, 0); // 倍に拡大するcacheCtx.drawImage(img, 0, 0); // キャッシュ用Canvasに書き込む
ctx.drawImage(cache, 100, 100); // キャッシュを使って描画する
20
Broadtail ConfidentialConfidential20
• Canvasに画像を描画する際、小数点の位置に描画しない– 小数点の位置に描画すると、
• アンチエイリアシングがかかる(こともある)のでにじむ
• 描画のスピードが遅い
• 拡大、縮小をせずに描画する
– 拡大縮小は時間がかかるので、メモリに余裕があれば拡大済・縮小済の画像を用意して対処する
画像やCanvasの描画(drawImage)
ctx.drawImage(img, x | 0, y | 0); // 座標を整数に整える
21
Broadtail ConfidentialConfidential21
• 同じ図形をパス(moveToやlineToなど)を駆使して描
画する場合、描画用のデータを毎回解析せず、最初に文字列として関数を作成し、それを関数化することでオーバーヘッドを削減できる
new Functionによるオーバーヘッドの削減(1)
var svg = "M 51.35 38.55 L 30.35 0 L 21 0 L 0 38.55 L 8.3 38.55"+ " L 12.7 30.3 L 38.65 30.3 L 43.05 38.55 L 51.35 38.55"+ " M 34.9 23.5 L 16.5 23.5 L 25.7 6.45 L 34.9 23.5".split(" ");
var body = "ctx.beginPath();";for(var i = 0; i < svg.length; i+=3) {
var pos = svg[i + 1] + "," + svg[i + 2];if(svg[i] == "M") { body += "ctx.moveTo(" + pos + ");"; }if(svg[i] == "L") { body += "ctx.lineTo(" + pos + ");"; }
}var func = new Function("ctx", body + "ctx.fill();");
func(ctx);
22
Broadtail ConfidentialConfidential22
• 生成されるJavaScriptはこんな感じ
• コードを自動生成することで、パース等に必要な余計なコストを削除する– 最初から自動生成したコードを使用するのもあり
• ちなみに上記コードを実行するとこれが出る
new Functionによるオーバーヘッドの削減(2)
ctx.beginPath();ctx.moveTo(51.35,38.55);ctx.lineTo(30.35,0);ctx.lineTo(21,0);ctx.lineTo(0,38.55);ctx.lineTo(8.3,38.55);ctx.lineTo(12.7,30.3);ctx.lineTo(38.65,30.3);ctx.lineTo(43.05,38.55);ctx.lineTo(51.35,38.55);ctx.moveTo(34.9,23.5);ctx.lineTo(16.5,23.5);ctx.lineTo(25.7,6.45);ctx.lineTo(34.9,23.5);
23
Broadtail ConfidentialConfidential23
• GPUキャッシュに描画する画像が乗るように意識する– GPUは高速化のために内部に画像キャッシュがあり、キャッ
シュ画像で再描画する際にはCPUからGPUにデータを転送せずにすむ
• どうすればキャッシュに乗るのかはブラウザの情況次第– 必ずキャッシュに乗るように書くことは難しいが、ある程
度は可能
– 基本戦略としては安定志向と博打志向• 安定志向:小さい画像(IMG)を複数用意し、それらを
drawImageする
• 博打志向:1024x1024等の大きい画像を用意し、そこから切り出してdrawImageする
• 博打する場合のサイズは512x512、1024x1024等にする
• 一定時間の間にブラウザに使われる画像を意識し、GPUにどのようにキャッシュが乗るのかを想像する
GPUを意識した高速化(1)
24
Broadtail ConfidentialConfidential24
• CanvasはGPUキャッシュに乗ることはないので、Canvasをimgタグに変換する– Canvasはプログラムによって変更されることが前提であるた
め、現在のブラウザの実装ではCanvasはGPUのキャッシュに乗らない
– toDataURL APIを利用してCanvasをimgに変換することで、GPUのキャッシュにのるようにしてやる
– 使い終わったcanvasはきちんとGCされるように気をつける
GPUを意識した高速化(2)
var src = canvas.toDataURL();var img = document.createElement("img");img.src = src;
25
Broadtail ConfidentialConfidential25
• 先述したとおり、Android Legacy Browserは多種多様の
変更が入っており、ありとあらゆる問題が起こりうる
• こんな簡単な命令ですら、動かないときは動かない– 問題が起こったら、ブラウザを過信せず徹底的に疑う
– なお上記の問題は以下で解決する
互換性問題の解決
ctx.clearRect(0, 0, width, height);
ctx.clearRect(0, 0, width + 1, height + 1);
26
Broadtail ConfidentialConfidential26
• ブラウザの気持ちになって考える
– ブラウザが、内部でどのような処理をしているせいでこうなったのだろうか
– 逆にこのような結果になるためには、どのような処理を書けば発生するだろうか
– 全体からコメントアウトしていって問題の場所を発見するか、もしくは小さなサンプルを作って問題の最小サンプルを作成し、問題をシンプルにして仮定を立てやすくする
互換性問題の解決(2)
27
Broadtail ConfidentialConfidential27
• 実際にあった問題– 特定の端末で、なぜかCanvasへの描画が乱れる
• GPUプログラムにバグがあることを突き止め、GPUを利用しないようにCanvasのサイズを一定以上のサイズ(>2048px)にする
– 特定の端末で、なぜかCanvasのメモリが解放されないことがある• 大き目のCanvasを用意して、消さずに使いまわすようにする
– 特定の端末で、なぜかimgのonloadが呼ばれないことがある
– 特定の端末で、なぜかJavaScriptの代入が失敗する• 失敗しないように代入文を書き直す
– 特定の端末で、なぜか温めると表示が乱れる• どうしろと…
互換性問題の解決(3)
setTimeout(function() {}, 0); // 絶対に消さないこと
28
Broadtail ConfidentialConfidential28
• Androidの対応は、IE6の対応より大変です
再掲: 残念なお知らせ
29
Broadtail ConfidentialConfidential29
• メモリを使いすぎない– メモリを使いすぎると、ブラウザは反抗する
• iPhone: 落ちる
• Android: 描画をサボる もしくは固まる もちろん落ちることもある
– 自前でキャッシュ管理機構を作ってキャッシュを消去する• LRU等の単純なアルゴリズムでも十分に効果がある
• メモリリークをしない– ブラウザのGCにきちんと回収されるように気をつける
• 使いもしていないCanvasの参照を持ち続けていないか?
• クロージャが予想以上にスコープを確保していないか?
– 動的にメモリを確認して、メモリが微増する場所を突き止める• adb やインスペクタを利用する
• iOSでもAndroidでも、メモリの特性は大体同じ• 特定の端末のみで発生する問題は、もちろんある
メモリの問題
30
Broadtail ConfidentialConfidential30
• 描画する部分が大きければ大きいほど、バッテリーの消費が激しくなる
– たとえばこのようなコードを書くと、CPUはそれほど働いていないにも関わらず、バッテリーはもりもり減る
• 描画をしなくていい場合には一切描画系のコマンドを呼び出さないようにする
バッテリーの問題
(function draw() {setTimeout(draw, 16);ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
})();
31
Broadtail ConfidentialConfidential31
• 高速化もメモリ管理も、実際のデータをもとに確認する
• どうしようもないこともある
鉄則
32
32
デモ
33
Broadtail ConfidentialConfidential33
Canvasをとことん使ったデモ
ダンジョンポッパーmobageでリリース中iPhone/Android対応
Google I/O 2013で発表したHTML5ゲームのデモ
34
Broadtail ConfidentialConfidential34
• ブラウザHTML5には、アプリでは絶対に達成できな
いメリットがある一方で、アプリに比べ劣っている点も多い
• HTML5らしさを出したWebアプリはほとんど出ていない– モバイルHTML5が世界で一番進んでいるのが日本
• 将来、アプリがWebに置き換わっていくのはほぼ確実
• HTML5のメリットをフル活用し、欠点の少ないアプ
リが簡単に作れるようになれば、世界を制することが出来る
最後に
35
Broadtail ConfidentialConfidential35
ぜひ皆さんで一緒に、次世代のWebアプリを世界に普及させましょう!
36
Broadtail ConfidentialConfidential36
ご清聴、ありがとうございました
紀平拓男 @tkihira
37
Broadtail ConfidentialConfidential37