【问题标题】:Determine if user navigated from mobile Safari确定用户是否从移动 Safari 导航
【发布时间】:2011-03-01 18:02:36
【问题描述】:

我有一个应用程序,我想根据用户的导航位置将用户重定向到不同的页面。

如果从网络剪辑导航,请不要重定向。 如果从移动 Safari 导航,请重定向到 safari.aspx。 如果从其他任何地方导航,请重定向到不可用的.aspx

我能够使用iPhone WebApps, is there a way to detect how it was loaded? Home Screen vs Safari? 来确定用户是否从网络剪辑导航,但我无法确定用户是否从 iPhone 或 iPod 上的移动 Safari 导航。

这是我所拥有的:

if (window.navigator.standalone) {
    // user navigated from web clip, don't redirect
}
else if (/*logic for mobile Safari*/) {
    //user navigated from mobile Safari, redirect to safari page
    window.location = "safari.aspx";
}
else {
    //user navigated from some other browser, redirect to unavailable page
    window.location = "unavailable.aspx";
}

【问题讨论】:

标签: javascript iphone mobile-safari web-clips


【解决方案1】:

请参阅https://developer.chrome.com/multidevice/user-agent#chrome_for_ios_user_agent - iOS 上的 Safari 和 iOS 上的 Chrome 的用户代理字符串非常相似:

Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60 Mobile/9B206 Safari/7534.48.3

Safari

Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543 Safari/419.3

看起来这里最好的方法是首先检查 iOS,就像其他答案所建议的那样,然后过滤使 Safari UA 独一无二的东西,我建议最好通过“是 AppleWebKit 而不是 CriOS ":

var ua = window.navigator.userAgent;
var iOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i);
var webkit = !!ua.match(/WebKit/i);
var iOSSafari = iOS && webkit && !ua.match(/CriOS/i);

【讨论】:

  • @fabricioflores c'est la vie :(
  • +1 涵盖所有规格的唯一答案。我只需将 iOS 测试正则表达式更改为 /iP(ad|hone)/i,这样您就不需要 or。
  • @sareed 我总是觉得能够正则表达式 iP(ad|od|hone) 非常令人满意
  • Stupid Opera on iOS 仍然会在上面的代码中传递 true,所以我将最后一行更改为: var iOSSafari = iOS && webkit && !ua.match(/CriOS/i) && !ua .match(/OPiOS/i);
  • 不错的答案。但是,当您可以使用 test() 时,为什么还要使用双重否定 (!!) 和 match?
【解决方案2】:

更新:这是一个非常古老的答案,我无法删除它,因为该答案已被接受。查看unwitting's answer below 以获得更好的解决方案。


您应该能够检查user agent 字符串中的“iPad”或“iPhone”子字符串:

var userAgent = window.navigator.userAgent;

if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i)) {
   // iPad or iPhone
}
else {
   // Anything else
}

【讨论】:

  • 我认为不是。与 Safari iOS 浏览器有何不同?我认为这个表达式不仅会排除 Safari,还会排除所有 iphone/ipad 浏览器。
  • 这不是正确的答案,因为如果我从 chrome for ios 访问它,它将返回 true
  • 这不起作用,因为用户现在可以在 iOS 上使用 Mobile Chrome 浏览,即使它不是 Mobile Safari,这仍然会返回 true。
  • 这不会检测用户是否正在使用移动 Chrome。与 Safari 相比,Chrome iOS 有一个非常古老的 javascript 引擎(由于 Apple 的政策),因此无法进行一些渲染。
  • 这不应被标记为正确答案,因为它包括在 iPhone 上运行的任何浏览器。该问题专门要求检测移动 safari。
【解决方案3】:

最佳做法是:

function isMobileSafari() {
    return navigator.userAgent.match(/(iPod|iPhone|iPad)/) && navigator.userAgent.match(/AppleWebKit/)
}

