Подтвердить что ты не робот

Как обнаружить в iOS webapp при возврате в Safari из фона?

Как создать веб-страницу, которая может отслеживать, когда страница получает фокус, особенно когда 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: Safari iPhone не запускает событие, когда окно получает фокус.

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

Что нужно попробовать:

  • Перейдите на другую вкладку
  • Блокировка экрана, ожидание, разблокировка
  • Привлечь другое приложение для фокусировки.
  • Свернуть браузер

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

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

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

Если вы используете UIWebView, тогда работают два метода (вы должны использовать UIWebViewif, поддерживающий приложение 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();
});

Ответ 3

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

Ответ 4

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

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

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

Код:

$('#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>

Ответ 5

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

window.addEventListener("focus", function(evt){
    console.log('show');
}, false);
window.addEventListener("blur", function(evt){
    console.log('hide');
}, false);

Ответ 6

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