Chiamata e terminazione di applicazioni AIR

Adobe AIR 1.0 e versioni successive

In questa sezione vengono descritti i diversi metodi di chiamata di un'applicazione Adobe® AIR® installata, nonché le opzioni e le considerazioni per la chiusura di un'applicazione in esecuzione.

Nota: gli oggetti NativeApplication, InvokeEvent e BrowserInvokeEvent sono disponibili solo per contenuto SWF in esecuzione nella sandbox dell'applicazione AIR. L'accesso a queste classi non è consentito al contenuto SWF in esecuzione nel runtime Flash Player, all'interno del browser o del lettore autonomo (proiettore), o in un'applicazione AIR esterna alla sandbox dell'applicazione.

Per una spiegazione rapida ed esempi di codice sulla chiamata e terminazione di applicazioni AIR, vedete i seguenti articoli delle Guide rapide in Centro per sviluppatori Adobe:

Chiamata dell'applicazione

Un'applicazione AIR viene chiamata quando l'utente o il sistema operativo:

  • Avvia l'applicazione dalla shell del desktop.

  • Utilizza l'applicazione come comando sulla shell della riga di comando.

  • Apre un tipo di file al quale l'applicazione è associata come applicazione di apertura predefinita.

  • (Mac OS X) Fa clic sull'icona dell'applicazione nella barra delle attività di ancoraggio, a prescindere se l'applicazione sia attualmente in esecuzione o meno.

  • Sceglie di avviare l'applicazione dal programma di installazione (alla fine di un nuovo processo di installazione oppure dopo aver fatto doppio clic sul file AIR per un'applicazione già installata).

  • Avvia un aggiornamento di un'applicazione AIR quando la versione installata segnala che sta gestendo gli aggiornamenti dell'applicazione mediante l'inclusione di una dichiarazione <customUpdateUI>true</customUpdateUI> nel file descrittore dell'applicazione.

  • (iOS) Riceve una notifica dal servizio APN (Apple Push Notification).

  • Attiva l'applicazione tramite un URL.

  • Visita una pagina Web che ospita un badge Flash o un'applicazione che chiama il metodo com.adobe.air.AIR launchApplication() specificando le informazioni di identificazione per l'applicazione AIR. (Affinché la chiamata al browser riesca, il file descrittore dell'applicazione deve includere anche una dichiarazione <allowBrowserInvocation>true</allowBrowserInvocation> ).

Ogniqualvolta viene chiamata un'applicazione AIR, AIR invia un oggetto InvokeEvent di tipo invoke attraverso l'oggetto singleton NativeApplication. Per offrire a un'applicazione tempo sufficiente a inizializzarsi e a registrare un listener di eventi, gli eventi invoke vengono inseriti in una coda anziché eliminati. Non appena il listener è stato registrato, tutti gli eventi in coda vengono consegnati.

Nota: quando un'applicazione viene chiamata mediante la funzione di chiamata del browser, se l'applicazione non è già in esecuzione l'oggetto NativeApplication invia solo un evento invoke .

Per ricevere gli eventi invoke , chiamate il metodo addEventListener() dell'oggetto NativeApplication ( NativeApplication.nativeApplication) . Quando un listener di eventi effettua la registrazione di un evento invoke , riceve anche tutti gli eventi invoke che si sono verificati prima della registrazione. Gli eventi invoke in coda vengono inviati uno alla volta in un breve intervallo dopo che la chiamata a addEventListener() viene restituita. Se nel corso di questo processo si verifica un nuovo evento invoke , è possibile che esso venga inviato prima di uno o più eventi in coda. Questo accodamento di eventi consente di gestire eventuali eventi invoke che si sono verificati prima dell'esecuzione del codice di inizializzazione. È opportuno sottolineare che se si aggiunge un listener di eventi in una fase successiva dell'esecuzione (dopo l'inizializzazione dell'applicazione), esso riceverà comunque tutti gli eventi invoke che si sono verificati fin dall'avvio dell'applicazione.

Viene avviata una sola istanza di un'applicazione AIR. Quando un'applicazione già in esecuzione viene richiamata, AIR invia un nuovo evento invoke all'istanza in esecuzione. Un'applicazione AIR è responsabile per la risposta a un evento invoke e l'azione appropriata da intraprendere, come ad esempio l'apertura di una nuova finestra del documento.

Un oggetto InvokeEvent contiene tutti gli argomenti trasmessi all'applicazione, nonché la directory da cui l'applicazione è stata chiamata. Se l'applicazione è stata chiamata a causa di un'associazione di tipo file, il percorso completo al file viene incluso negli argomenti della riga di comando. Analogamente, se l'applicazione è stata chiamata a causa di un aggiornamento, viene fornito il percorso completo al file AIR di aggiornamento.

Quando in una sola operazione vengono aperti più file, in Mac OS X viene inviato un unico oggetto InvokeEvent. Ogni file viene incluso nell'array arguments . In Windows e Linux per ogni file viene inviato un oggetto InvokeEvent distinto.

L'applicazione può gestire gli eventi invoke mediante la registrazione di un listener con il relativo oggetto NativeApplication:

NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvokeEvent); 

