Chamada e encerramento do aplicativo do AIR

Adobe AIR 1.0 e posterior

Essa seção discute as formas através das quais um aplicativo Adobe® AIR® instalado pode ser invocado, bem como opções e considerações para fechar um aplicativo em execução.

Nota: Os objetos NativeApplication, InvokeEvent e BrowserInvokeEvent só estão disponíveis para o conteúdo SWF em execução na caixa de proteção do aplicativo do AIR. O conteúdo SWF que está sendo reproduzido no tempo de execução do Flash Play, dentro do navegador ou no player autônomo (projetor), ou em um aplicativo do AIR fora da caixa de proteção do aplicativo, não pode acessar essas classes.

Para ver uma rápida explicação e exemplos de código da chamada e encerramento de aplicativos AIR, consulte os seguintes artigos de início rápido no Adobe Developer Connection:

Chamada do aplicativo

Um aplicativo do AIR é invocado quando o usuário (ou o sistema operacional):

  • Inicia o aplicativo do shell da área de trabalho.

  • Usa o aplicativo como um comando em um shell de linha de comando.

  • Abre um tipo de arquivo para o qual o aplicativo é o aplicativo de abertura padrão.

  • (Mac OS X) clica no ícone do aplicativo na barra de tarefas do encaixe (esteja o aplicativo em execução ou não no momento).

  • Opta por inicializar o aplicativo do instalador (na extremidade de um novo processo de instalação ou após clicar duas vezes no arquivo do AIR para um aplicativo já instalado).

  • Começa uma atualização de um aplicativo do AIR quando a versão instalada tiver indicado que está lidando sozinha com atualizações do aplicativo (incluindo uma declaração <customUpdateUI>true</customUpdateUI> no arquivo de descrição do aplicativo).

  • (iOS) Recebe uma notificação do serviço de Notificação por Push da Apple (APNs).

  • Invoca o aplicativo por um URL.

  • Visita uma página da Web que hospeda um crachá ou aplicativo do Flash que chama o método com.adobe.air.AIR launchApplication() especificando as informações de identificação para o aplicativo do AIR. (O descritor do aplicativo também deve incluir uma declaração <allowBrowserInvocation>true</allowBrowserInvocation> para que a chamada do navegador seja bem-sucedida.)

Sempre que um aplicativo do AIR for invocado, o AIR despacha um objeto de tipo InvokeEvent invoke pelo objeto singleton NativeApplication. Para permitir que o tempo de um aplicativo se inicialize e registre um ouvinte de evento, eventos invoke são enfileirados em vez de descartados. Assim que um ouvinte é registrado, todos os eventos enfileirados são entregues.

Nota: Quando um aplicativo é chamado usando o recurso de chamada do navegador, o objeto NativeApplication emite somente um evento invoke se o aplicativo ainda não estiver em execução.

Para receber eventos invoke , chame o método addEventListener() do objeto NativeApplication ( NativeApplication.nativeApplication) . Quando um ouvinte de evento registra um evento invoke , ele também recebe todos os eventos invoke que ocorreram antes do registro. Eventos invoke enfileirados são despachados um de cada vez em um curto intervalo após a chamada para addEventListener() ser retornada. Se um novo evento invoke ocorrer durante esse processo, ele poderá ser despachado antes de um ou mais dos eventos enfileirados. Esse enfileiramento de eventos permite que você manipule qualquer evento invoke que tenha ocorrido antes de seu código de inicialização ser executado. Tenha em mente que, se você adicionar um ouvinte de evento depois na execução (depois da inicialização do aplicativo), ele ainda receberá todos os eventos invoke que ocorreram desde que o aplicativo foi iniciado.

Apenas uma instância de um aplicativo do AIR é iniciada. Quando um aplicativo já em execução é invocado novamente, o AIR despacha um novo evento invoke para a instância em execução. É de responsabilidade de um aplicativo do AIR responder a um evento invoke e executar a ação apropriada (como abrir uma janela de um novo documento).

Um objeto InvokeEvent contém qualquer argumento transmitido ao aplicativo, bem como o diretório a partir do qual o aplicativo foi invocado. Se o aplicativo foi invocado devido a uma associação de tipo de arquivo, todo o caminho para o arquivo será incluído nos argumentos de linha de comando. Da mesma forma, se o aplicativo foi invocado devido a uma atualização de aplicativo, todo o caminho para o arquivo do AIR atualizado será fornecido.

