L'interazione tra Flash e JavaScript è un aspetto molto interessante ed utile ad esempio per aprire popup o mostrare alert; questa interazione, però, fino a Flash Mx2004 era piuttosto limitata, era infatti possibile utilizzare solo i comandi getURL
e fscommand
(da Flash verso JavaScript) e setVariable
, callFrame
e callLabel
(da JavaScript verso Flash).
Con Flash 8 l'interazione è migliorata grazie all'introduzione della classe ExternalInterface, che permette una comunicazione più fluida e flessibile tra Flash e JavaScript; tale classe inoltre può essere utilizzata anche in altri ambiti, infatti in generale permette di far comunicare un filmato Flash con il suo "contenitore", che può essere un browser web oppure un'altra applicazione (anche desktop).
Impostazioni di sicurezza
Prima di iniziare i nostri test, teniamo presente il fatto che il Flash Player usi un sistema denominato "sandbox" per stabilire i contenuti caricabili dal player, in particolare per quanto riguarda l'interazione con dati provenienti da domini esterni a quello dove si trova il filmato. Per far comunicare ActionScript e JavaScript con il player versione 8 (o successiva) dobbiamo modificare le impostazioni di default della proprietà allowScriptAccess
. Questa modifica non è necessaria per versioni del player antecedenti la 8. Vediamo quale è la modifica da eseguire e come effettuarla. Vediamo il codice HTML generati di default da Flash:
Codice HTML esportato di default da Flash
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>allowScriptAccess</title>
</head>
<body bgcolor="#ffffff">
<!--url's used in the movie-->
<!--text used in the movie-->
<!-- saved from url=(0013)about:internet -->
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="550" height="400" id="allowScriptAccess" align="middle">
<param name="allowScriptAccess" value="sameDomain" />
<param name="movie" value="allowScriptAccess.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />
<embed src="allowScriptAccess.swf" quality="high" bgcolor="#ffffff" width="550" height="400" align="middle"
name="allowScriptAccess" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>
</body>
</html>
Come vediamo alla proprietà allowScriptAccess
viene assegnato il valore sameDomain
. Questo fa sì che il filmato presente nella pagina possa caricare contenuti solo se questi sono presenti sullo stesso dominio del filmato stesso; tale proprietà però influisce anche sulla comunicazione tra ActionScript e JavaScript nei test in locale con alcuni comandi (es. getURL), pertanto il valore sameDomain
va cambiato con in always
. In caso di test su server possiamo lasciare il valore predefinito, dato che sameDomain è sufficiente a consentire la comunicazione Flash-Javascript sul server.
Nota: Questo accorgimento vale solo per il Flash Player 8 dato che le versioni precedenti non prevedono questa proprietà.
Prima di Flash 8
Come abbiamo accennato, anche prima di Flash 8 era possibile comunicare tra Flash e JavaScript, ma l'interazione era piuttosto limitata e soprattutto più laboriosa; questi metodi possono comunque essere utilizzati anche in Flash 8, che garantisce sotto questo punto di vista un'ottima retrocompatibilità. Vediamo come.
Da Flash a JavaScript
Utilizzo di getURL
Il metodo più semplice per richiamare una funzione JavaScript è l'utilizzo del comando getURL
. Ad esempio, se inseriamo questo codice ActionScript nel nostro filmato Flash
var msg:String = "'Ciao'";
getURL('JavaScript:callJavaScript('+msg+')');
... e questo codice nella pagina HTML ...
<script language="JavaScript">
function callJavaScript(str){
alert(str)
}
</script>
Aprendo la pagina appare una finestra di avviso del browser con il testo "Ciao".
Utilizzo di fscommand
In questo caso la situazione è leggermente più complessa, non tanto dal lato ActionScript dove il codice diventa
var msg:String = "'Ciao'";
fscommand("callJavaScript", msg);
Quanto dal lato della pubblicazione del filmato. Per sfruttare gli fscommand
infatti dobbiamo modificare le impostazioni di pubblicazione: dal menu selezioniamo la voce File>Impostazioni di pubblicazione, quindi portiamoci nella scheda "Flash" e selezioniamo come template "Flash con FSCommand" (come in figura).
Pubblicando i file (premendo il tasto "Pubblica") e aprendo il file HTML, noteremo che quest'ultimo contiene il seguente script:
<script language="JavaScript">
<!--
var isInternetExplorer = navigator.appName.indexOf("Microsoft") != -1;
// Handle all the FSCommand messages in a Flash movie.
function fscommand__DoFSCommand(command, args) {
var fscommand_Obj = isInternetExplorer ? document.all.fscommand_ : document.fscommand_;
//
// Place your code here.
//
}
// Hook for Internet Explorer.
if (navigator.appName && navigator.appName.indexOf("Microsoft") != -1
&& navigator.userAgent.indexOf("Windows") != -1
&& navigator.userAgent.indexOf("Windows 3.1") == -1)
{
document.write('<script language="VBScript">n');
document.write('On Error Resume Nextn');
document.write('Sub fscommand__FSCommand(ByVal command, ByVal args)n');
document.write(' Call fscommand__DoFSCommand(command, args)n');
document.write('End Subn');
document.write('</script>n');
}
//-->
</script>
Nella parte evidenziata in grassetto va piazzato il proprio codice, ad esempio
function fscommand_DoFSCommand(command, args)
{
var fscommandObj = isInternetExplorer ? document.all.fscommand : document.fscommand;
if(command == "callJavaScript") { alert(args) }
}
Testando il filmato nel browser vedremo anche in questo caso un alert contenente la scritta "Ciao".
Tra le due soluzioni il getURL
è sicuramente quella più comoda, inoltre è più semplice passare più argomenti alla funzione JavaScript.
Da JavaScript a Flash
Oltre alla comunicazione Flash-JavaScript è possibile il "percorso contrario": il metodo più comune è usare il comando setVariable
in JavaScript, quindi sfruttare il comando watch
in ActionScript per richiamare una determinata funzione quando il valore di una certa variabile viene modificato. Vediamo i passaggi da seguire.
Per prima cosa creiamo un nuovo filmato in Flash con al suo interno un campo di testo dinamico (nome istanza "result_txt").
// Creiamo una nuova variabile
var testValue:String = "";
// Creiamo la funzione da eseguire quando necessario
watchCallback = function (id, oldval, newval):String
{
// Mostriamo il nuovo valoe in un campo di testo
result_txt.text = newval;
return newval;
};
_root.watch("testValue", watchCallback);
Praticamente con questo codice facciamo in modo che ad ogni cambiamento di valore nella variabile testValue
venga eseguita la funzione watchCallBack
.
Ora dobbiamo inserire nella pagina HTML gli <input>
per inserire il valore della variabile e lo script che si occuperà di passare il valore da JavaScript a Flash. Possiamo utilizzare il seguente codice per la creazione di un testo di input e un pulsante che richiami la funzione JavaScript che andremo a creare.
<input type=button value="Invia il valore a Flash" onClick="callJavaScript()" />
<form name="inputValue">
Valore <input type="text" name="vars" size="10" />
</form>
Andiamo quindi a scrivere la funzione JavaScript, in questo modo:
Nota: myMovie
è l'id che assegnamo al filmato Flash.
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="550" height="100" <b>id="myMovie" </b>align="middle">
<param name="allowScriptAccess" value="sameDomain" />
<param name="movie" value="setVariable.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#ffcc00" />
<embed src="setVariable.swf" quality="high" bgcolor="#ffcc00" width="550" height="100"
name="myMovie" align="middle" allowScriptAccess="sameDomain"
type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>
Se ora avviamo la pagina HTML ed inseriamo un valore nel campo di testo ed inviandolo a Flash, questo sarà inserito nel campo dinamico creato all'interno del filmato.
Con Flash 8: la classe ExternalInterface
Dopo aver analizzato le soluzioni da utilizzare prima di Flash 8 per il passaggio di dati tra Flash e JavaScript, osserviamo il funzionamento della classe ExternalInterface
. Prima di tutto dobbiamo dire che questa classe ha un'alta compatibilità, infatti funziona sui seguenti browser
- Internet Explorer 5 e successivi su Windows
- Netscape 8 e successivi su Windows e Mac OS
- Mozilla 1.7.5 e successivi su Windows e Mac OS
- Firefox 1.0 e successivi su Windows e Mac OS
- Safari 1.3 e successivi su Mac OS
Il vantaggio principale che porta la classe ExternalInterface
è la facilità con la quale si può accedere alle funzioni JavaScript e recuperare l'eventuale valore restituito dalla funzione, il tutto con un solo comando (in precedenza avremmo dovuto usare le soluzioni viste prima, getURL
o fscommand
per inviare i dati a JavaScript e setVariable
per inviare il valore di ritorno a Flash).
Da Flash a JavaScript
Per chiamare una funzione JavaScript con la classe ExternalInterface
è sufficiente utilizzare il comando "call".
Sintassi di call
ExternalInterface.call(funzione, [parametri])
Dove funzione
è il nome della funzione JavaScript da eseguire e parametri
serve per impostare gli eventuali parametri da passare per la funzione (nel caso siano più di uno è necessario separarli tramite virgole).
Vediamo di ricreare gli esempi visti in precedenza utilizzando questo comando; apriamo un nuovo filmato Flash, creiamo un campo di testo dinamico (nome istanza "return_txt" ed aggiungiamo il codice ActionScript:
import flash.external.*;
// parametro per la funzione
var msg:String = "Ciao";
// Chiamiamo la funzione e associamo alla variabile
// returnValue il valore da essa restituito
var returnValue:String = ExternalInterface.call("callJavaScript", msg).toString();
return_txt.text = returnValue;
Nella pagina HTML inseriamo questa funzione:
<script language="JavaScript">
function callJavaScript(str)
{
alert(str);
return "ExternalInterface è un commando del Flash Player 8";
}
</script>
Una volta aperta la pagina HTML vedremo apparire un alert del browser con la scritta "Ciao" (come negli script precedenti) ed inoltre vedremo, nel campo di testo creato nel filmato Flash, la stringa restituita da JavaScript.
Lo script è molto semplice e consente di ricevere anche dei valori di ritorno dalla funzione chiamata, così da poter ricevere maggiori informazioni sullo scambio di dati tra le due tecnologie.
Da JavaScript a Flash
Per il passaggio di dati da JavaScript a Flash con la classe ExternalInterface
dobbiamo utilizzare il comando "addCallBack".
Sintassi di addCallBack
ExternalInterface.addCallback (funzioneJs, istanza, funzione)
- Il parametro
funzioneJS
è il nome con cui faremo riferimento alla funzione reale (stabilita dal parametrofunzione
) del filmato Flash. - Il parametro
istanza
non è obbligatorio e si può impostare anull
, altrimenti stabilisce l'oggetto a cui farà riferimento la parola chiavethis
nella funzione.
In questo caso creeremo un esempio un po' più complesso per renderci conto delle possibilità offerte da questo comando; creiamo dunque un nuovo progetto Flash con al suo interno un movieclip (nome istanza "ball_mc") ed inseriamo in Flash questo codice:
import flash.external.*;
ExternalInterface.addCallback("callPlayBall", null, playBall);
function playBall(tgX:Number, tgY:Number, spd:Number):Void {
moveMC(ball_mc, tgX, tgY, spd);
}
// Creiamo la funzione di movimento che useremo per spostare la palla
function moveMC(tgMC:MovieClip, tgX:Number, tgY:Number, spd:Number):Void {
var mc:MovieClip = tgMC.createEmptyMovieClip("tp_chProp", 98765);
mc.onEnterFrame = function()
{
this._parent._x += spd*(tgX-this._parent._x);
this._parent._y += spd*(tgY-this._parent._y);
var diffX:Number = Math.abs(tgX-this._parent._x);
var diffY:Number = Math.abs(tgY-this._parent._y);
if (diffX<0.5 && diffY<0.5) {
this._parent._x = tgX;
this._parent._y = tgY;
this.removeMovieClip();
}
};
}
Questo codice è in grado di far muovee il movieclip creato basandosi sui valori che vengono passati alla funzione: vediamo come passare tali valori da JavaScript.
Passare i dati a Flash
<script language="JavaScript">
function callExternalInterface() {
/* Richiama la funzione impostata nel filmato Flash */
getMovieName("myMovie").callPlayBall(inputValue.x.value, inputValue.y.value, inputValue.spd.value);
}
/* Ricava il nome del filmato Flash a seconda del browser */
function getMovieName(movieName) {
if (navigator.appName.indexOf("Microsoft") != -1) {
return window[movieName]
}
else {
return document[movieName]
}
}
</script>
Campi di input per l'inserimento dei dati
<input type="button" onClick="callExternalInterface()" value="Invia I dati a Flash" />
<form name="inputValue">
Posizione X <input type="text" name="x" size="10" />
Posizione Y <input type="text" name="y" size="10" />
Velocità <input type="text" name="spd" size="10" />
</form>
Provando il filmato all'interno del browser potremo vedere come impostando i valori per posizione e velocità e premendo il bottone daremo il via al movimento della pallina (nota: per la velocità vanno inseriti valori tra 0 ed 1).
Conclusioni
Abbiamo visto che la classe ExternalInterface
permette un passaggio molto più semplice e veloce dei dati (specialmente da JavaScript a Flash) rispetto alle soluzioni disponibili prima di Flash 8, con poche righe di codice è possibile ottenere una grande interattività tra ActionScript e JavaScript e sfruttare questa interazione per creare sistemi di interazione piuttosto interessanti.
Ricordiamo che la classe ExternalInterface
è possibile comunicare in generale con l'applicazione "contenitore" il file swf, che nel caso del web è proprio il browser (e quindi JavaScript). La sintassi di questa classe consente di risparmiare anche tempo nello sviluppo data la brevità degli script rispetto alle vecchie soluzioni, inoltre con la possibilità di ricevere i valori di ritorno delle funzioni con un solo comando, migliorando così notevolmente la gestione di eventuali errori.