Code JavaScript dans AIR

Flash Player 9 et les versions ultérieures, Adobe AIR 1.0 et les versions ultérieures

AIR apporte plusieurs modifications au comportement classique des objets JavaScript courants. La plupart de ces modifications sont destinées à simplifier l’écriture d’applications sécurisées dans AIR. Parallèlement à cela, ces différences de comportement impliquent que certains modèles de codage JavaScript courants et les applications Web existantes qui s’en servent risquent de ne pas fonctionner comme prévu dans AIR. Pour plus d’informations sur la correction de ces types de problèmes, voir la section Contournement des erreurs JavaScript liées à la sécurité .

Sandbox HTML

AIR place les différents contenus dans des sandbox distincts en fonction de leur origine. Les règles de sandbox respectent la stratégie de « même origine » implémentée par la plupart des navigateurs Web, de même que les règles applicables aux sandbox mises en œuvre par Adobe Flash Player. AIR propose en outre un nouveau type de sandbox d’ application conçu pour contenir et protéger le contenu de l’application. Pour plus d’informations sur les types de sandbox que vous êtes susceptible de rencontrer lors du développement d’applications AIR, voir Sandbox de sécurité .

L’accès à l’environnement d’exécution et aux API AIR est uniquement disponible pour les scripts HTML et JavaScript exécutés dans le sandbox de l’application. Parallèlement à cela, toutefois, les opérations d’évaluation et d’exécution dynamiques de code JavaScript, sous leurs diverses formes, sont largement limitées au sein du sandbox de l’application pour des raisons de sécurité. Ces restrictions s’appliquent que votre application charge réellement ou non des informations directement depuis un serveur. (Même le contenu des fichiers, les chaînes collées et les données saisies directement par l’utilisateur peuvent ne pas être fiables.)

L’origine du contenu d’une page détermine le sandbox associé au contenu. Seul le contenu chargé à partir du répertoire de l’application (le répertoire d’installation auquel le modèle d’URL app: fait référence) est placé dans le sandbox de l’application. Tout contenu chargé à partir du système de fichiers est placé dans le sandbox local avec système de fichiers ou le sandbox de sécurité approuvé localement , lequel permet d’accéder au contenu situé sur le système de fichiers local (mais pas au contenu distant) et d’interagir avec lui. Tout contenu chargé à partir du réseau est dirigé vers un sandbox distant correspondant à son domaine d’origine.

Pour qu’une page d’application puisse interagir librement avec un contenu situé dans un sandbox distant, vous pouvez la mapper au même domaine que le contenu distant. Si, par exemple, vous écrivez une application affichant des données de mappage provenant d’un service Internet, la page de l’application qui est chargée et qui présente le contenu émanant du service pourrait être mappée au domaine du service. Les attributs de mappage des pages dans un sandbox et un domaine distants sont de nouveaux attributs ajoutés aux éléments image et iframe HTML.

Pour permettre à un contenu d’un sandbox autre que d’application d’utiliser les fonctions d’AIR en toute sécurité, vous pouvez configurer un pont de sandbox parent. Pour permettre au contenu de l’application d’appeler des méthodes et des propriétés d’accès de contenu en toute sécurité dans d’autres sandbox, configurez un pont de sandbox enfant. La notion de sécurité évoquée ici signifie que le contenu distant ne peut pas obtenir accidentellement de références à des objets, des propriétés ou des méthodes exposés de manière non explicite. Seuls les objets anonymes, fonctions et types de données simples peuvent être transmis via le pont. Vous devez néanmoins éviter d’exposer explicitement des fonctions potentiellement dangereuses. Si, par exemple, vous avez exposé une interface qui autorisait le contenu distant à lire et à écrire des fichiers n’importe où sur le système d’un utilisateur, vous risquez de donner à ce contenu les moyens de nuire considérablement aux utilisateurs.

Fonction eval() JavaScript

L’utilisation de la fonction eval() est limitée au contenu du sandbox de l’application une fois le téléchargement de la page terminé. Dans certains cas, cette fonction peut servir à analyser en toute sécurité des données au format JSON, mais toute évaluation aboutissant à des résultats d’instructions exécutables se traduit par une erreur. La section Restrictions relatives au code pour un contenu dans des sandbox différents décrit les utilisations autorisées pour la fonction eval() .

Constructeurs de fonctions

Dans le sandbox d’application, il est possible d’utiliser des constructeurs de fonctions avant la fin du chargement d’une page. Dès lors que tous les gestionnaires d’événement load de page sont terminés, il est impossible de créer de nouvelles fonctions.

