ABC2013Sprint の講演HTML5におけるAndroid端末間互換性のまとめです.
走り書きなので, 誤字脱字はあるかもしれないが, 指摘があり次第随時修正します.
Canvas vs CSS3
CSS3
- わずかな記法でリッチな表現が可能
- DOMの操作をベースとした記述が主体.
- デザイナー向け.
- Canvasに比べ, 仕様が極めて複雑かつ曖昧, iPhone/Android間に互換性が少ない.
- 同じOS同士のレガシーブラウザでも端末間で挙動が大きく違う.
Canvas
- わずかな表現に相当の記述が必要.
- ピクセル単位の操作が主体.
- プログラマー向け.
- 構文の解釈の違いによる互換性の問題は少ない. アンチエイリアシングの有無程度.
- 問題になるのは, レガシーブラウザ自体のバグ/端末特有のバグ/チップセット特有のバグ(GPU, コア, etc. Intelチップ端末)
よくあるトラブル集
getImageData/putImageData
- Canvasのピクセル情報を直接操作するAPI
- 透明ピクセル(半透明ピクセル)があった場合に破綻する. getImageDetaで取得するデータは正しいが, putImageDataでα値をセットすると描画が破綻する.
- セットする場合には, 乗算済みαを設定する必要がある.
Canvas#clip
- 一部の領域だけをマスクして, その部分に描画するAPI.
- クリッピング指定しているが, クリッピングされない. たまにクリッピングされることもある. ブラウザのバグ.
- 描画の前後にCanvas#save()/canvas#restore()を無意味に指定すると解決する.
描画する際になぜか画面がclearRectされる.
- Android3.0系列の某端末で発生
- setTimeoutを利用して描画しようとすると, なぜか今までCanvasに買い得てあった秒がを全部消してしまう.
- 描画前にCanvas#getPixelDataを無駄に呼ぶ.
ctx.getPixelData(0, 0, 1, 1)
画像のonloadが呼ばれない
- Android2.2系列の某端末で発生
- onloadする直前にsetTimeoutを無駄に呼ぶ
setTimeout(function(){}, 0);
- デバッガを起動すると正しく動くのでデバッグできない.
Canvas#drawImage 画像を描画しようとすると空白になる
- Androidの様々な端末で発生
- たまに発生する. 負荷が高まったときなど.
- メモリ不足が原因のはずが多いのでメモリ管理をしっかりする.
adb shell 'dumpsys meminfo _package-name_'
本体温度があがると描画が乱れる
- Android4.x系の某端末で発生
- 本体温度があがるとまれに描画が破綻する. 描画されるべき命令がスキップされ, されるべき描画がまれにされなくなる.
- CPUに負荷がかかりすぎないように負荷を調整.
問題に対する解決方法
発見方法
- たいていの問題は実際の端末で動かすまでは分からない. 人海戦術, サポートからの問い合わせで対応.
- 発生した問題に対して, 似たような端末での動作を疑う. メーカー/シリーズ, Androidバージョン, メモリ搭載量, CPU(シングルコアか否か), GPU.
解決方法
- 一般的な方法(デバッガーで1行ずつ追って見る, 頭の中での想像など)はAndroidのバグの解決方法には適していない.
- 問題が発生する最小サンプルを作成したあと, 回避するコードをひたすら試す.
- 基本的な動作を疑う.
-
ctx.clip(), ctx.transform()
あたりをコメントアウトして確認する. -
ctx.save(), ctx.restore()
で全体を括ってみる. -
ctx.drawImage()
の再現に失敗する場合はメモリを消費させる.
回避コード
回避コードは, 全てのANdroidで動作するものが望ましい.
- UserAgentを確認して分岐させる方法は最低のアイディア. 将来のブラウザにも対応するのが望ましい.
- ほとんどコストを発生させずに解決するのが望ましい.
- 回避コードには, 詳しくコメントを書く.
可能であれば
ブラウザのソースコードを一度読んでみるとよい.
- 端末ごとの問題はソースコードが公開されていないので, ソースコードから問題の特定は不可能.
- display object.
- WebKit系でなくても, Mozillaでもかまわない. 特にレンダリング周りのコードがよい.
エンジニアが互換性に文句を言うのは大切だが, ユーザに快適にサービスを使ってもらう方がより大切