Javascript iOS 8错误-当设备从睡眠状态返回时,OnUpdateReady不再调用

Javascript iOS 8错误-当设备从睡眠状态返回时,OnUpdateReady不再调用,javascript,ios,web-applications,sleep,Javascript,Ios,Web Applications,Sleep,当运行Web应用程序的iOS 8设备(即从主屏幕上的快捷方式启动)从睡眠状态返回时,所有异步Web请求都无法触发OnUpdateReady回调 这个问题很容易重现——只需将下面的两个代码文件放在任何web服务器上并尝试一下 还有其他人遇到过这个问题吗?如果有,有什么解决办法吗 我发布这篇文章是为了让大家注意到iOS 8中的这个bug,它基本上毁了我所有的web应用程序——我们不得不建议不要升级到iOS 7之外。是的,我已经在Apple Bug Reporter上发布了这个问题,但我想已经很久没有

当运行Web应用程序的iOS 8设备(即从主屏幕上的快捷方式启动)从睡眠状态返回时,所有异步Web请求都无法触发OnUpdateReady回调

这个问题很容易重现——只需将下面的两个代码文件放在任何web服务器上并尝试一下

还有其他人遇到过这个问题吗?如果有,有什么解决办法吗

我发布这篇文章是为了让大家注意到iOS 8中的这个bug,它基本上毁了我所有的web应用程序——我们不得不建议不要升级到iOS 7之外。是的,我已经在Apple Bug Reporter上发布了这个问题,但我想已经很久没有人关注这些问题了

应用程序清单

CACHE MANIFEST
# 2014-09-24 - Test

CACHE:
default.html
default.html

<!DOCTYPE html>
<html manifest="app.manifest">
<head>
  <title>Test Harness</title>
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
  <meta name="HandheldFriendly" content="true" />
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black" />
  <script language="javascript" type="text/javascript">
    var Test = new function () {
      var _GetEnd = function (oResult) {
        var sResult = ': ' +
          ((oResult.Value === true)
            ? 'Success'
            : 'Failure<br>' + oResult.Reason) +
          '<br>';

        var oLog = document.getElementById('idLog');
        oLog.innerHTML = (new Date()) + sResult + oLog.innerHTML

        setTimeout(_GetBegin, 1000);
      };

      var _GetBegin = function () {
        var sURL = 'app.manifest';
        var hAsyncCallback = _GetEnd;

        try {
          var oRequest = new XMLHttpRequest();
          oRequest.onreadystatechange =
            function () {
              if (oRequest.readyState != 4) return;
              if (oRequest.status != 200) {
                hAsyncCallback({ Value: false, Reason: oRequest.responseText });
              } else {
                hAsyncCallback({ Value: true, Reason: null });
              }
            };
          oRequest.open('GET', sURL, true);
          oRequest.send(null);
        } catch (e) {
          alert('Critical Error: ' + e.message );
        }
      };

      this.Start = function () { _GetBegin(); }
    };
  </script>
</head>
<body onload="Test.Start();">
  <ol>
    <li>Put both app.manifest and default.html on a web server.</li>
    <li>Make sure this page is being launched from the Home screen as a web application.</li>
    <li>Press the sleep button while it is running.</li>
    <li>Press the wake button and unlock the phone to get back to this screen.</li>
    <li>Under iOS7x the page continues, under iOS8 the onreadystatechange never gets called again.</li>
  </ol>
  <div id="idLog"></div>
</body>
</html>

