Как обнаружить в веб-приложении iOS при переключении обратно в Safari из фона? - PullRequest
16 голосов
/ 11 января 2011

Как мне создать веб-страницу, которая может отслеживать, когда страница получает фокус, особенно когда Safari находится в фоновом режиме, а пользователь переключает Safari обратно на передний план.

Приведенный ниже код не срабатываетсобытие при переключении на Safari на iPhone

<html>
  <head>
    <script type="text/javascript">
      window.onfocus = function() { alert("onfocus"); };
    </script>
  </head>
  <body>

    Main text

  </body>
</html>

Согласно http://www.quirksmode.org/dom/events/index.html: iPhone Safari не запускает событие, когда окно получает фокус.

Итак, мой вопрос по-прежнему: как определить с помощью javascript на веб-странице в Safari для iPhone, что окно получает фокус?

Ответы [ 7 ]

13 голосов
/ 06 февраля 2011

Я считаю, что таймеры (setInterval ()) приостанавливаются, когда приложение переходит в фоновый режим.Вы можете сделать что-то вроде:

var lastFired = new Date().getTime();
setInterval(function() {
    now = new Date().getTime();
    if(now - lastFired > 5000) {//if it's been more than 5 seconds
        alert("onfocus");
    }
    lastFired = now;
}, 500);

Возможно, вам придется настроить эти временные интервалы в соответствии с вашими потребностями.

Но, скорее всего, если это было достаточно долго, чтобы потребовать обновления (несколько дней) Safari, вероятно, перезагрузит страницу, потому что ей не хватает памяти.

6 голосов
/ 05 февраля 2016

В зависимости от того, что вам нужно для поддержки, вам нужно множество различных методов, чтобы определить, когда страница становится видимой.Изменения происходят из-за поставщика браузера, версии браузера, ОС, работающих в WebView / UIWebView / WKWebView и т. Д.

Вы можете просмотреть, какие события происходят, используя эту страницу .Я обнаружил, что для определения того, когда страница «просыпается» во всех комбинациях, мне нужно было зарегистрировать все следующие события:

  • событие видимости окна
  • событие фокуса окна
  • событие окна просмотра страниц
  • запуск таймера и проверка того, занял ли таймер намного больше времени, чем должно быть (таймеры переводятся в спящий режим iOS при переходе в спящий режим).Приложение, использующее UIWebView, не запускает событие visibilityChange даже на iOS9 (WKWebView в порядке).

Раньше я также использовал webkitRequestAnimationFrame, но я удалил это, потому что это может вызвать джанк (AFAIK движок рендеринга делает для него блокирующий вызов основного потока).

Вещипопробовать:

  • Перейти на другую вкладку
  • Экран блокировки, подождать, разблокировать
  • Установить другое приложение на фокус
  • Свернуть браузер

Вы можете увидеть, какие события происходят:

  • в режиме реального времени, посмотрев журнал консоли (прикрепить отладчик).
  • в режиме реального времени на устройстве с помощьюиспользуя http://output.jsbin.com/rinece#http://localhost:80/ и просмотрите журнал, запрошенный как вызовы Ajax (используйте прокси-сервер или запустите небольшой сервер по адресу после # и введите тело в консоль).
  • посмотрите наЖурнал экрана и обратите пристальное внимание на время, зарегистрированное для каждой записи, чтобы увидеть, была ли запись зарегистрирована, например, событие скрытия visibilitychange может не произойти, когда страница действительно скрыта (если приложение находится в спящем режиме), но вместо этого ставится в очередь и происходит, когда страница перезапускается!!!

iOS: будьте осторожны, если вы используете таймер для определения того, перешел ли iOS UIWebView в спящий режим, вам нужно измерить разницу, используя new Date.getNow(), а не performance.now().Это связано с тем, что performance.now() перестает считать время, когда страница переводится в спящий режим, и iOS медленно реализует performance.now () ... (Кроме того: вы можете измерить количество времени, в течение которого страница спала, обнаруживразница между new Date.getNow() и performance.now(). Найдите! = на тестовой странице ).

Если вы используете UIWebView, то есть два метода, которые работают (вынеобходимо использовать UIWebView, если вы поддерживаете приложение iOS7).WKWebView имеет событие visibilitychange, поэтому обходные пути не требуются.

== Техника 1.

Когда в приложении происходит событие applicationWillEnterForeground, вызовите UIWebView stringByEvaluatingJavaScriptFromString, чтобы вызвать страницу JavaScriptAwakened ().

Преимущества: чистота, точность.

Недостаток: нужен код Objective-C.Вызываемая функция должна быть доступна из глобальной области видимости.

== Техника 2.

Используйте webkitRequestAnimationFrame и обнаруживать временную задержку.

Преимущества: только JavaScript.Работает для мобильного Safari на iOS7.