Definendo inoltre un listener di eventi:

var arguments:Array; 
var currentDir:File; 
public function onInvokeEvent(invocation:InvokeEvent):void { 
    arguments = invocation.arguments; 
    currentDir = invocation.currentDirectory; 
} 

Acquisizione degli argomenti della riga di comando

Gli argomenti della riga di comando associati alla chiamata di un'applicazione AIR sono consegnati nell'oggetto InvokeEvent inviato dall'oggetto NativeApplication. La proprietà arguments dell'oggetto InvokeEvent contiene un array degli argomenti passati dal sistema operativo quando viene chiamata un'applicazione AIR. Se gli argomenti contengono percorsi file relativi, solitamente è possibile risolvere i percorsi mediante la proprietà currentDirectory .

Gli argomenti trasmessi a un'applicazione AIR vengono trattati come stringhe delimitate da spazi vuoti, a meno che non siano racchiusi tra virgolette:

Argomenti

Array

tick tock

{tick,tock}

tick "tick tock"

{tick,tick tock}

"tick" “tock”

{tick,tock}

\"tick\" \"tock\"

{"tick","tock"}

La proprietà currentDirectory di un oggetto InvokeEvent contiene un oggetto File che rappresenta la directory da cui l'applicazione è stata avviata.

Quando un'applicazione viene chiamata perché viene aperto un file di un tipo registrato dall'applicazione, il percorso nativo al file viene incluso negli argomenti della riga di comando come stringa. (L'applicazione è responsabile per l'apertura o l'esecuzione dell'operazione prevista sul file). Analogamente, quando un'applicazione viene programmata per l'aggiornamento automatico invece di affidarsi all'interfaccia utente standard per l'aggiornamento di AIR, il percorso nativo al file AIR viene incluso quando un utente fa doppio clic su un file contenente un'applicazione con un ID applicazione corrispondente.

È possibile accedere al file utilizzando il metodo resolve() dell'oggetto File currentDirectory :

if((invokeEvent.currentDirectory != null)&&(invokeEvent.arguments.length > 0)){ 
    dir = invokeEvent.currentDirectory; 
    fileToOpen = dir.resolvePath(invokeEvent.arguments[0]); 
}

È inoltre opportuno convalidare che un argomento sia in realtà un percorso a un file.

Esempio: chiamata di un log di eventi

Nell'esempio seguente viene illustrato come registrare i listener e gestire l'evento invoke . Nell'esempio vengono registrati tutti gli eventi di chiamata ricevuti e vengono visualizzati la directory corrente e gli argomenti della riga di comando.

Esempio ActionScript

