Flash sur Android – Gérer les contraintes de taille, scale, full screen, rotation…

A partir d’Android 2.2 (FroYo), vos applications Flash / Flex pourront être lues directement dans le navigateur de votre mobile, grâce à l’application Flash Player 10.1 que vous pourrez télécharger par l’Android Market. Mais ce nouvel environnement n’est pas aussi facile à apprivoiser que votre environnement bureautique auquel vous êtes habitués. En effet, il faut maintenant gérer la rotation du téléphone, la mise à l’échelle automatique (scale) du navigateur Android, les différences de dpi, etc.

Pour vous aider, Allen Ellison (employée Adobe) a écrit un billet très complet que vous pouvez trouver sous une forme plus lisible sur le site de jeux en ligne Kongregate (coïncidence, c’est Kongregate qui avait sponsorisé mon premier jeu en Flash tout buggé à l’époque rotaZion !):

Adobe Flash Sizing Zen: Android Devices

Je vais traduire ici cet article pour nos amis francophones.

Introduction

Lorsque vous prenez votre contenu Flash (jeux, animations, applications Flex, …) et que vous voulez le faire tourner sur plusieurs plate-formes en utilisant Flash Player 10.1, il y a de nombreuses notions spécifiques que vous devez prendre en compte. Le plus important étant peut-être de vous assurer que votre contenu est à une taille correcte.

Il y a deux modes d’affichage supportés par Flash Player 10.1 sur environnements mobiles: embedded (embarqué dans une page web) et full screen (plein écran).  Adobe Air permet de faire des applications natives en dehors du navigateur et dispose d’une plus grande flexibilité (vous pouvez trouver plusieurs articles à ce sujet sur flex-tutorial, Air Android).

Mode Plein écran (Full Screen)

Quand le navigateur Android ouvre une page contenant du contenu Flash, il ne va jamais entrer automatiquement en mode plein écran. Plusieurs actions utilisateur peuvent cependant passer le contenu en plein écran:

  • Si le contenu utilise le mécanisme de passage en plein écran classique, celui que l’on peut trouver pour les applications bureautiques (les tags HTML object et embed contiennent la propriété allowFullScreen= »true » et qu’une action utilisation modifie le displayState du stage), alors le mode plein écran sera aussi lancé sur plate-formes mobiles. Toutes les restrictions de sécurité/fonctionnalités concernant le passage en plein écran classiques sont aussi appliquées sur plate-formes mobiles.
  • Si le tag HTML object contient le paramètre « fullScreenOnSelection« , alors le contenu sera lancé en plein écran quand l’utilisateur sélectionne le contenu (par une pression sur le contenu). L’utilisateur va recevoir une notification du passage en plein écran. Toutes les restrictions de sécurité/fonctionnalités concernant le passage en plein écran classiques sont aussi appliquées sur plate-formes mobiles.
  • Si l’utilisateur fait une pression longue sur le contenu (lorsqu’il n’est pas en mode plein écran), on lui proposera de passer le contenu en plein écran, peu importe si l’option allowFullScreen est à true ou non. Une pression longue en mode plein écran ne fait rien de spécial. Il n’y a aucune manière de désactiver ce comportement. Une fois en mode plein écran, toutes les restrictions de sécurité/fonctionnalités concernant le passage en plein écran classiques sont aussi appliquées sur plate-formes mobiles.

Une fois que l’utilisateur est sorti du mode plein écran, s’il sélectionne le contenu (même si fullScreenOnSelection= »true »), cela n’aura aucun effet. Pour avoir la possibilité de se mettre en plein écran à nouveau, l’utilisateur devra actualiser la page ou changer de page et revenir à celle ayant le contenu Flash.

A cause de ce comportement, il est recommandé aux jeux de se mettre en pause quand ils détectent une sortie du mode plein écran.

Le mode plein écran offre les bénéfices suivants:

  • Utilisation maximale de l’écran de l’utilisateur
  • Puisqu’une interaction utilisateur est nécessaire au passage en plein écran, vous êtes sur que votre contenu a le focus.
  • Vous pouvez bloquer l’écran en mode paysage (mais pas en portrait)
  • Vous êtes sûr que votre contenu est à la bonne taille, quelle que soit son orientation