Chargement d’un script externe

Les pages HTML du sandbox de l’application ne peuvent pas utiliser la balise script pour charger des fichiers JavaScript situés en dehors du répertoire de l’application. Pour qu’une page de votre application puisse charger un script stocké en dehors du répertoire de l’application, vous devez la mapper dans un sandbox autre que celui de d’application.

Objet XMLHttpRequest

AIR fournit un objet XMLHttpRequest (XHR) dont les applications peuvent se servir pour émettre des requêtes de données. L’exemple suivant illustre une demande de données simple :

xmlhttp = new XMLHttpRequest(); 
xmlhttp.open("GET", "http:/www.example.com/file.data", true); 
xmlhttp.onreadystatechange = function() { 
    if (xmlhttp.readyState == 4) { 
        //do something with data... 
    } 
} 
xmlhttp.send(null); 

Contrairement à un navigateur, AIR permet au contenu exécuté dans le sandbox de l’application de demander des données provenant de n’importe quel domaine. Le résultat d’une requête XHR contenant une chaîne JSON peut aboutir à des objets de données à moins de comprendre également du code exécutable. Si des instructions exécutables figurent dans le résultat de la requête XHR, une erreur est renvoyée et la tentative d’évaluation se solde par un échec.

Pour empêcher l’introduction accidentelle de code provenant de sources distantes, les requêtes XHR synchrones renvoient un résultat vide lorsqu’elles sont émises avant la fin du chargement de la page. Les requêtes XHR asynchrones sont toujours renvoyées après le chargement d’une page.

Par défaut, AIR bloque les requêtes XMLHttpRequest interdomaines dans les sandbox autres que d’application. Une fenêtre parent du sandbox de l’application peut choisir d’autoriser des requêtes interdomaines dans une image enfant dont le contenu ne se trouve pas dans un sandbox autre que d’application. Pour ce faire, définissez allowCrossDomainXHR , un attribut ajouté par AIR, sur la valeur true dans l’élément image ou iframe conteneur :

<iframe id="mashup" 
    src="http://www.example.com/map.html" 
    allowCrossDomainXHR="true" 
</iframe>
Remarque : si cela s’avère pratique, il est aussi possible de télécharger les données à l’aide de la classe URLStream AIR.

Si vous distribuez une requête XMLHttpRequest vers un serveur distant à partir d’une image ou d’une iframe doté du contenu de l’application mappé dans un sandbox distant, assurez-vous que l’URL de mappage ne masque pas l’adresse du serveur utilisé dans la requête XHR. Tenez compte, par exemple, de la définition d’iframe suivante, laquelle mappe le contenu de l’application dans un sandbox distant pour le domaine example.com :

<iframe id="mashup" 
    src="http://www.example.com/map.html" 
    documentRoot="app:/sandbox/" 
    sandboxRoot="http://www.example.com/" 
    allowCrossDomainXHR="true" 
</iframe>

Etant donné que l’attribut sandboxRoot remappe l’URL racine de l’adresse www.example.com, toutes les requêtes sont chargées à partir du répertoire de l’application et non du serveur distant. Les requêtes sont remappées, qu’elles soient issues de la navigation dans les pages ou d’une requête XMLHttpRequest.

Afin d’éviter de bloquer accidentellement des requêtes de données en direction du serveur distant, mappez sandboxRoot à un sous-répertoire de l’URL distante plutôt qu’à la racine. Le répertoire ne doit pas nécessairement exister. Par exemple, pour permettre le chargement des requêtes en direction de www.example.com à partir du serveur distant plutôt que du répertoire de l’application, modifiez l’iframe précédente de la manière suivante :

<iframe id="mashup" 
    src="http://www.example.com/map.html" 
    documentRoot="app:/sandbox/" 
    sandboxRoot="http://www.example.com/air/" 
    allowCrossDomainXHR="true" 
</iframe>

Dans ce cas, seul le contenu du sous-répertoire air est chargé en local.

Pour plus d’informations sur le mappage de sandbox, voir Eléments image et iframe HTML et Sécurité HTML dans Adobe AIR .

Cookies

Dans les applications AIR, seul le contenu des sandbox distants (chargé à partir de sources http: et https:) peut utiliser des cookies (propriété document.cookie ). Le sandbox d’application propose d’autres techniques de stockage des données persistantes, telles que les classes EncryptedLocalStore, SharedObject et FileStream.

