web-dev-qa-db-ja.com

iOSでHistory APIは壊れていますか? (ロケーションバーはpushStateで更新されません)

これは、これまで誰も気づかなかった私は信じられない、または私は何かが欠けているに違いないというカテゴリの下に提出します。

単純なwindow.history.pushState iOSでは、ユーザーのジェスチャーに応答しない限り、ロケーションバーは更新されません。状態自体はプッシュされます([戻る]ボタンボタンを押すとわかるように)。

これが、問題を再現するために思いつくことができる最も小さなテストケースです。

http://thelink.is/history-api-ios-bug

History APIをサポートするデスクトップブラウザでは、ロケーションバーのURLが毎秒/ 0、/ 1などに変化するはずです。 iOS – iPhone(iOS 4.3を実行)およびiPad(iOS 4.3.3を実行)でテスト済み–ロケーションバーは更新されませんが、[戻る]ボタンをクリックすると、以前の正しい場所が表示されます(テストケースでは404になります)これらのURLを処理するバックエンドロジックはありません)。

考え?回避策は?泣いて抱擁する肩?

更新:この問題はiOS 5で修正されました。

34
Aral Balkan

つまり、iOSが履歴APIに独自のセキュリティを追加しているということです。つまり、スクリプトを使用してURLを変更することはできません。 Aralの例にあるように、履歴APIがURLを変更できるのはユーザーアクションのみです(クリックなど)。

回避策は、URLでハッシュ(別名フラグメント識別子)を使用することです。

history.pushStateの代わりに、場所を変更します。

var i = 0;
var locationUpdateInterval = setInterval(function(){
  window.location.hash = i;
  i++;
}, 1000);   

IOSアプリでその場所が変更されたとき、またはアプリの特定のページ/パネルへのパーマリンクがある場合にイベントをキャプチャするには:

// named function on purpose for later
function hashchange() {
  var pageId = location.hash.substr(1); // drop the # symbol
  // do something with pageId
}

window.onhashchange = hashchange;

// onload - if there's a hash on the url, try to do something with it
if (location.hash) hashchange();

IOSでpushState/popStateを使用できないのはかなり残念ですが、ユーザーがアクションを開始しない限りフルスクリーンビデオをトリガーできないのと同じセキュリティです。 iOSでビデオまたはオーディオコンテンツをダウンロードする場合-スクリプトを作成することはできません。ユーザーが(何らかの方法で)開始する必要があります。

Android=に関するメモのように-問題はかなり似ているため、これはAndroidの回避策としても機能するはずです)。

デスクトップのサポートが必要な場合、ほとんどのブラウザーはonhashchangeをサポートしますが、そうだと思いますが、IEは背後に欠けているため、その悪質な部分をポリフィルすることができます(ただしjQueryが必要です。 。): http://benalman.com/projects/jquery-hashchange-plugin/

お役に立てば幸いです。

22
Remy Sharp

https://github.com/browserstate/history.js を使用すると、問題なく動作します。これにより、HTML5 History APIに関する他の多くのクロスブラウザーのバグも修正されます。

V1.7の時点で、これが解決するバグは次のとおりです。

  • History.jsは、次のブラウザのバグを解決します
    • HTML5ブラウザ
      • Chrome 8は、初期状態に戻るときに、正しい状態データを含まない場合があります
      • Safari 5、Safari iOS 4、Firefox 3および4は、ページにハッシュがロードされているときにonhashchangeイベントを発生させません
      • Safari 5およびSafari iOS 4は、他のブラウザーとは異なり、ハッシュが変更されたときにonpopstateイベントを発生させません
      • Safari 5とSafari iOS 4は、ハッシュがreplaceState呼び出し/ バグレポート に置き換えられると、正しい状態に戻りません。
      • Safari 5およびSafari iOS 4は、ビジー状態での状態変更の適用に失敗することがある/ バグレポート
      • Google Chrome 8,9,10およびRC 4より前のFirefox 4は、ページがロードされると常にonpopstateを起動します/ 推奨事項を変更
      • Safari iOS 4.0、4.1、4.2には動作するHTML5履歴APIがあります-ブラウザーの実際の戻るボタンは機能しませんが、HTML4ブラウザーとして扱います
      • HTML5ブラウザーは、実際にtitleおよびpushState呼び出しにreplaceState引数を使用していません
    • HTML4ブラウザー
      • MSIE 6,7やFirefox 2などの古いブラウザにはonhashchangeイベントがありません
      • MSIE 6および7は、指示された場合でもハッシュを適用しない場合があります(適用関数への2回目の呼び出しが必要)
      • Opera以外のHTML4ブラウザは、ハッシュがurlencodedでない場合、ハッシュを適用しない場合があります
    • すべてのブラウザ
      • 状態データとタイトルは、サイトを離れてから返されると保持されません(ページの更新を含む)
      • 州のタイトルがdocument.titleに適用されることはありません
2
balupton

(更新:Remyも回答したことを確認しました。代わりに、上記の彼の詳細な回答を読んでください。)

Remy 提供 この問題の回避策 Twitterで。

基本的に、location.hashを変更すると、ロケーションバーのアドレスが更新されます。ただし、これにより、履歴に別のエントリが作成されます(これは、私が達成しようとしていることには機能しません)。私が実装している回避策は、iOSのバグが修正されるまで、iOSではハッシュバンURLを使用し、他のプラットフォームでは通常のURLを使用することです。これは絶対に理想的ではありません。iOSのMobile SafariがChrome、Firefox、デスクトップのSafariのように動作することを願っています。

1
Aral Balkan

これが私が見つけたものです:

プッシュされた場所にハッシュ記号が含まれている場合、アドレスバーが更新されます。だからこれはうまくいくでしょう:

window.history.pushState(data, title, 'a/new/url#');

ただし、window.locationオブジェクトは更新されないため、プッシュされた場所が必要な場合は、プッシュされたURLを変数に保存し、window.locationの代わりにそれを使用する必要があります。

Safari for Androidでテスト済み。

1
Cref

私はちょっとうまくいくハックを見つけました。 history.pushStateの直後にハッシュを変更すると、ロケーションバーが更新されることがわかります。お気に入り:

        window.history.pushState(data, title, 'a/new/url');
        window.location.hash = 'new';

ロケーションバーを http://example.com/a/new/url#new に変更します。これは、ハッシュがそれ自体の履歴エントリになるため、別の問題を引き起こします。したがって、とにかくonHashChangeをリッスンする必要があります。

少し複雑ですが、ハッシュバングのURLを本当に嫌いで、非常に発言する人もいます。だからそれは価値があります。

0
Soska