web-dev-qa-db-fra.com

Est-ce que l'historique API est cassé sur iOS? (La barre d'adresse ne se met pas à jour sur pushState)

En classant cette catégorie sous la catégorie «Je ne crois pas que personne ne l’a remarqué avant» ou «Je dois manquer quelque chose»: 

Il semble que si vous faites un simple window.history.pushState sur iOS, la barre d’emplacement ne se met à jour que si elle répond à un geste de l’utilisateur. L'état lui-même est poussé (comme vous pouvez le constater en appuyant sur le bouton du bouton de retour).

Voici le plus petit test-test que je pourrais trouver pour recréer le problème:

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

Sur un navigateur de bureau prenant en charge l’API d’historique, l’adresse URL de la barre d’emplacement doit être remplacée par/0,/1, etc., toutes les secondes. Sur iOS - testé avec iPhone (sous iOS 4.3) et iPad (sous iOS 4.3.3) - la barre d’emplacement ne se met pas à jour, mais appuyer sur le bouton Précédent vous amènera au bon emplacement précédent (qui sera 404 sur le cas de test depuis il n'y a pas de logique back-end pour gérer ces URL).

Pensées? Solutions de contournement? Une épaule pour pleurer et des câlins?

UPDATE: ce problème a été corrigé dans iOS 5.

34
Aral Balkan

En résumé, iOS a ajouté sa propre sécurité autour de l'API d'historique, ce qui signifie que vous ne pouvez pas utiliser de script pour modifier l'URL. Seule une action de l'utilisateur peut permettre à l'API d'historique de modifier l'URL - c'est-à-dire un clic - conformément à l'exemple d'Aral.

La solution de contournement consiste à utiliser un hachage (ou identificateur de fragment) sur l'URL.

Au lieu du history.pushState, nous allons simplement changer l'emplacement:

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

Pour capturer l'événement lorsque quelque chose change cet emplacement dans l'application iOS ou s'ils ont un lien permanent avec une page/un panneau particulier de votre application:

// 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();

Il est assez médiocre de ne pas pouvoir utiliser la variable pushState/popState sur iOS, mais c'est la même sécurité que de ne pas pouvoir déclencher la vidéo en plein écran à moins que l'utilisateur ne lance l'action, ce qui revient au même que le téléchargement de contenu vidéo ou audio sur iOS. ne peut pas le script, l'utilisateur doit le démarrer (d'une manière ou d'une autre).

Juste comme une note sur Android - les problèmes sont assez similaires, donc cela (devrait) également fonctionner comme une solution de contournement pour Android.

Si vous voulez un support de bureau, la plupart des navigateurs supportent onhashchange mais, oui, vous avez deviné, IE est en retard - vous pouvez donc polyfiller ce mauvais garçon (bien que nécessite jQuery ...): http://benalman.com/projects/jquery-hashchange-plugin/

J'espère que cela pourra aider.

22
Remy Sharp

Fonctionne bien pour moi lorsque je me sers de: https://github.com/browserstate/history.js - cela corrige également de nombreux autres problèmes de navigation entre plusieurs navigateurs avec l’API d’historique HTML5.

A partir de la v1.7, voici les bugs résolus:

  • History.js résout les bogues de navigateur suivants:
    • Navigateurs HTML5
      • Parfois, Chrome 8 ne contient pas les données d'état correctes lors du retour à l'état initial
      • Safari 5, Safari iOS 4 et Firefox 3 et 4 ne déclenchent pas l'événement onhashchange lorsque la page est chargée avec un hachage
      • Safari 5 et Safari iOS 4 ne déclenchent pas l'événement onpopstate lorsque le hachage a changé contrairement aux autres navigateurs.
      • Safari 5 et Safari iOS 4 ne parviennent pas à revenir à l'état correct une fois qu'un hachage est remplacé par un appel replaceState/ rapport de bogue
      • Il arrive que Safari 5 et Safari iOS 4 n’appliquent pas le changement d’état dans des conditions d’occupation/ rapport de bogue
      • Google Chrome 8,9,10 et Firefox 4 avant la RC seront toujours activés onpopstate une fois la page chargée/ modification de la recommandation
      • Safari iOS 4.0, 4.1, 4.2 ont une API d’historique HTML5 qui fonctionne. Bien que les boutons de retour des navigateurs ne fonctionnent pas, nous les traitons donc comme des navigateurs HTML4.
      • Aucun des navigateurs HTML5 n'utilise l'argument title pour les appels pushState et replaceState.
    • Navigateurs HTML4
      • Les anciens navigateurs tels que MSIE 6,7 et Firefox 2 n'ont pas d'événement onhashchange
      • MSIE 6 et 7 n’appliquent parfois pas de hachage même s’il leur a été demandé (nécessitant un second appel à la fonction apply)
      • Parfois, les navigateurs HTML4 n’appliquent pas le hachage lorsque celui-ci n’est pas urlencoded
    • Tous les navigateurs
      • Les données d'état et les titres ne persistent pas une fois le site quitté, puis renvoyés (actualisations de page incluses)
      • Les titres d'état ne sont jamais appliqués au document.title
2
balupton

(Mise à jour: Je viens de voir que Remy a aussi répondu - lisez plutôt sa réponse détaillée ci-dessus.) 

Remy a fourni une solution de contournement pour ce problème sur Twitter.

En gros, si vous modifiez le fichier location.hash, l'adresse de la barre d'emplacement est mise à jour. Cependant, cela crée une entrée distincte dans l'historique (ce qui ne fonctionne pas pour ce que j'essaie de réaliser). La solution de contournement que j'implémente consiste à utiliser des URL de hachage pour iOS et des URL ordinaires pour d'autres plates-formes jusqu'à la résolution du bogue iOS. Ce n'est certainement pas idéal et j'espère que Mobile Safari sur iOS commencera à se comporter comme Chrome, Firefox et Safari sur le bureau.

1
Aral Balkan

Voici ce que j'ai trouvé:

Lorsque l'emplacement poussé contient un symbole de hachage, la barre d'adresse sera mise à jour. Ainsi, cela fonctionnera:

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

Mais l'objet window.location ne sera pas mis à jour. Vous devez donc enregistrer l'URL transférée dans une variable et l'utiliser à la place de window.location si vous avez besoin de l'emplacement déplacé.

Testé sur Safari pour Android.

1
Cref

J'ai trouvé un hack qui fonctionne un peu. Il s'avère que si vous modifiez le hachage juste après history.pushState, la barre d'emplacement est mise à jour. Comme:

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

modifie la barre d'emplacement en http://example.com/a/new/url#new . Ce qui pose un autre problème car le hachage devient sa propre entrée d'historique. Vous aurez donc besoin d'écouter onHashChange quand même.

C'est un peu compliqué, mais il y a des gens qui détestent vraiment les url de hashbang et qui en parlent très fort. Donc ça vaut le coup.

0
Soska