Обнаружение, если страница загружена внутри WKWebView в JavaScript
Как я могу надежно обнаружить с помощью javascript, что страница загружается внутри WKWebView? Я хотел бы иметь возможность обнаруживать эти сценарии:
- iOS и WKWebView
- iOS и Safari
- не iOS
Здесь есть аналогичный вопрос об UIWebView . Но он довольно старый, и я не уверен, что он применим и к WKWebView.
Ответы
Ответ 1
Вы можете проверить наличие window.webkit.messageHandlers
, которое WKWebKit использует для приема сообщений с JavaScript. Если он существует, вы находитесь внутри WKWebView
.
Это в сочетании с простой проверкой агента пользователя должно сделать трюк:
var iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false);
var isWKWebView = false;
if (window.webkit && window.webkit.messageHandlers) {
isWKWebView = true;
}
Ответ 2
Принятый ответ не работает как проверенный с помощью WKWebView vs UIWebView app
Как упоминается в статье, единственным отличием особенностей 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
}
}
Вы можете спросить: почему бы не использовать UserAgent? Это потому, что браузеры Android используют его в качестве настроек! Таким образом, мы никогда не должны доверять UA. Доступны только функции и свойства браузера.
Также я заметил, что плагин QuickTime
всегда был загружен как часть Старого Safari и других браузеров в UIWebView. Но плагин больше не присутствует в WKWebView. Таким образом, вы можете использовать присутствие плагина QuickTime
в качестве дополнительной проверки.
9/23/16 Редактирование: я скорректировал код для Safari 10, который больше не допускал, чтобы единственная проверка idb была надежной, как упоминалось @xmnboy. Чтобы отказаться от Safari 10, он проверяет наличие старой ошибки веб-кита, которая применяется только до Safari 9.2; и я использую резерв window.statusbar.visible
, который кажется надежным сигналом индикатора после нескольких сравнительных тестов между iOS 9 и 10. (пожалуйста, проверьте, хотя)
Ответ 3
Учитывая изменение поведения в UIWebView, которое было представлено Apple в iOS 10, вот новый ответ, который объединяет исходный ответ от @Justin-Michael и последующего фаворита от @hexalys.
var isWKWebView = false ;
if( navigator.platform.substr(0,2) === 'iP' ) { // iOS detected
if( window.webkit && window.webkit.messageHandlers ) {
isWKWebView = true ;
}
}
Оказывается, что ответ Justin был действительно лучшим механизмом обнаружения функции, потому что он работает как для iOS 9, так и для iOS 10.
Не сообщая, что произойдет, когда мы перейдем к iOS 11.: -)
Квалификация: этот тест будет работать, если вы используете официальный плагин Cordova WKWebView для создания своего веб-приложения, потому что этот плагин инициализирует метод addScriptMessageHandler
, как отметил @hexalys в комментариях к этому сообщению. Этот механизм используется Кордовой для определения нового JS для родного моста, когда присутствует плагин WKWebView.
Найти addScriptMessageHandler
в что плагин репо и увидеть самый конец файл ios-wkwebview-exec.js
в этом репо для некоторых деталей реализации (или найдите строку window.webkit.messageHandlers
в этом файле).
Ответ 4
Похоже, что из-за последнего iOS Chrome, использующего WKWebView в качестве механизма рендеринга, Chrome обнаруживается как WKWebView. ua.indexOf('CriOS')! == -1 поможет отличить Chrome от WKWebView в приложении.
Ответ 5
В 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];
В javascript вы можете проверить соединение следующим образом:
if ( window.webkit != undefined ){
//javascript is running in webview
}