🦁

【JavaScript】iOSのSafariをUserAgentで判別する方法

2020/10/27に公開

どうもZenn初投稿のka_wa_ha_giです。

最近、WebRTCを使う機会があり、実装を進めておりました。
そこでiOSのブラウザでWebRTCに対応しているのはSafariのみという問題にぶつかりまして、その回避策としてUserAgentでの分岐という手段を用いました。
以前に比べ、かなり変更されていて苦戦したのでまとめてみました。

safariが文字列として含まれてる問題

iPhoneXでUserAgentを確認した結果が下記になります。

  • Safari
Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1
  • Chrome
Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/85.0.4183.109 Mobile/15E148 Safari/604.1
  • Firefox
Mozilla/5.0 (iPhone; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/28.2 Mobile/15E148 Safari/605.1.15
  • Edge
Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 EdgiOS/45.8.10 Mobile/15E148 Safari/605.1.15

確認した全てのブラウザにsafariが含まれているのです。

では、どうやって判別するのか

パッケージを使用する

detect-browserというパッケージを使用するのが手っ取り早いです。

「なんだパッケージ使うのかよ」と思われる方もおられるかもしれません。
しかしUserAgentは仕様や各ブラウザ/OSのバージョンにより今後も変わっていく可能性があるため、判定する責務をパッケージに任せられるなら任せた方が良いと思いました。楽ですし

import { browserName, detectOS } from 'detect-browser';

/**
 * @class Version
 * @description デバイス情報を判定する処理
 */
export class Version {
  private readonly ua = window.navigator.userAgent;
  private readonly browserName = browserName(this.ua);
  private readonly detectOS = detectOS(this.ua);
  private readonly bodyElm = document.querySelector('body');
  public isSP = false;

  constructor() {
    this.eventHandler();
  }

  private eventHandler(): void {
    this.judgeSmartPhone();
    this.handleAddClass();
  }

  /**
   * スマートフォンかどうか判別
   */
  private judgeSmartPhone(): void {
    switch (this.detectOS) {
      case 'Android OS':
      case 'iOS':
      case 'Windows Mobile':
      case 'BlackBerry OS': {
        this.isSP = true;
      }
    }
  }

  /**
   * bodyにclass追加
   */
  private handleAddClass(): void {
    if (!this.bodyElm) {
      return;
    }
    switch (this.browserName) {
      case 'ie':
      case 'edge':
      case 'firefox': {
        this.bodyElm.classList.add(this.browserName);
        break;
      }
      case 'safari':
      case 'ios': {
        this.bodyElm.classList.add('safari');
        break;
      }
    }
    if (this.isSP) {
      this.bodyElm.classList.add('isSP');
    }
  }
}

既存の正規表現部分を更新する

自分でif文を書いて分岐させている方も多いと思います。
そこでdetect-browserのtsファイルを読んでみてください。Safari以外も正規表現で判別しているため、かなり参考になるはずです。
https://github.com/DamonOehlman/detect-browser/blob/master/src/index.ts

iOSのSafariは下記で分岐できます。

/Version\/([0-9\._]+).*Mobile.*Safari.*/

ちなみにPCのSafariは下記で.*Mobile部分をトルことで判別できます。

/Version\/([0-9\._]+).*Safari/

まとめ

正規表現は人類に早かった。

Discussion