【讨论】:

  • 这也适用于 Chrome iOS :( stackoverflow.com/a/13808053/668157
  • 这也会检测移动 chrome。
  • 那我们应该如何区分 iOS Safari 和 iOS Chrome 呢?有什么想法吗?
  • 这两个正则表达式可以轻松组合
  • 这也匹配 Desktop Safari。
【解决方案4】:

合并了所有的答案和 cmets。 这就是结果。

function iOSSafari(userAgent) {
    return /iP(ad|od|hone)/i.test(userAgent) &&
      /WebKit/i.test(userAgent) &&
      !(/(CriOS|FxiOS|OPiOS|mercury)/i.test(userAgent));
}


// Usage:
// if iOSSafari(window.navigator.userAgent) { /* iOS Safari code here */ }

// Testing:
var iPhoneSafari = [
  "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1",
  "Mozilla/5.0 (Apple-iPhone7C2/1202.466; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543 Safari/419.3",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1",
  "Mozilla/5.0 (iPhone9,3; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1",
  "Mozilla/5.0 (iPhone9,4; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1",
];
console.log("All true:", iPhoneSafari.map(iOSSafari));

var iPhoneNotSafari = [
  "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.105 Mobile/15E148 Safari/605.1",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/13.2b11866 Mobile/16A366 Safari/605.1.15",
];
console.log("All false:", iPhoneNotSafari.map(iOSSafari));

【讨论】:

  • 我猜这也符合桌面 safari (WebKit)
  • @antoine129 不,它没有(在 OS X El Capitan 上测试)- regexzzzz 是 ANDed,我猜 Desktop Safari 从不发送 iP* ...
【解决方案5】:

掉落的代码只能找到移动 safari,其他什么都没有(除了 dolphin 和其他小型浏览器)

  (/(iPad|iPhone|iPod)/gi).test(userAgent) &&
  !(/CriOS/).test(userAgent) &&
  !(/FxiOS/).test(userAgent) &&
  !(/OPiOS/).test(userAgent) &&
  !(/mercury/).test(userAgent)

【讨论】:

  • 这是唯一一个在 iOS 上区分 Firefox 和 Opera 的。
【解决方案6】:

看到所有答案,这里有一些关于建议的正则表达式的提示:

  • AppleWebKit 也匹配桌面 Safari(不仅是移动设备)
  • 对于这样简单的正则表达式,无需多次调用.match,而更喜欢更轻的.test 方法。
  • g(全局)正则表达式标志无用,而 i(不区分大小写)可能有用
  • 不需要捕获(括号),我们只是测试字符串

我只是在使用它,因为获得移动版 Chrome 的 true 对我来说是可以的(同样的行为):

/iPhone|iPad|iPod/i.test(navigator.userAgent)

(我只是想检测设备是否是 iOS 应用的目标)

【讨论】:

  • 关于正则表达式的重要说明(一般而言),感谢您在此处指出这一点(大多数人都弄错了)!除了您的答案之外,现在还应该检查!window.MSStream 以及根据this answer 将Microsoft 的浏览器排除在另一个问题中。 !/CriOS/.test(navigator.userAgent) 是为那些希望按照 this answer 过滤掉 Chrome 的人准备的。
【解决方案7】:

这个正则表达式对我有用,干净简单:

const isIOSSafari = !!window.navigator.userAgent.match(/Version\/[\d\.]+.*Safari/);

【讨论】:

  • 如果宿主应用程序没有明确地将Safari 添加到自定义用户代理字符串中,这将不适用于嵌入式 WKWebView。
  • iPad Safari 现在默认是躺着的。
【解决方案8】:

实际上,检测移动 Safari 并没有灵丹妙药。有不少浏览器可能会使用mobile safari的user agent的关键字。也许你可以尝试特征检测并不断更新规则。

【讨论】:

  • 例如,在我的情况下没有。我想显示为 iOS+Chrome 制作的自定义智能横幅,但不在 iOS+Safari 上显示此横幅,因为 iOS+Safari 已经内置了智能横幅。
  • @JobaDiniz 我知道很多人只想在移动 safari 中做某事,而不是在其他浏览器中,我也是。但是,事实上,匹配“iPad”、“ iOS", "iPhone" .etc 并不意味着它们是移动 safari,也许它们是 iOS 的其他一些浏览器。比如中国的UC和QQ浏览器。所有这些浏览器都可能使用 safari 的核心,并且大多数行为与移动 safari 相同,但有些不是。糟透了。
  • 确实很烂。愚蠢的我曾希望 navigator.appname 会有所不同,所有 iOS 浏览器都是“Netscape”。然而,Safari 是唯一能够安装配置文件的设备,因此如果其他任何人获得 .mobileconfig,它会下载它并且看起来很愚蠢,因为它不知道哪个应用程序可以打开它......
【解决方案9】:

我知道这是一个旧线程,但我想与你们分享我的解决方案。

我需要检测用户何时从桌面 Safari 导航(因为我们正处于 2017 年中期,Apple 尚未对 input[type="date"] YET 提供任何支持...

所以,我为它制作了一个后备自定义日期选择器)。但仅适用于桌面版 Safari,因为该输入类型在移动版 Safari 中运行良好。所以,我做了这个正则表达式只检测桌面 Safari。我已经对其进行了测试,但它与 Opera、Chrome、Firefox 或 Safari Mobile 不匹配。

希望对你们中的一些人有所帮助。

if(userAgent.match(/^(?!.*chrome).(?!.*mobile).(?!.*firefox).(?!.*iPad).(?!.*iPhone).*safari.*$/i)){
  $('input[type="date"]').each(function(){
    $(this).BitmallDatePicker();
  })
}

【讨论】:

    【解决方案10】:

    我赞成@unwitting 的回答,因为它不可避免地让我前进。但是,当在 iOS Webview 中渲染我的 SPA 时,我需要对其进行一些调整。

    function is_iOS () {
        /*
            Returns (true/false) whether device agent is iOS Safari
        */
        var ua = navigator.userAgent;
        var iOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i);
        var webkitUa = !!ua.match(/WebKit/i);
    
        return typeof webkitUa !== 'undefined' && iOS && webkitUa && !ua.match(/CriOS/i);
    };
    

    主要区别在于,将webkit 重命名为webkitUa,以防止与用作SPA 和UIView 之间消息处理程序的根webkit 对象发生冲突。

    【讨论】:

    • 这行得通。 return typeof webkitUa !== 'undefined' && iOS && webkitUa && !ua.match(/CriOS/i);
    【解决方案11】:

    我一直在寻找这个答案,我记得我以前遇到过这个。

    用 JavaScript 在 iOS 上检测 Safari 最可靠的方法是

    if (window.outerWidth === 0) {
        // Code for Safari on iOS
    } 
    
    or 
    
    if (window.outerHeight === 0) {
        // Code for Safari on iOS
    } 
    

    由于某种原因,iOS 上的 Safari 为 window.outerHeight 属性和 window.outerWidth 属性返回 0。

    这适用于所有 iOS 版本上的所有 iPad 和 iPhone。其他所有浏览器和设备都可以正常使用此属性。

    不确定他们是否打算改变这一点,但目前它运作良好。

    【讨论】:

      【解决方案12】:
      function isIOS {
        var ua = window.navigator.userAgent;
        return /(iPad|iPhone|iPod).*WebKit/.test(ua) && !/(CriOS|OPiOS)/.test(ua);
      }
      

      【讨论】:

        【解决方案13】:
        var isApple = false;    
        if(/iPhone|iPad|iPod/i.test(navigator.userAgent)) {      
          isApple = true;
        }
        

        【讨论】:

        • 虽然此代码可能会为问题提供解决方案,但最好添加有关其工作原理/方式的上下文。这可以帮助未来的用户学习并将这些知识应用到他们自己的代码中。在解释代码时,您也可能会以赞成票的形式从用户那里获得积极的反馈。
        猜你喜欢
        • 2012-12-24
        • 2014-10-04
        • 2018-05-11
        • 2010-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-30
        相关资源
        最近更新 更多