Le mode plein écran a en revanche, les inconvénients suivants:

  • Vous ne pouvez pas accéder au clavier (physique ou virtuel) en mode plein écran (même restriction que pour Flash Player desktop)
  • Le contenu HTML ne sera pas affiché en plein écran (même si le code JavaScript sera toujours exécuté)

Mode embarqué (Embedded)

Par défaut, quand l’utilisateur navigue vers un URL qui contient au moins du contenu Flash, celui-ci est en mode « embarqué ». Il existe une variation de ce mode qui est souvent appelé « selected » ou « focused », correspondant à l’état dans lequel se trouve votre application quand votre utilisateur a effectué une pression sur la zone de contenu. Lorsque cela arrive, le contenu Flash va clignoter brièvement pour indiquer qu’il a reçu le focus.

Ce mode « selected/focused » a les avantages suivants par rapport à un simple état « embarqué »:

  • Une plus grande priorité par rapport à d’autres contenus Flash (en terme de mémoire par exemple)
  • Accès au clavier et au DPAD (Pad directionnel) / Trackball
  • Peut recevoir les « gestures » gérées par Flash Player 10.1

Bien que cela ne fonctionne pas encore au moment de l’écriture de cet article, vous pouvez sélectionner automatiquement votre contenu Flash (ce qui ne le fera pas aller en plein écran pour autant).

Quand ce sera supporté, vous pourrez faire:

document.getElementById("YourFlashMovie").focus();

Indiquer à votre page HTML que le contenu est adapté à du mobile

Une fois que l’utilisateur a passé l’animation en plein écran, la gestion de la taille de votre animation est bien plus simple. Mais tant que vous êtes en mode « embarqué », l’avoir à la bonne taille est assez technique.

Pour la déclaration de votre page HTML, l’équipe Flash Player recommande:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN" "http://www.w3.org/TR/xhtml-basic/xhtml- basic10.dtd">
<html xmlns="http://www.w3.org/19999/xhtml" lang="en" xml:lang="en">

<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 ...
</head>
</html>

pour les raisons suivantes:

  • Cela évite le transcoding Verizon (un grand opérateur téléphonique américain)
  • Cela évite de marquer (à tort) le contenu comme WAP
  • Cela utilise un norme XHTML donnée par le W3C
  • Notez que ce type de DTD exclus intentionnellement la gestion des frames HTML.

Bloquer la largeur (width) de votre viewport Android

Le navigateur Android va automatiquement vous permettre de remettre la page à l’échelle (zoom avant / arrière sur la page). Dans notre cas, vous ne voulez sûrement pas ce comportement qui va mettre à petite échelle tout votre contenu.

Pour bloquer ce comportement, cela se passe par la balise meta portant le nom « viewport »:

<meta name="viewport" content="target- densitydpi=device-dpi, width=device-width, user-scalable=no"/>

Vous pouvez aussi donner la taille en pixels:

<meta name="viewport" content="target- densitydpi=device-dpi, width=480, user-scalable=no"/>

Il faut noter que certains attributs du viewport sont ignorés par Android: initial-scale, minimum-scale and maximum-scale.

Ne pas autoriser le cache (environnement de développement)

Lorsque vous allez tester votre contenu Flash, vous voudrez sûrement que la page ne soit pas gardée en cache. Si vous ne voulez pas vider le cache manuellement, il existe une balise meta qui permet d’indiquer cela (attention, ne pas mettre en production):

<meta http-equiv="CACHE-CONTROL" content="NO-CACHE">

Utilisation de la librairie SWFObject 2

Pour vous simplifier l’intégration de votre contenu Flash (détection de version, ajout des tags nécessaires sous tous les navigateurs, …),  il est conseillé d’utiliser la célèbre librairie JavaScript SWFObject 2.

Vous pouvez la télécharger et consulter la documentation sur la page Google Code du projet:

SWFObject 2 pour intégration de contenu Flash

Pour intégrer votre contenu, une seule ligne de JS va suffir, par exemple:

swfobject.embedSWF("/swf-path/yourContent.swf", "theGame","480", "678", "10.1.61", "/swf/expressInstall.swf",flashvars, params, attributes);

Fixer la hauteur et la largeur