Quando vários arquivos são abertos em uma operação, um único objeto InvokeEvent é despachado no Mac OS X. Cada arquivo é incluído na matriz arguments . No Windows e no Linux, um objeto InvokeEvent distinto é despachado para cada arquivo.

Seu aplicativo pode manipular eventos invoke registrando um ouvinte com seu objeto NativeApplication:

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

E definindo um ouvinte de evento:

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

Captura de argumentos de linha de comando

Os argumentos de linha de comando associados à invocação de um aplicativo do AIR são entregues no objeto InvokeEvent despachado pelo objeto NativeApplication. A propriedade arguments do InvokeEvent contém uma matriz dos argumentos transmitidos pelo sistema operacional quando um aplicativo do AIR é invocado. Se os argumentos contêm caminhos de arquivos relativos, você pode normalmente resolver os caminhos usando a propriedade currentDirectory .

Os argumentos transmitidos a um programa do AIR são tratados como sequências delimitadas de espaço em branco, a menos que estejam entre aspas duplas:

Argumentos

Matriz

tick tock

{tick,tock}

tick "tick tock"

{tick,tick tock}

"tick" “tock”

{tick,tock}

\"tick\" \"tock\"

{"tick","tock"}

A propriedade currentDirectory de um objeto InvokeEvent contém um objeto File que representa o diretório a partir do qual o aplicativo foi iniciado.

Quando um aplicativo é invocado porque um arquivo de um tipo registrado pelo aplicativo é aberto, o caminho nativo para o arquivo é incluído nos argumentos de linha de comando como uma sequência de caracteres. (Seu aplicativo é responsável por abrir ou executar a operação pretendida no arquivo.) Da mesma forma, quando um aplicativo é programado para se atualizar (em vez de confiar na interface de usuário de atualização do AIR padrão), o caminho nativo para o arquivo do AIR é incluído quando um usuário clica duas vezes em um arquivo do AIR que contém um aplicativo com uma ID correspondente do aplicativo.

Você pode acessar o arquivo usando o método resolve() do objeto File currentDirectory :

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

Você também deve validar se um argumento é realmente um caminho para um arquivo.

Exemplo: log de eventos de invocação

O exemplo a seguir demonstra como registrar ouvintes para e manipular o evento invoke . O exemplo registra todos os eventos de invocação recebidos e exibe o diretório atual e os argumentos de linha de comando.

Exemplo do 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); 
        } 
    } 
} 

Exemplo do 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>

Invocando um aplicativo do AIR no logon do usuário

Um aplicativo do AIR pode ser definido para ser inicializado automaticamente quando o usuário atual faz login definindo a propriedade StartAtLogi do NativeApplication como true . Depois de definido, o aplicativo é iniciado automaticamente sempre que o usuário fizer login. Ele continua a ser aberto no logon até que a configuração seja alterada para false , o usuário altera manualmente a configuração pelo sistema operacional ou o aplicativo é desinstalado. A inicialização no logon é uma configuração de tempo de execução. A configuração se aplica apenas ao usuário atual. O aplicativo deve ser instalado para definir com êxito a propriedade startAtLogin como true . Um erro é lançado se a propriedade for definida quando um aplicativo não está instalado (como quando ele é inicializado com o ADL).

Nota: O aplicativo não é iniciado quando o sistema do computador é iniciado. Ele é iniciado quando o usuário faz login.

Para determinar se um aplicativo foi iniciado automaticamente ou como resultado de uma ação do usuário, você pode examinar a propriedade reason do objeto InvokeEvent. Se a propriedade foi igual a InvokeEventReason.LOGIN , então o aplicativo é iniciado automaticamente. Para outros caminhos de invocação, a propriedade reason é definida da seguinte maneira:

  • InvokeEventReason.NOTIFICATION (somente iOS) - O aplicativo foi invocado por APNs. Para obter mais informações sobre APNs, consulte Usar notificações por push .

  • InvokeEventReason.OPEN_URL - O aplicativo foi invocado por outro aplicativo ou pelo sistema.

  • InvokeEventReason.Standard - Todos os demais casos.

Para acessar a propriedade reason , seu aplicativo deve se focalizar no AIR 1.5.1 ou superior (definindo o valor correto de namespace no arquivo de descrição do aplicativo).