Objet Clipboard

L’API Clipboard de WebKit est dotée des événements suivants : copy , cut et paste . L’objet événement transmis dans ces événements permet d’accéder au Presse-papiers via la propriété clipboardData . Faites appel aux méthodes suivantes de l’objet clipboardData pour lire ou écrire des données de Presse-papiers :

Méthode

Description

clearData(mimeType)

Efface les données du Presse-papiers. Définissez le paramètre mimeType sur le type MIME des données à effacer.

getData(mimeType)

Permet d’obtenir les données du Presse-papiers. Cette méthode peut uniquement être appelée dans un gestionnaire pour l’événement paste . Définissez le paramètre mimeType sur le type MIME des données à renvoyer.

setData(mimeType, data)

Copie les données dans le Presse-papiers. Définissez le paramètre mimeType sur le type MIME des données.

Le code JavaScript situé en dehors du sandbox de l’application peut uniquement accéder au Presse-papiers par le biais de ces événements. Toutefois, le contenu du sandbox de l’application a la possibilité d’accéder directement au Presse-papiers du système à l’aide de la classe Clipboard AIR. Par exemple, l’instruction suivante pourrait servir à obtenir des données au format texte du Presse-papiers :

var clipping = air.Clipboard.generalClipboard.getData("text/plain", 
                                air.ClipboardTransferMode.ORIGINAL_ONLY);

Les types MIME de données valides sont les suivants :

Type MIME

Valeur

Texte

"text/plain"

HTML

"text/html"

URL

"text/uri-list"

Image bitmap

"image/x-vnd.adobe.air.bitmap"

Liste de fichiers

"application/x-vnd.adobe.air.file-list"

Important : seul le contenu du sandbox de l’application peut accéder aux données de fichier stockées dans le Presse-papiers. Si du contenu hors application tente d’accéder à un objet fichier du Presse-papiers, une erreur de sécurité est générée.

Pour plus d’informations sur l’utilisation du Presse-papiers, voir Opération de copier-coller et Using the Pasteboard from JavaScript (centre des développeurs Apple) .

Opération glisser-déposer

Les mouvements de glisser-déposer vers et depuis un contenu HTML génèrent les événements DOM suivants : dragstart , drag , dragend , dragenter , dragover , dragleave et drop . L’objet événement transmis dans ces événements permet d’accéder aux données déplacées via la propriété dataTransfer . La propriété dataTransfer fait référence à un objet offrant les mêmes méthodes que l’objet clipboardData associé à un événement clipboard. Par exemple, la fonction suivante pourrait servir à obtenir des données au format texte à partir d’un événement drop :

function onDrop(dragEvent){ 
    return dragEvent.dataTransfer.getData("text/plain",  
            air.ClipboardTransferMode.ORIGINAL_ONLY); 
}

L’objet dataTransfer dispose des membres importants suivants :

Membre

Description

clearData(mimeType)

Efface les données. Définissez le paramètre mimeType sur le type MIME de la représentation de données à effacer.

getData(mimeType)

Permet d’obtenir les données que vous avez fait glisser. Cette méthode peut uniquement être appelée dans un gestionnaire pour l’événement drop . Définissez le paramètre mimeType sur le type MIME des données à obtenir.

setData(mimeType, data)

Définit les données à faire glisser. Définissez le paramètre mimeType sur le type MIME des données.

types

Tableau de chaînes contenant les types MIME de toutes les représentations de données actuellement disponibles dans l’objet dataTransfer .

effectsAllowed

Indique si les données que vous faites glisser peuvent être copiées, déplacées et/ou liées. Définissez la propriété effectsAllowed du gestionnaire pour l’événement dragstart .

dropEffect

Indique, parmi les effets de type drop (déposer) autorisés, ceux qui sont pris en charge par une cible de type drag (glisser). Définissez la propriété dropEffect du gestionnaire pour l’événement dragEnter . Au cours du glissement, le curseur change de forme afin d’indiquer l’effet qui se produirait si l’utilisateur relâchait le bouton de la souris. Si aucun effet dropEffect n’est spécifié, un effet doté de la propriété effectsAllowed est appliqué. L’effet copy (copier) est prioritaire sur l’effet move (déplacer), lequel a priorité sur l’effet link (lier). L’utilisateur peut modifier le niveau de priorité par défaut au moyen du clavier.