Vous pouvez utiliser du 480 x 678. Sur le Nexus One, c’est la taille de l’écran sans la place prise par l’interface du navigateur. Mieux vaut quand même laisser le navigateur gérer cela, pour ne pas avoir à prendre chaque mobile en cas par cas (width et height à 100%).

Suppression de la barre d’adresse

Vous pouvez supprimer la barre d’adresse en faisant en JS:

window.scrollTo(0,1);

Cela n’est pas recommandé car votre contenu Flash va occuper tout l’écran et écoutera tous les évènements. L’utilisateur ne pourra alors plus scroller pour récupérer sa barre d’adresse dans l’écran. Cela peut être déroutant / frustrant.

Détection de Flash Player

Si pour une certaine raison, vous n’utilisez pas la librairie SWFObject (voir plus haut), vous devrez gérer la présence de Flash Player tout seul comme ceci:

<noscript>
 <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="480" height="678" id="testStage">
  <param name="movie" value="testStage.swf" />
  <param name="quality" value="high" />
  <param name="bgcolor" value="#ffffff" />
  <param name="allowScriptAccess" value="sameDomain" />
  <param name="allowFullScreen" value="true" />
<!--[if !IE]>-->
  <object type="application/x-shockwave-flash" data="testStage.swf" width="480" height="678">
   <param name="quality" value="high" />
   <param name="bgcolor" value="#ffffff" />
   <param name="allowScriptAccess" value="sameDomain" />
   <param name="allowFullScreen" value="true" />
   <p> Either scripts and active content are not permitted to run or Adobe Flash Player version 10.1.0 or greater is
    not installed.</p>
   <a href="http://www.adobe.com/go/getflashplayer">
      <img src="http://www.adobe.com/images/shared/download_butto ns/get_flash_player.gif" alt="Get Adobe Flash
       Player" />
   </a>
  </object>
 </object>
</noscript>

Code pour le resize de la fenêtre (portrait / paysage)

Voici un code qui fait le resize du SWF à la fois en portrait et en paysage:

<script type="text/javascript">
	var iw = window.innerWidth;
	var ih = window.innerHeight; function resizeHandler()
	{ var scrolling = false;
	  iw = window.innerWidth;
      if(iw > 480) {
		window.scrollTo(0, 1); setTimeout("resizeSWF();",800);
		} else {resizeSWF();}
    }
	function resizeSWF()
    {
		document.getElementById("theGame").width = window.innerWidth;
			document.getElementById("theGame").height = window.innerHeight;
	}
	window.onresize = resizeHandler;
	window.onload = resizeHandler;
</script>

Ce code va laisser la barre d’adresse en mode portrait mais va la masquer en mode paysage.

Scaling et alignement

Dans les tags HTML object / embed, vous pouvez fixer le paramètre « scale » à une de ces valeurs:

  • showall: mode par défaut, s’assure que tout le contenu remplit la scène est visible
  • exactfit: déconseillé, étire le contenu
  • noborder: remplit toujours l’espace disponible mais pour pouvez perdre un peu de contenu sur les bords
  • noscale: Bien que non trivial au niveau de l’implémentation, c’est le meilleur réglage pour un contenu multi-screen. Cela demande cependant à avoir une mise en page évolutive pour garder un texte lisible, des icônes assez grands et de pouvoir s’afficher sur un maximum d’espace.

En ActionScript, vous pouvez accomplir la même chose dynamiquement en fixant la propriété « stage.scaleMode » à

  • StageScaleMode.SHOW_ALL
  • StageScaleMode.EXACT_FIT
  • StageScaleMode.NO_BORDER
  • StageScaleMode.NO_SCALE

Bien sûr, si vous utilisez SWFObject, vous pouvez passer le « scale » avec les autres paramètres:

var params = {	id: "flashcontent", name: "flashcontent",
	menu: "false", allowFullScreen: "true",
	fullScreenOnSelection: "true", scale:"showall",
	salign:"middle"};

Bloquer le contenu en mode paysage

La plupart des contenus sont neutres au niveau de l’orientation. Cependant pour certains contenus comme les jeux, on s’est basé sur un format plutôt desktop (paysage).