O aplicativo simplificado a seguir usa a propriedade reason do InvokeEvent para decidir como se comportar quando ocorre um evento invoke. Se a propriedade reason for "login", o aplicativo continua em plano de fundo. Do contrário, ele torna o aplicativo principal visível. O aplicativo que usa esse padrão em geral é iniciado no logon, de forma que possa realizar o processamento de fundo ou o monitoramento do evento e abre uma janela em resposta a um evento invoke disparador pelo usuário.

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: Para ver a diferença no comportamento, empacote e instale o aplicativo. A propriedade startAtLogin só pode ser definida para os aplicativos instalados.

Invocação de um aplicativo do AIR do navegador

Usando o recurso de invocação do navegador, um site da Web pode inicializar um aplicativo instalado do AIR do navegador. A chamada do navegador é permitida apenas se o arquivo descritor do aplicativo definir allowBrowserInvocation como true :

<allowBrowserInvocation>true</allowBrowserInvocation>

Quando o aplicativo é invocado pelo navegador, o objeto NativeApplication do aplicativo despacha um objeto BrowserInvokeEvent.

Para receber eventos BrowserInvokeEvent, chame o método addEventListener() do objeto NativeApplication ( NativeApplication.nativeApplication ) no aplicativo do AIR. Quando um ouvinte de evento registra um evento BrowserInvokeEvent, ele também recebe todos os eventos BrowserInvokeEvent que ocorreram antes do registro. Esses eventos são despachados depois que a chamada a addEventListener() retorna, mas não necessariamente antes de outros eventos BrowserInvokeEvent, que podem ser recebidos depois do registro. Isso permite que você manipule os eventos BrowserInvokeEvent ocorridos antes que seu código de inicialização fosse executado (por exemplo, quando o aplicativo foi inicialmente invocado do navegador). Tenha em mente que, se você adicionar um ouvinte de evento depois na execução (depois da inicialização do aplicativo), ele ainda receberá todos os eventos BrowserInvokeEvent ocorridos desde que o aplicativo foi iniciado.

O objeto BrowserInvokeEvent inclui as seguintes propriedades:

Propriedade

Descrição

argumentos

Uma matriz de argumentos (sequências de caracteres) para transmitir ao aplicativo.

isHTTPS

Se o conteúdo do navegador usa o esquema de URL https ( true ) ou não ( false ).

isUserEvent

Se a invocação do navegador resultou em um evento de usuário (como clique do mouse). No AIR 1.0, este ajuste é sempre true ; o AIR exige um evento de usuário para o recurso de invocação do navegador.

sandboxType

O tipo de caixa de proteção para o conteúdo do navegador. Valores válidos são definidos como aqueles que podem ser usados na propriedade Security.sandboxType e podem ser um dos seguintes:

  • Security.APPLICATION – O conteúdo está na caixa de proteção de segurança do aplicativo.

  • Security.LOCAL_TRUSTED – O conteúdo está na caixa de proteção de segurança local com sistema de arquivos.

  • Security.LOCAL_WITH_FILE – O conteúdo está na caixa de proteção de segurança local com sistema de arquivos.

  • Security.LOCAL_WITH_NETWORK – O conteúdo está na caixa de proteção de segurança local com rede.

  • Security.REMOTE — O conteúdo está em um domínio remoto (de rede).

securityDomain

O domínio de segurança para o conteúdo do navegador, como "www.adobe.com" ou "www.example.org" . Essa propriedade é definida apenas para conteúdo na caixa de proteção de segurança remota (para conteúdo de um domínio de rede). Ele não é definido para conteúdo em uma caixa de proteção de segurança local ou do aplicativo.

Se você usa o recurso de invocação do navegador, certifique-se de considerar implicações de segurança. Quando um site da Web inicia um aplicativo do AIR, ele pode enviar dados pela propriedade arguments do objeto BrowserInvokeEvent. Cuidado ao usar esses dados em qualquer operação confidencial, como carregar código ou arquivo de APIs. Esse nível de risco depende do que o aplicativo está fazendo com os dados. Se você espera apenas um site da Web específico para invocar o aplicativo, o aplicativo deve verificar a propriedade securityDomain do objeto BrowserInvokeEvent. Você também pode exigir que o site invoque o aplicativo para usar HTTPs, o que você pode verificar marcando a propriedade isHTTPS do objeto BrowserInvokeEvent.

