如何检测iOS的webapp从后台切换回Safari?

如何构build一个能够监控页面何时获得焦点的网页,尤其是当Safari处于后台并且用户将Safari切换回前台时。

下面的代码在iPhone上切换到Safari时不会触发事件

<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不会触发事件。

所以我的问题仍然是:如何检测通过使用Safari浏览器中的iPhone的JavaScript的窗口接收焦点?

我相信计时器(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可能会因为内存不足而重新加载页面。

Page Visibility API可能会为这个问题提供解决scheme。 我猜这个API还没有在Mobile Safari中实现,至less我还没有find任何iOS实现的文档。 但是,Webkit Trunk已经实现了一个实现,因此未来的Mobile Safari版本有可能支持该实现。

根据您需要支持的内容,您需要各种不同的技术来检测页面何时可见。 由于浏览器供应商,浏览器版本,操作系统,在WebView / UIWebView / WKWebView等中运行,会导致变化

您可以使用此页面查看正在发生哪些事件。 我发现,要检测何时页面“唤醒”所有组合,我需要注册以下所有事件:

  • 窗口visibilitychange事件
  • 窗口焦点事件
  • 窗口页面显示事件
  • 启动一个定时器,看看定时器是否比预期的要长得多(当hibernate时定时器被iOS置入)。 即使在iOS9上,使用UIWebView的应用程序也不会触发visibilityChange事件(WKWebView正常)。

我也使用webkitRequestAnimationFrame,但我删除了,因为它可能会导致jank(AFAIK呈现引擎阻止调用主线程)。

试一试:

  • 转到另一个选项卡
  • locking屏幕,等待,解锁
  • 带来另一个应用程序的重点
  • 最小化浏览器

你可以看到哪些事件正在发生:

iOS:注意如果使用定时器来检测iOS UIWebView是否已经进入hibernate状态,则需要使用new Date.getNow()而不是使用performance.now()来测量差异。 这是因为当页面进入睡眠状态时, performance.now()停止计数时间也是iOS执行performance.now()的速度很慢…(另外:您可能能够测量页面睡眠的时间通过检测new Date.getNow()performance.now()的差异的差异性,在testing页面上查找!=)。

如果您使用的是UIWebView,那么有两种技术可以工作(您必须使用UIWebViewif才能支持iOS7应用程序)。 WKWebView具有visibilitychange事件,所以不需要解决方法。

==技术1。

当应用程序中发生applicationWillEnterForeground事件时,调用UIWebView stringByEvaluatingJavaScriptFromString来调用您的JavaScript pageAwakened()。

好处:干净,准确。

缺点:需要Objective-C代码。 被调用函数需要从全局范围访问。

==技术2。

使用webkitRequestAnimationFrame并检测时间延迟。

优点:仅限JavaScript。 适用于iOS7上的移动Safari。

下滑:丑陋和使用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(); }); 

由于问题是与移动Safari和它支持popstate事件,您可以使用此事件来检测用户回来

窗口上的焦点和模糊事件可以很好地检测浏览器是从后台还是从后台。 这对我在iOS8的Safari浏览器:

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

使用pageshowpagehide事件。

 <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