最近困ったスマホブラウザ系ハマりポイント


HTML,JavaScriptをはじめとしたWeb標準技術を使ってモバイルブラウザ向けに開発を行う場合、よくハマるのがAndroid対応です。弊社エンジニアもバグのまとめ記事に大変助けられています・・・。

今回は、最近困ったAndroidの標準ブラウザおよびAndroid Chromeでのハマりポイントをいくつかご紹介したいと思います。有名なハマりポイントや解決には至っていないものもありますが、同じような実装を行う際の参考になりましたら幸いです。

拡縮/スクロール操作の後だとtouchMoveイベントが数回しか発生しない?

お絵描きアプリ等、HTML要素をスワイプ操作やドラッグ操作したいときによく用いる「touchMoveイベント」に関するハマりポイントです。確認に使用した端末およびブラウザは、Sony Tablet Z SO-03E(Android:4.1.2 / Android Chrome ブラウザ)です。端末やブラウザによっては動作が異なる可能性があります。予めご了承ください。

touchMoveでよくある処理としては、viewportのscalableをnoに設定したり、任意の要素のtouchmoveのハンドラ内でevent.preventDefault()することが挙げられます。しかし今回は拡縮もスクロールも可能にしておく必要があり、viewportのscalableはyesのまま開発を進めました。すると、拡縮/スクロール操作の後だとtouchMoveイベントが数回しか発生しない問題が見受けられました。

前述の検証環境にてスワイプでの拡縮、スクロール時にtouchcancelが発火していることを確認しました。iOS(MobileSafari)ではtouchcancelは発火せず、意図通りに動作したため、今回の検証ではtouchcancelというイベントが関係していそうだという仮説に至りました。

touchcancelは、タッチイベントがシステムによってキャンセルされた場合に発火するイベントです。このtouchcancelが発火した後だと、touchmoveが2回ほど発火したのち正常に発火されなくなります。拡縮/スクロール後、イベントを再度登録し、mouseMoveの処理を行うと問題は起こりません。必要が無い限り、viewportのscalableはnoに設定しておくのが良いです。

参考

縦横の向きの判別にwindow.orientationを使用しない

こちらは端末別の実装差に関係するハマりポイントです。デバイスの傾きを取得できるorientationというプロパティがあります。ユーザが端末を持っている方向が、縦方向(portrait)か横方向(landscape)か判別し、レイアウトや処理を変えるような際に利用できます。たとえば、以下のような処理が考えられます。

  $(window).on(“orientationchange”, function(){

if (Math.abs(window.orientation) === 90) {
// 横向きの処理
} else {
// 縦向きの処理
}

});

ただ、この縦の状態と横の状態、Androidでは端末ごとにどの方向を基本とするかの設定がまちまちのようなのです。文章では分かりにくいので下記をご覧ください。

orientationで取得できる角度は、端末の基本の方向から何度傾いたかです。そのため、端末が横長、縦長の状態どちらを基本としているかによってこの値の持つ意味が変わります。orientationの値が90だからといって、横長の向きとは限らないということですね。向きの判別には、画面サイズを取得し、縦横比によって判定する必要があります。

  $(window).on(“resize”,function(){
// 画面のサイズを取得
var height = $(window).innerHeight();
var width = $(window).innerWidth();
// サイズを比較して縦向きおよび横向きの場合の処理を行う
if(height>width){
……..
}
});

一部のAndroidでonorientationchangeが取得できないので、画面の回転タイミングの判別にはresizeイベントを使います。

正確な画面サイズを取得できない時がある

上記のように、縦横判別の際には画面サイズ(innerHeight, innerWidth)を取得する必要があるのですが、Androidでは正確な画面サイズを取得できるタイミングがずれる場合があります。あまり綺麗な方法ではありませんが、今回は画面サイズの取得タイミングをsetTimeoutで300msほど遅延させることで、正確な値を取得することができました。縦横判別をしたい際には、ライブラリを使用するのも一つの手かもしれません。

if(checkDevice(‘android’)){
$(window).bind(“resize”,function(){
// Androidの場合は取得タイミングをずらす
setTimeout(getWindowSize,300);
});
}else{
$(window).bind(“orientationchange”,getWindowSize);
}

まとめ

以上、最近ハマった不具合をご紹介しました。一度解決してもすぐに忘れてしまうので、不具合情報は都度ストックしていきたいものです。間違いなどありましたら@riaxdnpまでご指摘いただけますと幸いです。