如果网站在 iPad 的 Safari 内或应用程序 WebView 内运行,有没有办法用 JavaScript 检测?
这使用了 window.navigator.userAgent
和 window.navigator.standalone
的组合。它可以区分与 iOS Web 应用程序相关的所有四种状态:safari(浏览器)、独立(全屏)、uiwebview 和非 iOS。
演示:http://jsfiddle.net/ThinkingStiff/6qrbn/
var standalone = window.navigator.standalone,
userAgent = window.navigator.userAgent.toLowerCase(),
safari = /safari/.test( userAgent ),
ios = /iphone|ipod|ipad/.test( userAgent );
if( ios ) {
if ( !standalone && safari ) {
//browser
} else if ( standalone && !safari ) {
//standalone
} else if ( !standalone && !safari ) {
//uiwebview
};
} else {
//not iOS
};
用户代理
在 UIWebView 中运行
Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/98176
在 iPad 上的 Safari 中运行
Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B176 Safari/7534.48.3
在 Mac OS X 上的 Safari 中运行
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.5 Safari/534.55.3
在 Mac OS X 上的 Chrome 中运行
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.151 Safari/535.19
在 Mac OS X 上的 FireFox 中运行
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0
检测码
var is_uiwebview = /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(navigator.userAgent);
var is_safari_or_uiwebview = /(iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent);
UIWebView
和 Safari 在其用户代理中都有 Safari
Version
而不是 Safari
的测试对我有用。
Version
的含义?您是否将 var is_uiwebview
行中的 Safari
替换为 Version
?
我认为您可以只使用User-Agent
。
更新
使用 iPhone Safari 浏览的页面
Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7
我将尝试使用 UIWebView
Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Mobile/8B117
不同之处在于 Safari 显示的是 Safari/6531.22.7
解决方案
var isSafari = navigator.userAgent.match(/Safari/i) != null;
Safari/.....
本身
我已经尝试了所有这些解决方案,但在我的情况下都不起作用,
我将在 Telegram 中检测 Webview。我认为它使用 SFSafariViewController
。
我注意到 Safari 应用程序将所有电话样式文本更改为带有“tel:”前缀的链接,但 webview 没有。
所以,我使用了它。
在这里测试它: jsfiddle
<!DOCTYPE html>
<html>
<head></head>
<body>
<ul id="phone" style="opacity:0">
<li>111-111-1111</li>
</ul>
</body>
</html>
<script>
var html = document.getElementById("phone").innerHTML;
if (navigator.platform.substr(0,2) === 'iP') {
if (html.indexOf('tel:') == -1)
alert('not safari browser');
else
alert('safari browser');
}
else
alert('not iOS');
</script>
navigator.platform === 'MacIntel'
。这尤其会影响 iPadOS 13 Mobile Safari,因为它默认使用桌面模式。
是的:
// is this an IPad ?
var isiPad = (navigator.userAgent.match(/iPad/i) != null);
// is this an iPhone ?
var isiPhone = (navigator.userAgent.match(/iPhone/i) != null);
// is this an iPod ?
var isiPod = (navigator.userAgent.match(/iPod/i) != null);
请注意,此方法不适用于 iOS 10 及更早版本。
在 2018 年春季,没有一个建议的方法对我有用,所以我想出了一种新方法(不是基于 userAgent):
const hasValidDocumentElementRatio =
[ 320 / 454 // 5, SE
, 375 / 553 // 6, 7, 8
, 414 / 622 // 6, 7, 8 Plus
, 375 / 812 // X
, 414 / 896 // Xs, Xr
].some(ratio =>
ratio === document.documentElement.clientWidth /
document.documentElement.clientHeight
)
const hasSafariInUA = /Safari/.test(navigator.userAgent)
const isiOSSafari = hasSafariInUA && hasValidDocumentElementRatio // <- this one is set to false for webviews
https://gist.github.com/BorisChumichev/7c0ea033daf33da73306a396ffa174d1
欢迎您也为 iPad 设备扩展代码,我认为它应该可以解决问题。
适用于 Telegram、Facebook、VK 网页浏览。
Neoneye 的解决方案不再起作用(见评论)并且可以简化。另一方面,在 UA 中仅测试“Safari”的地址比 ios 手持设备要多得多。
这是我正在使用的测试:
var is_ios = /(iPhone|iPod|iPad).*AppleWebKit.*Safari/i.test(navigator.userAgent);
现在是 2022 年,Safari 版本是 15.4。以上解决方案都不适合我。 iOS 上有两个 webview 类:WKWebView 和 SFSafariViewController。 SFSafariViewController 与 Safari 具有相同的 userAgent。我想出的解决方案依赖于在 Mobile Safari 上如何处理 height: 100vh
。 100vh 是设备屏幕高度,而不是文档可见高度。
有关更多信息,请参阅:
https://developers.google.com/web/updates/2016/12/url-bar-resizing
https://bugs.webkit.org/show_bug.cgi?id=141832
https://github.com/bokand/URLBarSizing
因此,在 iOS 上,这样的功能会检测 WebView 模式。
function isWebView()
{
const htmlEl = document.getElementsByTagName('html')[0];
const bodyEl = document.getElementsByTagName('body')[0];
const oldHtmlHeight = htmlEl.style.height;
const oldBodyHeight = bodyEl.style.height;
htmlEl.style.height = "100vh";
bodyEl.style.height = "100%";
const webViewMode = document.documentElement.clientHeight === document.documentElement.scrollHeight;
// restore height
htmlEl.style.height = oldHtmlHeight;
bodyEl.style.height = oldBodyHeight;
return webViewMode;
}
尝试使用 IOS 13
function mobileDetect() {
var agent = window.navigator.userAgent;
var d = document;
var e = d.documentElement;
var g = d.getElementsByTagName('body')[0];
var deviceWidth = window.innerWidth || e.clientWidth || g.clientWidth;
// Chrome
IsChromeApp = window.chrome && chrome.app && chrome.app.runtime;
// iPhone
IsIPhone = agent.match(/iPhone/i) != null;
// iPad up to IOS12
IsIPad = (agent.match(/iPad/i) != null) || ((agent.match(/iPhone/i) != null) && (deviceWidth > 750)); // iPadPro when run with no launch screen can have error in userAgent reporting as an iPhone rather than an iPad. iPadPro width portrait 768, iPhone6 plus 414x736 but would probably always report 414 on app startup
if (IsIPad) IsIPhone = false;
// iPad from IOS13
var macApp = agent.match(/Macintosh/i) != null;
if (macApp) {
// need to distinguish between Macbook and iPad
var canvas = document.createElement("canvas");
if (canvas != null) {
var context = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (context) {
var info = context.getExtension("WEBGL_debug_renderer_info");
if (info) {
var renderer = context.getParameter(info.UNMASKED_RENDERER_WEBGL);
if (renderer.indexOf("Apple") != -1) IsIPad = true;
}
;
}
;
}
;
}
;
// IOS
IsIOSApp = IsIPad || IsIPhone;
// Android
IsAndroid = agent.match(/Android/i) != null;
IsAndroidPhone = IsAndroid && deviceWidth <= 960;
IsAndroidTablet = IsAndroid && !IsAndroidPhone;
message = ""
if (IsIPhone) {
message = "Device is IsIPhone"
}
else if (IsIPad) {
message = "Device is ipad"
} else if (IsAndroidTablet || IsAndroidPhone || IsAndroid) {
message = "Device is Android"
} else {
message = "Device is Mac || Windows Desktop"
}
return {
message: message,
isTrue: IsIOSApp || IsAndroid || IsAndroidTablet || IsAndroidPhone
}
}
const checkMobile = mobileDetect()
alert(checkMobile.message + " =====> " + checkMobile.isTrue)
我知道此代码将检查是否从添加到主屏幕的图标访问它:
if (window.navigator.standalone == true) {
//not in safari
}
但我不确定它在 UIWebView 中会如何反应。我能想到的唯一其他解决方案是获取用户代理或使用 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
并将您正在访问的页面的查询字符串替换为页面用来识别它正在从 Web 视图访问的内容。
上次我需要这个(只是为了 WebView 目的),我使用了这个检查:
function isIOS() {
return !/safari/.test( window.navigator.userAgent.toLowerCase()) || navigator.platform === 'iOS' || navigator.platform === 'iPhone';
}
我找到了一个简单的解决方案来检测 iPhone 或 iPad。这对我来说很好。
var is_iPad = navigator.userAgent.match(/iPad/i) != null;
var is_iPhone = navigator.userAgent.match(/iPhone/i) != null;
if(is_iPad || is_iPhone == true){
//perform your action
}
Working 15.02.19
在 iOS 上检测网络视图的另一种解决方案是检查 navigator.mediaDevices
的支持/存在。
if (navigator.mediaDevices) {
alert('has mediaDevices');
} else {
alert('has no mediaDevices');
}
在我的情况下,我不需要捕获所有 webview,但是那些不支持摄像头/麦克风输入的 webview(提醒:警报不会在 Webview 中触发,因此请确保在 dom 中更改某些内容以进行调试)
navigator.mediaDevices
,因此您不能在 HTTP 页面上使用此方法。
我不认为您可以在客户端 Javascript 中使用任何特定的东西,但是如果您可以控制原始 UIWebView 可以做什么,您可能需要考虑使用它生成的用户代理字符串,并在您的客户端Javascript呢?我知道有点 hack,但是,嘿……这个问题可能会为调整用户代理提供一些指导:
Change User Agent in UIWebView (iPhone SDK)
@ Sod,嗯,我没有答案,但我不相信你为什么要检查,因为,浏览器引擎是否它的 safari(浏览器)或应用程序将与它的 Webkit 相同,是的应用程序可以配置浏览器引擎功能,如, 应用程序是否要运行 JS 或 Display Image 等...
我相信,您必须检查浏览器是否支持 Flash 或浏览器是否显示图像的某些属性,或者您可能想检查屏幕大小,
Safari
。它在要求 .ics 文件的webcal://
协议方面表现不同