package  
{ 
    import flash.display.Sprite; 
    import flash.events.InvokeEvent; 
    import flash.desktop.NativeApplication; 
    import flash.text.TextField; 
         
    public class InvokeEventLogExample extends Sprite 
    { 
        public var log:TextField; 
         
        public function InvokeEventLogExample() 
        { 
            log = new TextField(); 
            log.x = 15; 
            log.y = 15; 
            log.width = 520; 
            log.height = 370; 
            log.background = true; 
             
            addChild(log); 
 
            NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke); 
        } 
             
        public function onInvoke(invokeEvent:InvokeEvent):void 
        { 
            var now:String = new Date().toTimeString(); 
            logEvent("Invoke event received: " + now); 
                     
            if (invokeEvent.currentDirectory != null) 
            { 
                logEvent("Current directory=" + invokeEvent.currentDirectory.nativePath); 
            }  
            else  
            { 
                logEvent("--no directory information available--"); 
            } 
                     
            if (invokeEvent.arguments.length > 0) 
            { 
                logEvent("Arguments: " + invokeEvent.arguments.toString()); 
            }  
            else  
            { 
                logEvent("--no arguments--"); 
            } 
        } 
                 
        public function logEvent(entry:String):void  
        { 
            log.appendText(entry + "\n"); 
            trace(entry); 
        } 
    } 
} 

Esempio Flex

<?xml version="1.0" encoding="utf-8"?> 
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" 
    invoke="onInvoke(event)" title="Invocation Event Log"> 
    <mx:Script> 
    <![CDATA[ 
    import flash.events.InvokeEvent; 
    import flash.desktop.NativeApplication; 
 
    public function onInvoke(invokeEvent:InvokeEvent):void { 
        var now:String = new Date().toTimeString(); 
        logEvent("Invoke event received: " + now); 
                 
        if (invokeEvent.currentDirectory != null){ 
            logEvent("Current directory=" + invokeEvent.currentDirectory.nativePath); 
        } else { 
            logEvent("--no directory information available--"); 
        } 
                 
        if (invokeEvent.arguments.length > 0){ 
            logEvent("Arguments: " + invokeEvent.arguments.toString()); 
        } else { 
            logEvent("--no arguments--"); 
        } 
    } 
             
    public function logEvent(entry:String):void { 
        log.text += entry + "\n"; 
        trace(entry); 
    } 
    ]]> 
    </mx:Script> 
    <mx:TextArea id="log" width="100%" height="100%" editable="false" 
        valueCommit="log.verticalScrollPosition=log.textHeight;"/> 
</mx:WindowedApplication>

Chiamata di un'applicazione AIR al login utente

È possibile impostare un'applicazione AIR in modo che venga avviata automaticamente quando l'utente corrente accede impostando startAtLogin su true . Una volta effettuata tale impostazione, l'applicazione viene avviata automaticamente ogni volta che l'utente accede al sistema e continua ad essere avviata all'accesso al sistema fino a che l'impostazione viene modificata su false , l'utente modifica manualmente l'impostazione attraverso il sistema operativo oppure l'applicazione viene disinstallata. L'avvio all'accesso è un'impostazione di runtime. L'impostazione si applica solo all'utente corrente. Inoltre, per impostare la proprietà startAtLogin su true è necessario che l'applicazione sia installata. Se la proprietà viene impostata quando un'applicazione non è installata (ad esempio quando viene avviata con ADL), viene generato un errore.

Nota: l'applicazione non viene eseguita quando il computer viene avviato, bensì quando l'utente esegue l'accesso.

Per determinare se un'applicazione è stata avviata automaticamente o come risultato di un'azione dell'utente, potete esaminare la proprietà reason dell'oggetto InvokeEvent. Se la proprietà è uguale a InvokeEventReason.LOGIN , allora l'applicazione si è avviata automaticamente. Per altri percorsi di chiamata, la proprietà reason è impostata nel modo seguente:

  • InvokeEventReason.NOTIFICATION (solo iOS) - L'applicazione è stata chiamata mediante il servizio APN. Per altre informazioni su APN, vedete Utilizzare le notifiche push .

  • InvokeEventReason.OPEN_URL - L'applicazione è stata chiamata da un'altra applicazione o dal sistema.

  • InvokeEventReason.Standard - Tutti gli altri casi.

