Avec l’arrivée officielle de l’iPhone en France, il est temps de s’intéresser à la bête et de voir si elle est compatible avec notre framework web favori. Dans cet article, nous verrons quelques indications pour parvenir à générer un contenu optimisé pour iPhone dans nos applications Rails.
Il y a quelques temps, j’ai eu la chance de mettre la main sur un iPhone et je suis très vite tombé amoureux de l’engin: malgré l’écran de (relativement) petite taille par rapport à celui d’un ordinateur classique, le browser Safari est particulièrement fabuleux et ouvre de nouvelles perspectives au surf mobile. C’était donc pour moi un devoir d’essayer de faire tourner une application Rails dessus; voici donc quelques conseils pour ce faire.
iPhoney
Tout d’abord, si vous développez sur OSX, téléchargez vite iPhoney: il s’agit d’une petite application qui simulera l’apparence de votre site dans le navigateur Safari 320×480 pixels de l’iPhone. Cela vous permettra de voir immédiatement le résultat de vos développements sans devoir systématiquement faire un refresh sur votre iPhone (voire carrément d’en acheter un, si vous êtes dans un pays où l’iPhone n’est pas encore disponible… hum hum).
MIME-type iPhone
Créez un alias MIME-type pour l’iPhone en utilisant les initialiseurs de Rails 2 :
# config/initializers/mime_types
Mime::Type.register_alias "text/html", :iphone
Détection de l’iPhone
La recommandation officielle d’Apple, lors de la détection d’un navigateur client de type iPhone, est de non pas rediriger vers une version du site faite pour iPhone, mais plutôt de montrer le site dans sa version “normale” en proposant un lien vers la version iPhone. La raison pour cela est que les utilisateurs d’iPhone sont habitués à naviguer sur l’entièreté du web et ne veulent être contraint à n’avoir accès qu’à un sous-ensemble limité.
Pour effectuer la détection de l’iPhone, Apple recommande de chercher la chaîne de caractères “Mobile Safari” (et non “iPhone” ou “iPod Touch”, ceci afin de rester ouvert à d’éventuels autres appareils dans le futur). Une solution est donc d’ajouter à votre application_helper.rb la méthode suivante:
# Détection d'une requête iPhone ou iPod touch (navigateur Mobile Safari)
def iphone_user_agent?
request.env["HTTP_USER_AGENT"] &&
request.env["HTTP_USER_AGENT"][/(Mobile\/.+Safari)/]
end
Dans votre vue, montrez un message pour les navigateurs iPhone pointant vers la version adaptée:
<% if iphone_user_agent? -%>
<div class="message">
<p>
Vous naviguez à partir d'un iPhone?
<a href="http://iphone.monsite.com/">Utilisez la version optimisée</a>.
</p>
</div>
<% end -%>
Sous-domaine iPhone
Donc, plutôt que de forcer l’adaptation du site à l’iPhone, nous proposons cette option via un sous-domaine alternatif (avec un lien retour au cas où l’utilisateur voudrait malgré tout voir le site “normal”). A vous de configurer votre serveur DNS pour permettre cette possibilité. Pour le développement en local, une solution est de simplement éditer votre fichier /etc/hosts et y rajouter la référence à ce nom de domaine fictif:
127.0.0.1 iphone.monsite.com
Ajustement du format à l’iPhone
Ces quelques méthodes privées permettent d’automatiquement appliquer le format pour iPhone si celui-ci est détecté:
class ApplicationController < ActionController::Base
before_filter :adjust_format_for_iphone
private
# Utiliser le format iPhone si la requête est faite
# au sous-domaine iphone.monsite.com
def adjust_format_for_iphone
request.format = :iphone if iphone_request?
end
# Renvoie true pour les requêtes vers requests to iphone.monsite.com
def iphone_request?
return (request.subdomains.first == "iphone" ||
params[:format] == "iphone")
end
end
Gestion de l’orientation
L’iPhone permet aux utilisateurs de naviguer sur le web en mode portrait comme en mode paysage. Cette fonctionnalité peut avoir un énorme impact sur votre application. En effet, vous pourriez d’une part vouloir adapter vos CSS en fonction de l’orientation (position des menus, des publicités, etc.), et d’autre part, utiliser Ruby pour suivre quelle orientation vos utilisateurs préfèrent.
Pour l’instant, il n’y a malheureusement pas de solution élégante au problème. Une solution est de sonder de manière régulière l’orientation actuelle de l’iPhone via JavaScript, et réagir en cas de changement. Par exemple, le code suivant vérifie 5 fois par seconde l’orientation actuelle et met à jour un attribut de la balise body appelé “orientation” :
currentWidth = 0;
window.setInterval( 'checkMyOrientation()', 200 );
function checkMyOrientation() {
if (window.innerWidth != currentWidth) {
currentWidth = window.innerWidth;
var myOrientation = (currentWidth == 320) ? "upright" : "landscape";
document.body.setAttribute("orientation", myOrientation);
}
};
Cet attribut “orientation” n’est pas un attribut standard mais cela est permis dans les CSS. Il est ainsi possible de définir en CSS un look tout à fait différent suivant l’orientation, avec les sélecteurs body[orientation="upright"] et body[orientation="landscape"], et ce entièrement du côté client.
Si, par contre, les changements à faire sont plus conséquents et nécessitent l’intervention du serveur, libre à vous de remplacer la ligne mettant à jour l’attribut “orientation” par un appel AJAX.
Empêcher le zoom
Même si c’est, en quelque sorte, imposer une contrainte sur l’expérience utilisateur de votre application, il est possible que vous souhaitiez désactiver le zoom disponible sur Mobile Safari. Cela peut servir, par exemple, si vous souhaitez rendre aussi discret que possible le côté “page web” de votre application et simuler le comportement d’une application iPhone native. Pour désactiver le zoom, utilisez user-scalable=no :
<meta name="viewport" content="user-scalable=no" />
Liens vers un numéro de téléphone
En principe, l’iPhone détecte automatiquement les numéros et les convertit si nécessaire, ce qui vous permet d’appeler un numéro indiqué sur une page rien qu’en cliquant dessus. Evidemment, l’iPhone ne reconnaît pas tous les formats de numéros de téléphone et il est possible que vous vouliez permettre un appel via un lien sans afficher platement le numéro sur la page.
Pour ce faire, le format “tel:” est reconnu par Mobile Safari; il fonctionne de la même manière que le fameux “mailto:”, et vous permet d’appeler un numéro en cas de clic tout en permettant de rendre le lien plus descriptif: <a href="tel:33612345678">Pierre</a>.
Utilisation d’iUI et création de vues pour iPhone
Pour conclure, parlons du framework iUI, basé sur le travail de Joe Hewitt, qui simplifie énormément le développement d’applications web pour iPhone. Il suffit d’inclure les fichiers JavaScript et CSS d’iUI et suivre certaines conventions dans les vues pour simuler un comportement iPhone natif, tels que les menus coulissants et les rechargements AJAX.
Rails 2 rend triviale la création de vues différentes en fonction du format, y compris les layouts. Voici un exemple de layout pour iPhone (app/views/layouts/application.iphone.erb) qui utilise les conventions pour iUI:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta id="viewport" name="viewport" content="width=320;
initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<title><%= @page_title -%></title>
<%= stylesheet_link_tag 'iui' %>
<%= javascript_include_tag 'iui' %>
</head>
<body>
<div class="toolbar">
<h1 id="pageTitle"></h1>
<a id="backButton" class="button" href="#"></a>
</div>
<%= yield %>
</body>
</html>
En ce qui concerne les vues, il faut s’adapter aux conventions d’iUI. Les liens “normaux” sont chargés via AJAX et provoquent un “glissement latéral” de la page vers la vue de destination. Il est possible de spécifier target="_self" pour remplacer la page entière, ou target="_replace" pour remplacer l’élément avec la réponse AJAX.
Exemple:
index.iphone.erb
<ul title="Bienvenue" selected="true">
<li><%= link_to 'Action exemple', example_path %></li>
<li><%= link_to 'Déconnexion', logout_path, :method => :delete,
:target => '_self' %></li>
</ul>
show.iphone.erb
<div class="panel" title="Exemple" selected="true">
<h2>Contenu exemple</h2>
<p>Voici du contenu</p>
</div>
Attention: comme iUI charge toujours le contenu via AJAX, le layout ne doit être chargé que pour la première page. Toutes les requêtes suivantes doivent utiliser render :layout => false (sauf dans le cas particulier target="_replace" qui charge une nouvelle page). Si vous observez des bizarreries dans le rendu de certaines pages, c’est probablement à cause de cette particularité.
respond_to do |format|
format.iphone do # action.iphone.erb
render :layout => false
end
end
Bien entendu, rien ne vous oblige à utiliser iUI et dans pas mal de cas, ce framework s’avèrera trop restrictif. Mais si vous aimez le “look’n’feel” de l’interface proposée sur l’iPhone, iUI vous permet d’avoir celui-ci sur votre site en vous épargnant tous les petits détails techniques.
Resources
Cet article est essentiellement une combinaison/traduction des ressources anglophones suivantes:
- iPhone on Rails – Creating an iPhone optimised version of your Rails site using iUI and Rails 2
- iPhone subdomains with Rails
- iPhone Web Development with Ruby on Rails
Les pages suivantes vous donneront des informations additionnelles:
1 Commentaire
Très bon article, surtout iUI que je ne connaissais pas. Sinon, pour donner un retour d’utilisateurs, j’ai développé une partie de mon application pour safari mobile et équipé les infirmiers d’iPodTouch (c’est un logiciel médical) pour la saisie d’infos au lit du malade, et bien ils sont ravis de l’ergonomie de l’appareil. En plus, avec Rails et sa gestion des formats, ce fut facile d’adapter les vues.