Недостаток: ужасный риск джанка и использования webkitRequestAnimationFrame - серьезный взлом.

// iOS specific workaround to detect if Mobile App comes back to focus. UIWebView and old iOS don't fire any of: window.onvisibilitychange, window.onfocus, window.onpageshow
function iosWakeDetect() {
    function requestAnimationFrameCallback() {
        webkitRequestAnimationFrame(function() {
            // Can't use timestamp from webkitRequestAnimationFrame callback, because timestamp is not incremented while app is in background. Instead use UTC time. Also can't use performance.now() for same reason.
            var thisTime = (new Date).getTime();
            if (lastTime && (thisTime - lastTime) > 60000) {    // one minute
                // Very important not to hold up browser within webkitRequestAnimationFrame() or reference any DOM - zero timeout so shoved into event queue
                setTimeout(pageAwakened, 0);
            }
            lastTime = thisTime;
            requestAnimationFrameCallback();
        });
    }
    var lastTime;
    if (/^iPhone|^iPad|^iPod/.test(navigator.platform) && !window.indexedDB && window.webkitRequestAnimationFrame) {    // indexedDB sniff: it is missing in UIWebView
        requestAnimationFrameCallback();
    }
}

function pageAwakened() {
    // add code here to remove duplicate events. Check !document.hidden if supported
};

window.addEventListener('focus', pageAwakened);
window.addEventListener('pageshow', pageAwakened);
window.addEventListener('visibilitychange', function() {
    !document.hidden && pageAwakened();
});
6 голосов
/ 22 июля 2012

API видимости страницы , вероятно, предложит решение этой проблемы.Я предполагаю, что этот API еще не был реализован в Mobile Safari, по крайней мере, я не нашел никакой документации для реализации iOS.Однако реализация была передана в магистраль Webkit, поэтому есть вероятность, что она будет поддерживаться будущими версиями Mobile Safari.

1 голос
/ 29 мая 2019

Я написал небольшую тестовую страницу, чтобы увидеть, какие события отправляются в окно на iOS.

Страница "Apple Web App поддерживает", поэтому вы можете сохранить ее на главном экране и протестировать в автономном режиме.

Вот эта страница: Тест событий окна

Код:

$('#btnClear').on('click', function() {
  $('#olEvents').empty();
});
var eventNames = [
  'load',
  'focus',
  'blur',
  'change',
  'close',
  'error',
  'haschange',
  'message',
  'offline',
  'online',
  'pagehide',
  'pageshow',
  'popstate',
  'resize',
  'submit',
  'unload',
  'beforeunload'
];
eventNames.forEach(function(eventName) {
  $(window).on(eventName, function(evt) {
    let now = new Date()
    $('#olEvents').append('<li>' + now.toTimeString() + ' - ' + evt.type + '</li>');
    // scroll to bottom div
    $(window).scrollTop($('#divBottom').offset().top);
  });
});
<!DOCTYPE html>
<!--
  Test of Window Events - displays all the events sent to document.window, except for 'scroll'
-->
<html lang="en">

<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, maximum-scale=1, minimum-scale=1, shrink-to-fit=no, user-scalable=no">

  <!-- apple web app meta tags -->
  <meta name="apple-mobile-web-app-title" content="WinEvents">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">

  <link rel="apple-touch-icon" sizes="180x180" href="./testing-180x180.png">

  <title>Test of Window Events</title>

  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">

</head>

<body>

  <div id="wrapper" class="container">

    <h1>Test of Window Events</h1>

    <p><button id="btnClear" class="btn btn-sm btn-outline-danger">Clear History</button></p>

    <h4>Events Caught:</h4>
    <div id="divEvents" style="border: 1px solid gray; min-height: 200px; padding: 2rem">
      <ol id="olEvents"></ol>
    </div>

    <div id="divBottom" style="height: 40px"></div>

  </div>
  <!-- /wrapper -->
  <!-- jquery-->
  <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
  <script>
  </script>
</body>

</html>
0 голосов
/ 25 августа 2015

События фокуса и размытия в окне хороши для определения, движется ли браузер к фону или обратно.Это работало для меня на iOS8 Safari:

window.addEventListener("focus", function(evt){
    console.log('show');
}, false);
window.addEventListener("blur", function(evt){
    console.log('hide');
}, false);
0 голосов
/ 21 ноября 2014

Используйте события pageshow и pagehide.

<script type="text/javascript">
        window.addEventListener("pageshow", function(evt){
            alert('show');
        }, false);
        window.addEventListener("pagehide", function(evt){
            alert('hide');
        }, false);
</script>

https://developer.apple.com/library/mac/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html

0 голосов
/ 17 мая 2014

Поскольку проблема связана с мобильным сафари, и оно поддерживает событие popstate, вы можете использовать это событие, чтобы определить, когда пользователь вернулся

...