Per accedere alla proprietà reason , l'applicazione deve fare riferimento a AIR 1.5.1 o superiore (impostando il valore di spazio dei nomi corretto nel file descrittore dell'applicazione).

L'applicazione semplificata seguente utilizza la proprietà reason dell'oggetto InvokeEvent per decidere il comportamento da adottare quando si verifica un evento invoke. Se la proprietà reason è "login", l'esecuzione dell'applicazione rimane in background. In caso contrario, l'applicazione principale viene resa visibile. Un'applicazione che utilizza questo schema viene in genere avviata all'accesso in modo da poter eseguire elaborazioni in background o il monitoraggio di eventi e apre una finestra in risposta a un evento invoke attivato dall'utente.

package { 
    import flash.desktop.InvokeEventReason; 
    import flash.desktop.NativeApplication; 
    import flash.display.Sprite; 
    import flash.events.InvokeEvent; 
 
    public class StartAtLogin extends Sprite 
    { 
        public function StartAtLogin() 
        { 
            try 
            { 
                NativeApplication.nativeApplication.startAtLogin = true; 
            } 
            catch ( e:Error ) 
            { 
                trace( "Cannot set startAtLogin:" + e.message ); 
            } 
             
            NativeApplication.nativeApplication.addEventListener( InvokeEvent.INVOKE, onInvoke ); 
        } 
                 
        private function onInvoke( event:InvokeEvent ):void 
        { 
            if( event.reason == InvokeEventReason.LOGIN ) 
            { 
                //do background processing... 
                trace( "Running in background..." ); 
            }             
            else 
            { 
                this.stage.nativeWindow.activate(); 
            } 
        } 
    } 
}
Nota: per vedere le differenze di comportamento, creare un pacchetto dell'applicazione e installarla. La proprietà startAtLogin può essere impostata solo per applicazioni installate.

Chiamata di un'applicazione AIR dal browser

Utilizzando la funzionalità di chiamata browser un sito Web può avviare un'applicazione AIR installata attivandola mediante il browser. La chiamata browser è consentita solo se il file descrittore dell'applicazione imposta allowBrowserInvocation su true :

<allowBrowserInvocation>true</allowBrowserInvocation>

Quando l'applicazione viene chiamata tramite browser, l'oggetto NativeApplication dell'applicazione invia un oggetto BrowserInvokeEvent.