测试线束
var测试=新函数(){
var_GetEnd=函数(oResult){
var sResult=':'+
((oResult.Value==true)
“成功”
:“失败
”+或结果原因)+ “
”; var-oLog=document.getElementById('idLog'); oLog.innerHTML=(新日期())+sResult+oLog.innerHTML 设置超时(_GetBegin,1000); }; var_GetBegin=函数(){ var sURL='app.manifest'; var hAsyncCallback=\u GetEnd; 试一试{ var oRequest=newXMLHttpRequest(); oRequest.onreadystatechange= 函数(){ 如果(oRequest.readyState!=4)返回; 如果(oRequest.status!=200){ hAsyncCallback({Value:false,Reason:oRequest.responseText}); }否则{ hAsyncCallback({Value:true,Reason:null}); } }; 开放('GET',sURL,true); oRequest.send(空); }捕获(e){ 警报(“严重错误:”+e.message); } }; this.Start=函数(){u GetBegin();} };
  • 将app.manifest和default.html放在web服务器上
  • 确保此页面作为web应用程序从主屏幕启动
  • 在运行时按下睡眠按钮
  • 按下唤醒按钮并解锁手机,返回此屏幕
  • 在iOS7x下,页面继续,在iOS8下,onreadystatechange将不再被调用

  • 我也看到了同样的问题,尽管我的示例要简单得多。只需使用一个webclip应用程序

    
    setInterval(函数(){
    log(“Johnny Five Alive!:”+new Date());
    },1000);
    

    在页面上。检查控制台,睡眠唤醒后,不再有控制台输出。这在iOS7上运行得很好(我的实际应用程序是一个复杂的angularJS,我只是将问题归结为这个)。您对您的错误报告有任何回应吗?

    我们(针对AJAX)的解决方案是:

    • Detect iOS8(实际上8.0.2仍有此功能)(其他解决方案也请参见此项:)
    • 删除普通的EventListener,但保留onProgress
    。。。
    this.onProgress=函数(e)
    {
    var位置=e.位置| | e.加载;
    var total=e.totalSize | | e.total;
    风险值百分比=0.0;
    如果(总计!=0)
    {
    百分比=职位/总数;
    }
    如果(百分比==1){
    if(this.isIOS8()){
    恢复uuid.get(uuid,uid.bind(this.ios8ScriptReturn,this));
    }
    }
    }
    ...
    //当注入具有此UUID的脚本时,将调用此函数
    this.ios8ScriptReturn=函数(uuid,值){
    //然后我们创建一个更简单的非真实的
    this.xhr={};
    this.xhr.readyState=4;
    this.xhr.status=200;
    this.xhr.responseText=值;
    this.xhr.onreadystatechange=null;
    this.xhr.isFake=true;
    //伪国家技术
    此.onReadyStateChange();
    }
    
    • 向每个请求添加UUID
    if(this.isIOS8()){
    ajaxInfo.url+='&recoveryUUID='+ajaxInfo.uuid;
    }
    
    • 然后仍然执行XHR发送(实际上工作正常,服务器获取并发送回正常)
    • 服务器端将“结果”保存在数据库/文件中,UUID作为索引/文件名的一部分
    //检测是否需要保存结果,并将其保存到请求时
    如果(isset($\u GET['recoveryUUID'])){
    $uuid=$\u GET['recoveryUUID'];
    recoveryuid::post($uuid,$result\u json\u string);
    }
    
    • 在客户端上,创建一个小助手全局对象,该对象侦听代码注入并将它们重定向到onProgress处理程序
    var RecoveryUUID=(函数(\u根){
    函数recoveryuid(){
    this.callbacks={};
    }
    var proto=recoveryuid.prototype;
    proto.onload=null;
    proto.set=函数(uuid,值){
    log('RECOVERY UUID:Received DATA:'+UUID+'值:'+value');
    if(this.callbacks的类型[uuid]!=“未定义”){
    this.callbacks[uuid](uuid,value);
    删除此。回调[uuid];//自动删除
    } 
    如果(this.onload!=null){
    这个.onload(uuid,value);
    }
    var script=document.getElementById(“recoveryScript_uId”+uuid);
    script.parentElement.removeChild(脚本);
    }
    proto.getURL=函数(uuid){
    返回“http://”+window.location.hostname+”:8888/recoveryuid/index.php?uuid=“+uuid;
    }
    proto.get=函数(uuid,回调){
    var script=document.createElement(“脚本”);
    script.setAttribute(“id”、“recoveryScript”+uuid);
    setAttribute(“type”、“text/javascript”);
    script.setAttribute(“src”,this.getURL(uuid));
    if(回调类型!=“未定义”){
    this.callbacks[uuid]=回调;
    }
    document.getElementsByTagName(“head”)[0].appendChild(脚本);
    }
    返回recoveryuid;
    })();
    //全球-就这样注入的股票
    
        document.body.style.display='none';
        setTimeout( function() { document.body.style.display = 'block'; }, 1);