🔍

2021年版 主要なアプリ内ブラウザのUserAgentを調べてみた & 判定を実装してみた

2021/06/27に公開

アプリ内ブラウザによって挙動が違うと、時にはグッとこらえてUserAgentによる条件分岐を入れなくてはいけないということもあるでしょう。

本当はこんな条件分岐入れたくない。でも、長い人生では止むに止まれぬ大人の事情というものがあります。

...さて、どう判定しよう? ざっと調べたところ少し古い情報しか見当たらなかったので、自分で調べてみました。

2021年6月27日時点、手元の

  • iPhone 12 Pro(iOS 14.5)
  • Pixel 4(Android 11)

を使って各アプリの(おそらく)最新版を使って調査しました。

それをもとに作成した、JavaScript (ES6)による実装例もつけてあります。間違いやもっといい方法などあればぜひコメントください。

テストコード付きの実装例はこちらから。
https://codesandbox.io/s/detect-in-app-browser-s4owq

UserAgentの実例集め

対象にしたアプリは以下の通り:

  • Twitter
  • Facebook
  • Instagram
  • LINE
  • Slack
  • Discord

また、比較のためSafari(iOSのみ)とChromeも調べています。

iOS

Twitter、Slack、DiscordはSafariと全く同じUserAgentなので、判別不可能そうでした。Chrome、Facebook、Instagram、LINEは大丈夫です。

# Safari
Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1

# Chrome
Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/91.0.4472.80 Mobile/15E148 Safari/604.1

# Twitter
Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1

# Facebook
Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 [FBAN/FBIOS;FBDV/iPhone13,3;FBMD/iPhone;FBSN/iOS;FBSV/14.5;FBSS/3;FBID/phone;FBLC/ja_JP;FBOP/5]

# Instagram
Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Instagram 193.0.0.29.121 (iPhone13,3; iOS 14_5; ja_JP; ja-JP; scale=3.00; 1170x2532; 299401192) NW/3

# LINE
Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Safari Line/11.10.0

# Slack
Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1

# Discord
Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1

Android

iOSと同様に、Twitter、Slack、DiscordはChromeと全く同じUserAgentなので、判別できなさそう。Facebook、Instagram、LINEは大丈夫です。

# Chrome
Mozilla/5.0 (Linux; Android 11; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36

# Twitter
Mozilla/5.0 (Linux; Android 11; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36

# Facebook
Mozilla/5.0 (Linux; Android 11; Pixel 4 Build/RQ2A.210405.005; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/90.0.4430.210 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/324.0.0.48.120;]

# Instagram
Mozilla/5.0 (Linux; Android 11; Pixel 4 Build/RQ2A.210405.005; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/90.0.4430.210 Mobile Safari/537.36 Instagram 193.0.0.45.120 Android (30/11; 440dpi; 1080x2236; Google/google; Pixel 4; flame; flame; ja_JP; 300078998)

# LINE
Mozilla/5.0 (Linux; Android 11; Pixel 4 Build/RQ2A.210405.005; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/90.0.4430.210 Mobile Safari/537.36 Line/11.10.2/IAB

# Slack
Mozilla/5.0 (Linux; Android 11; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36

# Discord
Mozilla/5.0 (Linux; Android 11; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36

判定する関数の実装

上記をもとに、どのアプリ内ブラウザかを判定する関数 detectInAppBrowser を実装してみます。

window.navigator.userAgentなどで取得したUserAgentの文字列を渡すと、以下のように構成される文字列を返します。

(isまたはmaybe)_(アプリ)_(OS)

アプリは判定できたけどOSがわからない場合is_(アプリ)_unknownのようになり、アプリを判定できなかった場合はnullを返します。

テストコード付きのソースコードはこちらから。
https://codesandbox.io/s/detect-in-app-browser-s4owq

/*
  Detect in-app browser by UserAgent.
  e.g. `console.log('your browser ' + detectInAppBrowser(navigator.userAgent))`
  
  @param {string} ua UserAgent string
  @returns {string | null} [is|maybe]_[safari|chrome|facebook|instagram|line]_[ios|android|unknown]
 */
export function detectInAppBrowser(ua) {
  ua = ua.toLowerCase().trim();

  // iOS Chrome
  if (ua.includes('crios')) {
    return 'is_chrome_ios';
  }
  
  const isIOS =
    ua.includes('iphone') || ua.includes('ipod') || ua.includes('ipad');
  const isAndroid = ua.includes('android');

  // Facebook
  if (ua.includes('fbios') || ua.includes('fb_iab')) {
    return isIOS
      ? 'is_facebook_ios'
      : isAndroid
      ? 'is_facebook_android'
      : 'is_facebook_unknown';
  }

  // Instagram
  if (ua.includes('instagram')) {
    return isIOS
      ? 'is_instagram_ios'
      : isAndroid
      ? 'is_instagram_android'
      : 'is_instagram_unknown';
  }

  // LINE
  if (ua.includes(' line/')) {
    return isIOS
      ? 'is_line_ios'
      : isAndroid
      ? 'is_line_android'
      : 'is_line_unknown';
  }

  // iOS Safari|Twitter|Slack|Discord|etc
  if (isIOS && /safari\/[0-9.]+$/.test(ua)) {
    return 'maybe_safari_ios';
  }

  // Android Chrome|Twitter|Slack|Discord|etc
  if (isAndroid && ua.includes('chrome') && /safari\/[0-9.]+$/.test(ua)) {
    return 'maybe_chrome_android';
  }

  return null;
}

例えば、

const result = detectInAppBrowser(window.navigator.userAgent);

if (result.startsWith('is_facebook_')) {
  console.log('Facebook');
  if (result.endsWith('_ios')) {
    console.log('のiOS版');
  } else if (result.endsWith('_android')) {
    console.log('のAndroid版');
  }
   console.log('ですね');
}

とすれば、FacebookのiOS版ですねなどを出力できます。

参考

Discussion