Per ricevere l'evento BrowserInvokeEvent, chiamate il metodo addEventListener() dell'oggetto NativeApplication ( NativeApplication.nativeApplication ) nell'applicazione AIR. Quando un listener di eventi effettua la registrazione di un evento BrowserInvokeEvent, riceve anche tutti gli eventi BrowserInvokeEvent che si sono verificati prima della registrazione. Questi eventi vengono inviati dopo che la chiamata a addEventListener() viene restituita, ma non necessariamente prima di altri eventi BrowserInvokeEvent che potrebbero essere stati ricevuti dopo la registrazione. Ciò consente di gestire gli eventi BrowserInvokeEvent che si sono verificati prima dell'esecuzione del codice di inizializzazione (ad esempio quando l'applicazione è stata inizialmente chiamata dal browser). Si consideri che se si aggiunge un listener di eventi in una fase successiva dell'esecuzione (dopo l'inizializzazione dell'applicazione), esso riceverà comunque tutti gli eventi BrowserInvokeEvent che si sono verificati fin dall'avvio dell'applicazione.

L'oggetto BrowserInvokeEvent include le seguenti proprietà:

Proprietà

Descrizione

arguments

Un array di argomenti (stringhe) da passare all&apos;applicazione.

isHTTPS

Se il contenuto del browser utilizza ( true ) o meno ( false ) lo schema URL https.

isUserEvent

Indica se la chiamata al browser ha generato un evento utente (ad esempio un clic del mouse). In AIR 1.0, il valore è sempre impostato su true ; AIR richiede un evento utente per la funzionalità di chiamata browser.

sandboxType

Il tipo di sandbox del contenuto del browser. I valori validi definiti sono gli stessi che è possibile utilizzare nella proprietà Security.sandboxType . Può trattarsi di uno dei seguenti:

  • Security.APPLICATION : il contento si trova nella sandbox di sicurezza dell'applicazione.

  • Security.LOCAL_TRUSTED : il contenuto si trova nella sandbox di sicurezza locale con file system.

  • Security.LOCAL_WITH_FILE : il contenuto si trova nella sandbox di sicurezza locale con file system.

  • Security.LOCAL_WITH_NETWORK : il contenuto si trova nella sandbox di sicurezza locale con rete.

  • Security.REMOTE : il contenuto si trova in un dominio (rete) remoto.

securityDomain

Il dominio di sicurezza per il contenuto del browser, ad esempio "www.adobe.com" o "www.example.org" . La proprietà è impostata solo per il contenuto della sandbox di sicurezza remota (per il contenuto proveniente da un dominio di rete) e non per il contenuto di una sandbox di sicurezza dell'applicazione o locale.

Se utilizzate la funzionalità di chiamata browser, tenete presenti le implicazioni di sicurezza Quando un sito Web avvia un'applicazione AIR, può inviare i dati mediante la proprietà arguments dell'oggetto BrowserInvokeEvent. Fate attenzione a utilizzare questi dati in operazioni sensibili quali API di caricamento del codice o di file. Il livello di rischio varia in base alle operazioni che l'applicazione effettuerà con i dati. Se prevedete che solo uno specifico sito Web chiami l'applicazione, sarebbe opportuno che quest'ultima controllasse la proprietà securityDomain dell'oggetto BrowserInvokeEvent. Potete inoltre richiedere che il sito Web che chiama l'applicazione utilizzi HTTPs. Ciò può essere verificato controllando la proprietà isHTTPS dell'oggetto BrowserInvokeEvent.

L'applicazione dovrebbe convalidare i dati che vengono trasmessi. Ad esempio, se si prevede che un'applicazione trasmetta URL a un dominio specifico, essa dovrebbe convalidare che gli URL puntino effettivamente a quel dominio. In questo modo è possibile impedire a un utente malintenzionato di "ingannare" l'applicazione in modo che invii dati riservati.

Nessuna applicazione dovrebbe utilizzare argomenti BrowserInvokeEvent che potrebbero puntare a risorse locali. Ad esempio, un'applicazione non dovrebbe creare oggetti File basati su un percorso trasmesso dal browser. Se si prevede che vengano trasmessi percorsi remoti dal browser, l'applicazione dovrebbe garantire che i percorsi non utilizzino il protocollo file:// invece di un protocollo remoto.

Terminazione dell'applicazione

Il sistema più semplice per terminare un'applicazione consiste nel chiamare il metodo exit() dell'oggetto NativeApplication. Tale sistema funziona quando l'applicazione non ha dati da salvare né risorse esterne da pulire. La chiamata al metodo exit() chiude tutte le finestre e termina l'applicazione. Tuttavia, per consentire alle finestre o ad altri componenti dell'applicazione di interrompere il processo di terminazione ed eventualmente di salvare dati critici, inviate gli eventi di avviso appropriati prima di effettuare la chiamata a exit() .

Un'ulteriore considerazione in merito alla chiusura normale di un'applicazione consiste nel fornire un percorso di esecuzione singolo, a prescindere da come viene avviato il processo di arresto. L'utente, o il sistema operativo, possono attivare la terminazione dell'applicazione nei modi seguenti:

  • Chiudendo l'ultima finestra dell'applicazione quando NativeApplication.nativeApplication.autoExit è impostato su true .

  • Selezionando il comando di uscita dall'applicazione dal sistema operativo (ad esempio quando l'utente sceglie il comando di uscita dall'applicazione dal menu predefinito). (Ciò accade solo su Mac OS; Windows e Linux non forniscono un comando di uscita dall'applicazione attraverso il chrome di sistema.)

  • Mediante l'arresto del computer.