Pour plus d’informations sur l’ajout de la prise en charge du glisser-déposer à une application AIR, voir Opération glisser-déposer dans AIR et Using the Drag-and-Drop from JavaScript (centre de développeurs Apple) .

Propriétés innerHTML et outerHTML

Pour des raisons de sécurité, AIR limite l’utilisation des propriétés innerHTML et outerHTML avec un contenu exécuté dans le sandbox de l’application. Avant l’événement de chargement de la page, de même que pendant l’exécution de tout gestionnaire d’événement de chargement, l’utilisation des propriétés innerHTML et outerHTML n’est pas restreinte. Toutefois, dès lors que la page est chargée, vous pouvez uniquement vous servir des propriétés innerHTML ou outerHTML afin d’ajouter un contenu statique au document. Toute instruction de la chaîne attribuée à innerHTML ou à outerHTML qui aboutit à du code exécutable est ignorée. Si, par exemple, vous incluez un attribut de rappel d’événement dans une définition d’élément, l’écouteur d’événement n’est pas inséré. De la même manière, les balises <script> intégrées ne sont pas évaluées. Pour plus d’informations, voir Sécurité HTML dans Adobe AIR .

Méthodes Document.write() et Document.writeln()

L’utilisation des méthodes write() et writeln() n’est pas limitée dans le sandbox de l’application avant la survenue de l’événement load de la page. Toutefois, dès lors que la page est chargée, l’appel de l’une ou l’autre de ces méthodes n’efface pas la page ou n’en crée pas de nouvelle. Dans un sandbox autre que celui de l’application, comme dans la plupart des navigateurs Web, l’appel de la méthode document.write() ou writeln() après la fin du chargement de la page entraîne l’effacement de la page active et l’ouverture d’une nouvelle page vide.

Propriété Document.designMode

Définissez la propriété document.designMode sur la valeur on afin de rendre tous les éléments du document modifiables. L’éditeur intégré prend en charge les modifications de texte, la copie, le collage et le glisser-déposer. Définir designMode sur on revient au même que configurer la propriété contentEditable de l’élément body sur la valeur true . La propriété contentEditable permet de définir les sections modifiables d’un document pour la plupart des éléments HTML. Pour plus d’informations, voir la section Attribut contentEditable HTML .

Evénements unload (pour les objets body et frameset)

Dans la balise frameset ou body de niveau supérieur d’une fenêtre (y compris la fenêtre principale de l’application), ne répondez pas à la fenêtre (ou à l’application) en cours de fermeture au moyen de l’événement unload . Au lieu de cela, optez pour l’événement exiting de l’objet NativeApplication (afin de détecter le moment de fermeture d’une application). Une autre solution consiste à utiliser l’événement closing de l’objet NativeWindow (afin de détecter le moment de fermeture d’une fenêtre). Par exemple, le code JavaScript suivant affichage un message ( « Goodbye » ) lorsque l’utilisateur ferme l’application :

var app = air.NativeApplication.nativeApplication; 
app.addEventListener(air.Event.EXITING, closeHandler); 
function closeHandler(event) 
{ 
    alert("Goodbye."); 
}

Toutefois, les scripts peuvent réagir correctement à l’événement unload déclenché par la navigation dans une image, une iframe ou le contenu d’une fenêtre de niveau supérieur.

Remarque : il est probable que ces limitations soient supprimées dans une prochaine version d’Adobe AIR.

Objet Window JavaScript

L’objet Window reste l’objet global dans le contexte d’exécution JavaScript. Dans le sandbox de l’application, AIR insère de nouvelles propriétés dans l’objet Window JavaScript en vue d’offrir un accès aux classes intégrées d’AIR de même qu’à des objets hôte importants. En outre, certaines méthodes et propriétés se comportent différemment selon qu’elles se trouvent dans le sandbox de l’application ou pas.

Propriété Window.runtime
La propriété runtime vous permet d’instancier et d’utiliser les classes d’exécution intégrées à partir du sandbox de l’application. Ces classes comprennent les API AIR et Flash Player (mais pas, par exemple, la structure Flex). L’instruction suivante crée par exemple un objet de fichier AIR :
var preferencesFile = new window.runtime.flash.filesystem.File();

Le fichier AIRAliases.js , disponible dans le kit SDK d’AIR, contient des définitions d’alias permettant de raccourcir de telles références. Ainsi, lorsque le fichier AIRAliases.js est importé dans une page, il est possible de créer un objet File à l’aide de l’instruction suivante :

var preferencesFile = new air.File();

