「デスクトップ版を表示する」にチェックを付けると平然とUAを偽装するAndroid用標準ブラウザの判定をムキになってしてみます
モバイル版 Safari の「デスクトップ用サイトを表示」でも iOS のバージョンを取得できるようになりました。(2018/1/16 追記)
リッチな Web アプリや手厚いフォールバックの実装にあたっては、やはり「ブラウザ判定こそ基礎中の基礎、最近の表現だと一丁目一番地だ」と何年振りかに根を詰めてやってみました。
はじめに
Android 標準ブラウザ(AOSP, Chrome WebView)の判定には、navigator.userAgent
文字列から "Android"と"Version"の有無を利用するものが知られています。しかしこれらの文字列の有無は必ずしも信頼できるものではありません。
例えば Android 用ブラウザの多くには「デスクトップ版を表示する」といった設定があります。このチェックが付くとユーザーエージェント文字列は大きく変化して OS とブラウザの判定が難しくなります。しかしユーザーエージェント文字列が変わったからと言って、各モバイルブラウザに固有の挙動、バグを含む挙動がデスクトップ用ブラウザのソレへと変化することはありません。よってユーザーエージェント文字列に惑わされず正しく環境を判定する必要があります。
さらにユーザーエージェント文字列の変化を利用してユーザーの「デスクトップ版的なものを表示して欲しい」という意図を検出することも可能です。この情報を元にページの表現を切り替えればよりユーザーにフレンドリィ、エクスペリエンスあげあげな HTML コンテンツを提供できるのではないでしょうか。
いわゆる「おもてなし」、最近では「忖度」。それでは張り切っていきましょう。
各環境とブラウザの判定方法
OS+ブラウザ | PC版を表示 | OS判定 | OSバージョン | エンジン判定 | ブラウザバージョン |
---|---|---|---|---|---|
Android4.3- AOSP | Android | v | Version/ | OSバージョンと同じ | |
v | 矛盾文字列(*1) | △不正確(*2) | |||
Android4.4+ Chrome WebView | Android | v | (*3) | OSバージョンと同じ | |
v | 矛盾文字列(*1) | △不正確(*2) | |||
Android Firefox | Android | v | 'MozAppearance' | 'rv:' | |
v | 矛盾文字列(*1) | 不明 | |||
Android Chrome | Android | v | window.chrome | 'Chrome/' | |
v | 矛盾文字列(*1) | 不明 | |||
Android Prsto Opera | platform=Android | v(ua) | window.opera | getVersion() | |
v | platform=Android | 不明 | |||
Android Blink Opera | platform=Android | v(ua) | window.opr | 'OPR/' | |
v | 矛盾文字列(*1) | 不明 |
- 次の「矛盾するプラットフォーム文字列を使ったAndroidシステムの判定」を参照
- 「Android 標準ブラウザの Android バージョン判定」を参照
- UA を AOSP に偽装して出荷している端末があるため
document.registerElement
を確認する
矛盾するプラットフォーム文字列を使ったAndroidシステムの判定
次の Android 用ブラウザでは「デスクトップ版を表示する」場合にユーザーエージェント文字列等から Android 文字列が消えます。
- Android 標準ブラウザ AOSP, Chrome WebView
- Android 用 Chrome
- Android 用 Blink Opera
この際には、プラットフォーム文字列に "Linux armv7l" または "Linux i686" が入っている一方で、ユーザーエージェント文字列に "Linux x86_64" という矛盾した値が入っている点を利用して Android を判定します。
maybeAndroid = ( navigator.platform === 'Linux armv7l' || navigator.platform === 'Linux i686' ) && navigator.userAgent.indexOf( 'Linux x86_64' ) !== -1;
また Android バージョンの取得ができなくなります。Android にバンドルされている標準ブラウザに限っては、実装状況をヒントに Android バージョンを推測することはできます。
Ubuntu Mobile や Firefox OS などが似たようなことをしていないか?などは未検証です。
Android 標準ブラウザの Android バージョン判定
さて、ユーザーエージェント文字列等に "Android" がなくとも、Android と標準ブラウザの組み合わせであることが分かりました。続いて Android バージョンを判定していきます。
Android 4.0 以降ではユーザーエージェント文字列の WebKit バージョンが当てにならなくなるので、プロパティの有無で判定していきます。
バージョン | 判定法 | メモ |
---|---|---|
5.x | document.registerElement && !document.execCommand | execCommand が居なくなる… |
4.4.3+ | document.registerElement && document.execCommand | これ以降 Chrome Web View |
4.4 | window.Int8Array && !navigator.connection | ここまで AOSP |
4.2 | window.Int8Array && !window.searchBoxJavaBridge_ | 4.2 と 4.3 の判定は出来ていない |
4.1 | window.Int8Array && Number.isNaN | |
4.0 | window.Int8Array | |
3.x | 534 <= verWebKit | |
2.3 | 531 <= verWebKit && window.HTMLAudioElement | |
2.2 | 531 <= verWebKit && !window.HTMLAudioElement | |
2.0 | 529 <= verWebKit | 2.0 と 2.1 の判定は出来ていない |
1.x | verWebKit < 529 |
ところで、Web 開発では「ユーザーエージェント判定よりも機能判定」とはよく言われます。しかし、触るとクラッシュする等で機能判定の使えないケースについてはコード内に有効な機能のカタログを持つしかありません。また Android のバージョンが分かれば端末の大まかなスペックも推定できるのが素晴らしいですね。