检测页面是否在 JavaScript 中的 WKWebView 中加载
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28795476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detect if page is loaded inside WKWebView in JavaScript
提问by andr111
How can I reliably detect using javascript that a page is loaded inside a WKWebView? I'd like to be able to detect these scenarios:
如何使用 javascript 可靠地检测页面已加载到 WKWebView 中?我希望能够检测到这些场景:
- iOS & WKWebView
- iOS & Safari
- not iOS
- iOS & WKWebView
- iOS 和 Safari
- 不是 iOS
There is a similar question about UIWebView here. But it's quite old and I'm not sure if same still applies to WKWebView.
有一个关于UIWebView的一个类似的问题在这里。但它已经很旧了,我不确定 WKWebView 是否仍然适用。
采纳答案by Justin Michael
You can check for the existence of window.webkit.messageHandlers
which WKWebKit uses to receive messages from JavaScript. If it exists, you're inside a WKWebView
.
您可以检查是否存在window.webkit.messageHandlers
WKWebKit 用于接收来自 JavaScript 的消息。如果它存在,你就在一个WKWebView
.
That combined with a simple user agent check should do the trick:
结合简单的用户代理检查应该可以解决问题:
var iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false);
var isWKWebView = false;
if (window.webkit && window.webkit.messageHandlers) {
isWKWebView = true;
}
回答by hexalys
The accepted answer doesn't work as tested using the WKWebView vs UIWebView app
接受的答案在使用WKWebView vs UIWebView 应用程序测试时不起作用
As the article mentions, the only HTML5 feature difference is IndexedDB support. So I'd go for a more reliable pattern with:
正如文章所提到的,唯一的 HTML5 功能区别是对 IndexedDB 的支持。所以我会选择一个更可靠的模式:
if (navigator.platform.substr(0,2) === 'iP'){
//iOS (iPhone, iPod or iPad)
var lte9 = /constructor/i.test(window.HTMLElement);
var nav = window.navigator, ua = nav.userAgent, idb = !!window.indexedDB;
if (ua.indexOf('Safari') !== -1 && ua.indexOf('Version') !== -1 && !nav.standalone){
//Safari (WKWebView/Nitro since 6+)
} else if ((!idb && lte9) || !window.statusbar.visible) {
//UIWebView
} else if ((window.webkit && window.webkit.messageHandlers) || !lte9 || idb){
//WKWebView
}
}
You may ask: Why not using the UserAgent? That's because Android browsers use it as settings! So, we should never trust any UAs. Only browser features and property checks as such.
你可能会问:为什么不使用 UserAgent?那是因为 Android 浏览器使用它作为设置!所以,我们永远不应该相信任何 UA。只有浏览器功能和属性检查等。
Also I noticed that the QuickTime
plugin was always loaded as part of Older Safari and other Browsers in UIWebView. But the plugin is no longer present in WKWebView. So you can use the QuickTime
plugin presence as an extra check.
我还注意到该QuickTime
插件总是作为 UIWebView 中的 Older Safari 和其他浏览器的一部分加载。但是该插件不再存在于 WKWebView 中。所以你可以使用QuickTime
插件的存在作为额外的检查。
9/23/16 Edit: I adjusted the code for Safari 10 which no longer allowed the sole idb check to be reliable, as mentioned by @xmnboy. To discard Safari 10, it checks for the old webkit engine bug, which only applied until Safari 9.2; and i use a window.statusbar.visible
fallback which appears to be a reliable indicator signal after a few comparison tests between iOS 9 and 10. (please check though)
2016 年 9 月 23 日编辑:如@xmnboy 所述,我调整了 Safari 10 的代码,该代码不再允许唯一的 idb 检查可靠。为了放弃 Safari 10,它会检查旧的 webkit 引擎错误,该错误仅适用于 Safari 9.2;window.statusbar.visible
在 iOS 9 和 10 之间进行了几次比较测试后,我使用了一个后备,这似乎是一个可靠的指标信号。(请检查)
回答by xmnboy
Given the change in behavior to the UIWebView that was introduced by Apple in iOS 10, here's a new answer that combines the original response by @Justin-Michael and the follow-up favorite by @hexalys.
考虑到 Apple 在 iOS 10 中引入的 UIWebView 的行为变化,这里有一个新的答案,它结合了@Justin-Michael 的原始回复和@hexalys 的后续回复。
var isWKWebView = false ;
if( navigator.platform.substr(0,2) === 'iP' ) { // iOS detected
if( window.webkit && window.webkit.messageHandlers ) {
isWKWebView = true ;
}
}
It turns out that Justin's answer was really the better feature detection mechanism, because it works for both iOS 9 and iOS 10.
事实证明,贾斯汀的答案确实是更好的功能检测机制,因为它适用于 iOS 9 和 iOS 10。
No telling what happens when we get to iOS 11. :-)
不知道当我们到达 iOS 11 时会发生什么。:-)
Qualification:this test will work if you are using the official Cordova WKWebView pluginto build your webview app, because that plugin does initialize the addScriptMessageHandler
method, as noted by @hexalys in the comments to this post. That mechanism is being used by Cordova to define a new JS to native bridgewhen the WKWebView plugin is present.
资格:如果您使用官方 Cordova WKWebView 插件来构建您的 webview 应用程序,则此测试将起作用,因为该插件确实初始化了该addScriptMessageHandler
方法,如@hexalys 在此帖子的评论中所述。当 WKWebView 插件存在时,Cordova 正在使用这种机制来定义一个新的JS 到本机桥接器。
Search for addScriptMessageHandler
in that plugin repoand see the very end of the ios-wkwebview-exec.js
filein that repo for some implementation details (or search for the string window.webkit.messageHandlers
in that file).
搜索addScriptMessageHandler
在该插件回购,看到的最后的ios-wkwebview-exec.js
文件在回购的一些实施细则(或搜索字符串window.webkit.messageHandlers
在该文件)。
回答by Chung-Hsien Chang
It seems that because of the latest iOS Chrome using WKWebView as rendering engine, Chrome is detected as WKWebView. ua.indexOf('CriOS') !== -1 will helps to distinguish Chrome from WKWebView in App.
似乎是因为最新的 iOS Chrome 使用 WKWebView 作为渲染引擎,Chrome 被检测为 WKWebView。ua.indexOf('CriOS') !== -1 将有助于在应用程序中区分 Chrome 和 WKWebView。
回答by Jarir
In iOS, you could add this code to establish communication between javascript and objective-c:
在 iOS 中,您可以添加以下代码来建立 javascript 和 Objective-c 之间的通信:
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKUserContentController *controller = [[WKUserContentController alloc] init];
[controller addScriptMessageHandler:self name:@"javascript_observer"];
configuration.userContentController = controller;
...
...
webview = [[WKWebView alloc] initWithFrame:... configuration: configuration];
In javascript, you could test the connection like this:
在 javascript 中,您可以像这样测试连接:
if ( window.webkit != undefined ){
//javascript is running in webview
}