La propriété window.runtime est exclusivement définie pour un contenu situé dans le sandbox de l’application et uniquement pour le document parent d’une page dotée d’images ou d’iframes.

Voir la section Utilisation du fichier AIRAliases.js .

Propriété Window.nativeWindow
La propriété nativeWindow fournit une référence à l’objet window natif sous-jacent. Grâce à cette propriété, vous pouvez coder des fonctions et propriétés de fenêtre (window) telles que la position, la taille et la visibilité, et gérer des événements de fenêtre comme la fermeture, le redimensionnement et le déplacement. Dans l’exemple suivant, l’instruction permet de fermer la fenêtre :
window.nativeWindow.close();
Remarque : les fonctions de contrôle de la fenêtre fournies par l’objet NativeWindow chevauchent celles fournies par l’objet Window JavaScript. Dans de tels cas, vous pouvez opter pour la méthode qui vous semble la plus pratique.

La propriété window.nativeWindow est exclusivement définie pour un contenu situé dans le sandbox de l’application et pour le document parent d’une page dotée d’images ou d’iframes.

Propriété Window.htmlLoader
La propriété htmlLoader fournit une référence à l’objet HTMLLoader AIR disposant du contenu HTML. Grâce à cette propriété, vous pouvez coder l’aspect et le comportement de l’environnement HTML. Vous pouvez ainsi utiliser la propriété htmlLoader.paintsDefaultBackground afin de déterminer si la commande dessine un arrière-plan blanc par défaut :
window.htmlLoader.paintsDefaultBackground = false;
Remarque : l’objet HTMLLoader proprement dit est doté d’une propriété window , laquelle fait référence à l’objet Window JavaScript du contenu HTML inclus. Cette propriété vous permet d’accéder à l’environnement JavaScript via une référence à l’objet HTMLLoader conteneur.

La propriété window.htmlLoader est exclusivement définie pour un contenu situé dans le sandbox de l’application et pour le document parent d’une page dotée d’images ou d’iframes.

Propriétés Window.parentSandboxBridge et Window.childSandboxBridge
Les propriétés parentSandboxBridge et childSandboxBridge vous permettent de définir une interface entre un cadre parent et un cadre enfant. Pour plus d’informations, voir la section Programmation croisée du contenu dans des sandbox de sécurité distincts .

Fonctions Window.setTimeout() et Window.setInterval()
Pour des raisons de sécurité, AIR limite l’utilisation des fonctions setTimeout() et setInterval() dans le sandbox de l’application. Il est impossible de définir le code à exécuter sous forme de chaîne lors de l’appel de la fonction setTimeout() ou setInterval() . Vous devez impérativement utiliser une référence à la fonction. Pour plus d’informations, voir la section setTimeout() et setInterval() .

Fonction Window.open()
Lorsqu’elle est appelée par du code exécuté dans un sandbox autre que d’application, la méthode open() ouvre seulement une fenêtre si elle est appelée suite à une action utilisateur (telle qu’un clic de souris ou l’activation d’une touche du clavier). De plus, le titre de la fenêtre est précédé du titre de l’application (afin d’empêcher l’ouverture de fenêtres par du contenu distant provenant de fenêtres d’usurpation d’identité ouvertes par l’application). Pour plus d’informations, voir la section Restrictions relatives à l’appel de la méthode window.open() de JavaScript .

Objet air.NativeApplication

L’objet NativeApplication fournit des informations sur l’état de l’application, distribue différents événements de niveau application importants et offre des fonctions pratiques de contrôle du comportement de l’application. Une occurrence unique de l’objet NativeApplication est créée automatiquement. Elle est accessible via la propriété NativeApplication.nativeApplication définie dans la classe.

Pour accéder à l’objet à partir du code JavaScript, vous pouvez utiliser :

var app = window.runtime.flash.desktop.NativeApplication.nativeApplication;

Autre solution, si le script AIRAliases.js a été importé, vous adoptez la forme plus courte suivante :

var app = air.NativeApplication.nativeApplication;

L’objet NativeApplication est uniquement accessible à partir du sandbox de l’application. Pour plus d’informations sur l'objet NativeApplication, voir Utilisation des informations sur le moteur d’exécution d’AIR et les systèmes d’exploitation .

Modèle d’URL JavaScript

L’exécution d’un code défini dans un modèle d’URL JavaScript (comme dans href="javascript:alert('Test')" ) est bloquée au sein du sandbox de l’application. Aucune erreur n’est renvoyée.