O aplicativo deve validar os dados transmitidos. Por exemplo, se um aplicativo espera para transmitir URLs a um domínio específico, ele deve validar se as URLs realmente apontam para aquele domínio. Isso pode impedir que um invasor engane o aplicativo para lhe enviar dados confidenciais.

Nenhum aplicativo deve usar argumentos BrowserInvokeEvent que possam apontar para recursos locais. Por exemplo, um aplicativo não deve criar objetos File com base em um caminho transmitido do navegador. Se espera-se que caminhos remotos sejam transmitidos do navegador, o aplicativo deve garantir que os caminhos não usem o protocolo file:// em vez de um protocolo remoto.

Encerramento do aplicativo

A forma mais rápida de encerrar um aplicativo é chamar o método exit() do NativeApplication. Isso funciona bem quando seu aplicativo não tem dados para salvar ou recursos externos para limpar. Chamar exit() fecha todas as janelas e, em seguida, encerra o aplicativo. No entanto, para permitir que janelas ou outros componentes do seu aplicativo interrompam o processo de encerramento, talvez para salvar dados vitais, despache os eventos de aviso adequados antes de chamar exit() .

Outra consideração sobre como fechar um aplicativo graciosamente é fornecer um único caminho de execução, sem importar como o processo de encerramento é iniciado. O usuário (ou sistema operacional) pode disparar o encerramento do aplicativo das seguintes maneiras:

  • Fechando a última janela do aplicativo quando NativeApplication.nativeApplication.autoExit for true .

  • Selecionando o comando de saída do aplicativo do sistema operacional; por exemplo, quando o usuário escolhe o comando de sair do aplicativo do menu padrão. (Isso só ocorre com o Mac OS. O Windows e o Linux não fornecem um comando de saída do aplicativo por meio do cromo do sistema.)

  • Desligando o computador.

Quando um comando de saída é mediado pelo sistema operacional por uma dessas rotas, o NativeApplication despacha um evento exiting . Se nenhum ouvinte cancelar o evento exiting , qualquer janela aberta será fechada. Cada janela despacha um evento closing e, em seguida, um close . Se alguma das janelas cancelar o evento closing , o processo de encerramento será interrompido.

Se a ordem do fechamento das janelas for um problema para o seu aplicativo, ouça o evento exiting do NativeApplication e feche você mesmo as janelas na ordem adequada. Talvez você precise fazer isso, por exemplo, se tiver uma janela de documento com as paletas da ferramenta. Poderia ser inconveniente, ou pior, se o sistema fechou as paletas, mas o usuário decidiu cancelar o comando de sair para salvar alguns dados. No Windows, o único momento que você obterá o evento exiting é depois de fechar a última janela (quando a propriedade autoExit do objeto NativeApplication for definida como true ).

Para fornecer um comportamento consistente em todas as plataformas, seja a sequência de saída iniciada pelo cromo do sistema operacional, por comandos de menu ou pela lógica do aplicativo, observe as seguintes práticas recomendadas para sair do aplicativo:

  1. Sempre despache um evento exiting pelo objeto NativeApplication antes de chamar exit() no código do aplicativo e verifique se outro componente do seu aplicativo não cancela o 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. Ouça o evento exiting do aplicativo do objeto NativeApplication.nativeApplication e, no manipulador, feche qualquer janela (despachando um evento closing primeiro). Execute qualquer tarefa de limpeza necessária, como salvar dados de aplicativo ou excluir arquivos temporários, após todas as janelas terem sido fechadas. Apenas use métodos síncronos durante a limpeza para garantir que eles sejam concluídos antes que o aplicativo seja encerrado.

    Se a ordem na qual suas janelas forem fechadas não importar, você pode efetuar um loop pela matriz NativeApplication.nativeApplication.openedWindows e fechar cada janela sucessivamente. Se a ordem importar , forneça um modo de fechar as janelas na sequência correta.

    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. As janelas devem sempre manipular sua própria limpeza ouvindo seus próprios eventos closing .

  4. Use apenas um ouvinte exiting no seu aplicativo uma vez que manipuladores chamados anteriormente não podem saber se os manipuladores subsequentes irão cancelar o evento exiting (e não seria inteligente confiar na ordem de execução).