L’API d’orientation ne permet pas encore de faire cela mais c’est prévu pour une prochaine release de FP 10.1. En attendant, il y a une feinte qui vous permet d’avoir un contenu toujours en mode portrait. Il faut pour cela ajouter un objet Video sur votre scène, même sans l’utiliser. Quand (et seulement dans ce cas), vous passez en plein écran, votre contenu Flash va automatiquement se bloquer en position paysage:

private var video:Video = new Video();
private function MyClassicChessGame() {
	super();
	addChild(video);
}

Bloquer le contenu en mode portrait

Il n’y a pas d’équivalent de ce que l’on vient de voir pour le mode portrait. Cependant, vous pouvez avoir un résultat similaire en bloquant le stage en mode paysage avec une rotation de 90° de votre contenu (+ une translation, voir schéma):

sizing-zen_img1

En assumant que tout votre contenu visible est dans une Sprite appelée « game », vous aurez:

game.rotation=-90;
game.y=stage.fullScreenHeight;

Rappelez-vous cependant que le pad directionnel et le trackball vont envoyer des évènements comme en mode portrait. La flèche du haut devient alors la flèche de droite, etc.

Détection d’un changement d’orientation ou d’un passage en plein écran

Pour détecter une entrée/sortie du mode full screen, écoutez l’évènement FullScreenEvent.FULL_SCREEN:

import flash.events.FullScreenEvent;
function fullScreenChange(event:FullScreenEvent):void {
	if(event.fullscreen) {
		// entered full screen
    } else {
		// leaving full screen
	}
}
function init():void {
	stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenChange);
	...
}

Voir la documentation sur le passage Full Screen sur les Livedocs

Vous pouvez aussi détecter un passage en full screen en écoutant l’évènement RESIZE sur le stage. Vous pourrez ensuite déterminer l’orientation en comparant stage.stageWidth et stage.stageHeight.

Mettre votre contenu à la bonne taille

Le diagramme ci dessous représente les caractéristiques les plus communes pour les devices Android. Cela devrait vous donner une idée en terme de taille de police par exemple, pour vous assurer que votre contenu est lisible (cliquez sur l’image pour la voir en taille réelle):

sizing-zen_img2

Sur un Nexus One, la hauteur disponible pour le contenu du browser, en éliminant la place prise par le browser est de 678 pixels (sur 800). Si vous ne voulez pas changer le ratio de votre contenu quand il va en full Screen, alors votre animation devrait faire du 480×480 et il vous suffira de choisir du 406×678 pour la zone HTML embed/object (si vous ne voulez pas faire du 100%/100%) et « showall » comme « scale ». Vous allez perdre en qualité au niveau des textes et des images mais vous aurez un rendu parfait en mode plein écran. Pour être 100% certain, détectez le passage en full screen et forcez le contenu à être non-scaled et aligné dans le coin haut gauche (en ActionScript).

L’avantage d’être « pixel-perfect » est que vous n’aurez pas de comportement bizarre (ligne qui ne se dessine pas à cause d’un mauvais chevauchement…) mais les performances de Flash Player seront aussi meilleures car Flash Player n’aura pas à faire tout le travail de mise à l’échelle du contenu.

<noscript>
<object classid= »clsid:D27CDB6E-AE6D-11cf-96B8-444553540000″ width= »480″ height= »678″ id= »testStage »>
<param name= »movie » value= »testStage.swf » />
<param name= »quality » value= »high » />
<param name= »bgcolor » value= »#ffffff » />
<param name= »allowScriptAccess » value= »sameDomain » />
<param name= »allowFullScreen » value= »true » />
<!–[if !IE]>–>
<object type= »application/x-shockwave-flash » data= »testStage.swf » width= »480″ height= »678″>
<param name= »quality » value= »high » />
<param name= »bgcolor » value= »#ffffff » />
<param name= »allowScriptAccess » value= »sameDomain » />
<param name= »allowFullScreen » value= »true » />
<p> Either scripts and active content are not permitted to run or Adobe Flash Player version 10.1.0 or greater is
not installed.</p>
<a href= »http://www.adobe.com/go/getflashplayer »>
<img src= »http://www.adobe.com/images/shared/download_butto ns/get_flash_player.gif » alt= »Get Adobe Flash
Player » />
</a>
</object>
</object>
</noscript>