Quando un comando di uscita viene mediato nel sistema operativo da uno di questi sistemi, NativeApplication invia un evento exiting . Se nessun listener annulla l'evento exiting , tutte le finestre aperte vengono chiuse. Ciascuna finestra invia un evento closing e quindi un evento close . Se qualcuna delle finestre annulla l'evento closing , il processo di arresto viene interrotto.

Se l'ordine di chiusura delle finestre è un problema per l'applicazione, utilizzate listener per l'evento exiting da NativeApplication, quindi chiudete manualmente le finestre nell'ordine appropriato. Ciò può accadere, ad esempio, se disponete di una finestra del documento con tavolozze degli strumenti. Può essere quanto meno scomodo se il sistema chiude le tavolozze, ma l'utente decide di annullare il comando di uscita per salvare alcuni dati. In Windows, l'unica volta che si otterrà l'evento exiting sarà dopo la chiusura dell'ultima finestra (quando la proprietà autoExit dell'oggetto NativeApplication è impostato su true ).

Per seguire un comportamento coerente su tutte le piattaforme, a prescindere se la sequenza di uscita sia avviata mediante il chrome del sistema operativo, i comandi di menu o la logica dell'applicazione, per uscire dall'applicazione è opportuno osservare le seguenti pratiche consigliate:

  1. Inviate sempre un evento exiting mediante l'oggetto NativeApplication prima di chiamare il metodo exit() nel codice dell'applicazione, quindi controllate che nessun altro componente dell'applicazione annulli l'evento.

    public function applicationExit():void { 
        var exitingEvent:Event = new Event(Event.EXITING, false, true); 
        NativeApplication.nativeApplication.dispatchEvent(exitingEvent); 
        if (!exitingEvent.isDefaultPrevented()) { 
            NativeApplication.nativeApplication.exit(); 
        } 
    } 
  2. Eseguite il listener per l'evento exiting dell'applicazione dall'oggetto NativeApplication.nativeApplication , quindi, nel gestore, chiudete tutte le finestre inviando innanzitutto un evento closing . Eseguite tutte le attività di pulitura necessarie, quali il salvataggio dei dati di un'applicazione o l'eliminazione di file temporanei, dopo che tutte le finestre sono state chiuse. Durante la pulitura, utilizzate solo metodi sincroni per essere sicuri che vengano completati prima dell'uscita dall'applicazione.

    Se l'ordine di chiusura delle finestre non conta, è possibile iniziare a cercare nell'array NativeApplication.nativeApplication.openedWindows e chiudere ciascuna finestra a turno. Se l'ordine conta , fornite un sistema per chiudere le finestre nella sequenza corretta.

    private function onExiting(exitingEvent:Event):void { 
        var winClosingEvent:Event; 
        for each (var win:NativeWindow in NativeApplication.nativeApplication.openedWindows) { 
            winClosingEvent = new Event(Event.CLOSING,false,true); 
            win.dispatchEvent(winClosingEvent); 
            if (!winClosingEvent.isDefaultPrevented()) { 
                win.close(); 
            } else { 
                exitingEvent.preventDefault(); 
            } 
        } 
         
        if (!exitingEvent.isDefaultPrevented()) { 
            //perform cleanup 
        } 
    } 
  3. Le finestre dovrebbero sempre gestire la propria pulitura "ascoltando" i relativi eventi closing .

  4. Utilizzate un solo listener exiting nell'applicazione, dal momento che i gestori non sono in grado di sapere se gestori successivi annulleranno l'evento exiting e sarebbe poco saggio affidarsi all'ordine di esecuzione.