Запуск и завершение приложения AIR

Adobe AIR 1.0 и более поздних версий

В настоящем разделе обсуждаются способы запуска установленного приложения Adobe® AIR®, а также параметры закрытия, и, наконец, соображения относительно закрытия работающего приложения.

Примечание. Для запуска содержимого SWF, работающего в изолированной программной среде приложения AIR, доступны только объекты NativeApplication, InvokeEvent и BrowserInvokeEvent. Содержимое SWF, воспроизводимое приложением Flash Player, браузером, отдельным проигрывателем (проектором) или приложением AIR вне изолированной программной среды, не имеет доступа к эти классам.

Краткое разъяснение и примеры кодов с запуском и завершением работы приложений AIR см. в следующих статьях по быстрому началу работы в центре Adobe Developer Connection:

Вызов приложения

Приложение AIR вызывается, когда пользователь (или операционная система):

  • запускает приложение с рабочего стола;

  • Указывает приложение в качестве команды в командной строке.

  • открывает тип файла, для которого данное приложение является приложением по умолчанию;

  • щелкает по значку приложения в панели задач Dock в Mac OS (неважно, запущено ли уже приложение);

  • запускает приложение из программы установки (в конце процесса установки либо после двойного щелчка по файлу AIR уже установленного приложения);

  • начинает обновление приложения AIR, когда установленная версия сообщает, что уже обрабатывает обновления (с помощью объявления <customUpdateUI>true</customUpdateUI> в файле дескриптора);

  • в ОС iOS: получает уведомление через службу push-уведомлений Apple (Apple Push Notification service, APNs);

  • вызывает приложение посредством URL-ссылки;

  • посещает веб-страницу с элементом Flash badge или приложением, вызывающим метод com.adobe.air.AIR launchApplication() , задающий информацию для приложения AIR. (Дескриптор приложения должен содержать объявление <allowBrowserInvocation>true</allowBrowserInvocation> для вызова обозревателя.)

При вызове приложения AIR среда AIR отправляет объект InvokeEvent типа invoke через единственный объект NativeApplication. Чтобы приложение успело инициализироваться и зарегистрировать прослушиватель событий, события invoke ставятся в очередь, а не сбрасываются. Как только прослушиватель регистрируется, все события в очереди доставляются.

Примечание. При вызове приложения с помощью функции запуска обозревателя объект NativeApplication отправляет событие invoke только в случае, если приложение еще не запущено.

Для получения событий invoke вызовите метод addEventListener() объекта NativeApplication ( NativeApplication.nativeApplication) . Когда прослушиватель события регистрируется на событие invoke , он также получает все события invoke , которые произошли до регистрации. События invoke , поставленные в очередь, отправляются по одному с небольшим интервалом после возвращения результатов вызова метода addEventListener() . Если во время этого процесса происходит новое событие invoke , оно может быть отправлено прежде, чем события из очереди. Постановка событий в очередь позволяет обрабатывать события invoke , которые произошли до выполнения кода инициализации. Помните, что при добавлении прослушивателя далее в процессе выполнения (после инициализации приложения), он все равно будет получать все события invoke , случившиеся с момента запуска приложения.

Запускается только один экземпляр приложения AIR. При повторном вызове уже запущенного приложения среда AIR отправляет новое событие invoke работающему экземпляру. Приложение AIR должно ответить на событие invoke соответствующим действием (например, открыть документ в новом окне).

Объект InvokeEvent может содержать любые аргументы, передаваемые приложению, а также каталог, из которого приложение запускается. Если приложение запущено в результате открытия ассоциированного с ним типа файла, то полный путь к файлу включается в аргументы командной строки. Точно так же, если приложение запущено в результате обновления, предоставляется полный путь к файлу обновления AIR.

Если в одной операции открывается сразу несколько файлов, в Mac OS X создается один объект InvokeEvent. Каждый файл включается в массив arguments . В операционных системах Windows и Linux отдельный объект InvokeEvent создается для каждого файла.

Приложение может обрабатывать события invoke путем регистрации прослушивателя с объектом NativeApplication:

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

и определения прослушивателя событий:

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

Захват аргументов командной строки

Аргументы командной строки, ассоциируемые с вызовом приложения AIR, доставляются в объект InvokeEvent, который отправляется объектом NativeApplication. Свойство InvokeEvent arguments содержит массив аргументов, передаваемых операционной системой при вызове приложения AIR. Если аргументы содержат относительные пути к файлам, то их обычно можно обработать с помощью свойства currentDirectory .

Аргументы, передаваемые приложению AIR, обрабатываются как строки, разделенные пробелами, если только они не заключены в двойные кавычки:

Аргументы

Массив

tick tock

{tick,tock}

tick "tick tock"

{tick,tick tock}

"tick" “tock”

{tick,tock}

\"tick\" \"tock\"

{"tick","tock"}

Свойство currentDirectory объекта InvokeEvent содержит объект File, представляющий каталог, из которого запускалось приложение.

Когда приложение вызывается в результате открытия типа файла, ассоцииированного с приложением, исходный путь к файлу включается в строковом виде в аргументы командной строки. (Приложение отвечает за открытие файла или выполнение любой другой операции над ним). Точно так же, когда механизм обновления содержится в самом приложении (а не в стандартном пользовательском интерфейсе AIR), исходный путь к файлу AIR включается, когда пользователь дважды щелкает по файлу AIR, содержащему приложение с совпадающим ID.

Доступ к файлу можно получить методом resolve() объекта File currentDirectory :

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

Также необходимо проверить, действительно ли аргумент является путем к файлу.

Пример: вызов журнала событий

В этом примере показано, как регистрировать прослушиватели и обрабатывать события invoke . В примере все полученные события вызова заносятся в журнал, после чего отображается текущий каталог и аргументы командной строки.

Пример 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); 
        } 
    } 
} 

Пример 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>

Запуск приложения AIR по имени входа пользователя

Приложение AIR может запускаться автоматически, когда текущий пользователь входит в систему. Для этого необходимо задать свойству startAtLogin класса NativeApplication значение true . После этого приложение будет автоматически запускаться при входе пользователя в систему. Такое положение дел сохранится до тех пор, пока значение не будет изменено на false , пока пользователь не изменит этот параметр вручную в операционной системе, или пока приложение не будет удалено. Запуск при входе является параметром времени выполнения. Этот параметр относится только к конкретному пользователю. Чтобы задать для свойства startAtLogin значение true , приложение должно быть установлено. Если свойство задается, пока приложение не установлено (а, например, запущено через ADL), генерируется ошибка.

Примечание. Приложение открывается не при запуске системы, а при входе в нее пользователя.

Чтобы определить, запущено ли приложение автоматически или в результате действий пользователя, нужно проверить значение свойства reason объекта InvokeEvent. Если значение свойства равно InvokeEventReason.LOGIN , приложение запускается автоматически. В случае если приложение вызвано другим путем, свойство reason получает следующие значения:

  • InvokeEventReason.NOTIFICATION (только для iOS) — приложение было вызвано через службу APNs. Дополнительные сведения о службе APNs приведены в разделе Использование push-уведомлений .

  • InvokeEventReason.OPEN_URL — приложение было вызвано из другого приложения или системы.

  • InvokeEventReason.Standard — все прочие случаи.

Для доступа к свойству reason приложение должно быть предназначено для AIR 1.5.1 или более поздней версии (путем задания правильного значения пространства имен в файле дескриптора приложения).

Приведенное ниже простое приложение использует свойство reason объекта InvokeEvent, чтобы определить дальнейшее поведение при реализации события запуска. Если свойство reason имеет значение «login», приложение остается в фоновом режиме. В противном случае оно делает главное приложение видимым. Приложение, использующее этот путь, как правило, запускается при вводе имени входа, так что оно может работать в фоновом режиме или производить мониторинг событий, и открывает окно в ответ на событие запуска, инициированное пользователем.

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(); 
            } 
        } 
    } 
}
Примечание. Чтобы увидеть разницу в поведении приложения, упакуйте и установите приложение. Свойство startAtLogin может быть задано только для установленных приложений.

Запуск приложения AIR из браузера

Веб-сайт может с помощью функции вызова из обозревателя запускать установленное приложение AIR, запуск которого предусмотрен из обозревателя. Вызов из обозревателя разрешается, только если в файле дескриптора приложения allowBrowserInvocation равно true :

<allowBrowserInvocation>true</allowBrowserInvocation>

Когда приложение вызывается из обозревателя, его объект NativeApplication отправляет объект BrowserInvokeEvent.

Для получения событий BrowserInvokeEvent вызовите метод addEventListener() объекта NativeApplication ( NativeApplication.nativeApplication ) в приложении AIR. Когда прослушиватель события регистрируется на событие BrowserInvokeEvent, он также получает все события BrowserInvokeEvent, которые произошли до регистрации. Эти события отправляются после возврата вызова addEventListener() , но необязательно раньше остальных событий BrowserInvokeEvent, которые могут быть получены после регистрации. Это позволяет обрабатывать события BrowserInvokeEvent, которые происходят до выполнения кода инициализации (например, когда приложение изначально запускается из обозревателя). Помните, что при добавлении прослушивателя далее в процессе выполнения (после инициализации приложения), он все равно будет получать все события BrowserInvokeEvent, случившиеся с момента запуска приложения.

Ниже перечислены свойства объекта BrowserInvokeEvent.

Свойство

Описание

arguments

Массив аргументов (строк), передаваемых приложению.

isHTTPS

Указывает, испольлзует ли содержимое в обозревателе схему URL-адресов https ( true , если да, false , если нет).

isUserEvent

Указывает, привел ли вызов обозревателя к пользовательскому действию (например, щелчку мыши). В AIR 1.0 оно всегда имеет значение true ; в AIR пользовательское действие обязательно при вызове обозревателя.

sandboxType

Тип изолированной программной среды для содержимого в обозревателе. Действительны такие же значения, как для свойства Security.sandboxType , т. е. значения могут быть следующими:

  • Security.APPLICATION — содержимое находится в изолированной программной среде приложения.

  • Security.LOCAL_TRUSTED — содержимое находится в локальной изолированной программной среде файловой системы.

  • Security.LOCAL_WITH_FILE — содержимое находится в локальной изолированной программной среде файловой системы.

  • Security.LOCAL_WITH_NETWORK — содержимое находится в локальной изолированной программной средой с сетевым подключением.

  • Security.REMOTE — содержимое находится на удаленном (сетевом) домене.

securityDomain

Безопасный домен для содержимого в обозревателе, например "www.adobe.com" или "www.example.org" . Это свойство задается только для содержимого в удаленной защищенной изолированной программной среде (с сетевого домена). Для содержимого в локальной изолированной программной среде или изолированной программной среде приложения оно не задается.

Если используется функция вызова обозревателя, не забывайте об ограничениях безопасности. Когда веб-сайт запускает приложение AIR, данные могут передаваться через свойство arguments объекта BrowserInvokeEvent. При выполнении операций с конфиденциальными данными, например в API-интерфейсах файла или загрузки кода, с ними нужно обращаться очень осторожно. Уровень риска зависит от того, как приложение распоряжается данными. Если только определенный сайт может запускать приложение, необходимо проверить свойство securityDomain объекта BrowserInvokeEvent. Также можно требовать, чтобы веб-сайт, вызывающий приложение, использовал протокол HTTPs — такая информация содержится в свойстве isHTTPS объекта BrowserInvokeEvent.

Приложение должно проверять все передаваемые ему данные. Например, если приложение ожидает передачи URL-адресов определенного домена, необходимо удостовериться, что URL-адреса действительно ведут на этот домен. Таким образом можно оградить приложение от случайной отправки конфиденциальных данных злоумышленнику.

Приложение не должно использовать аргументы BrowserInvokeEvent, которые указывают на локальные ресурсы. Например, приложение не должно создавать объекты File на основе пути, передаваемого из обозревателя. Если от обозревателя ожидается передача удаленных путей, приложение должно проверить, не используется ли в них протокол file:// вместо протокола удаленного доступа.

Завершение работы приложения

Самым быстрым способом завершения приложения является вызов метода exit() класса NativeApplication. Он отлично работает, когда приложение не содержит данных, которые нужно сохранить, или внешних ресурсов, которые нужно очистить. Вызов метода exit() закрывает все окна и завершает работу приложения. Однако, чтобы окна и другие компоненты могли вмешиваться в процесс завершения работы, например для сохранения важных данных, отправляйте перед вызовом метода exit() соответствующие события уведомлений.

Другой способ закрыть приложение без лишних проблем — предоставить единый путь выполнения; при этом неважно, как начинается процесс закрытия. Пользователь (или операционная система) могут вызывать завершение приложения несколькими способами:

  • Закрытие последнего окна приложения, если NativeApplication.nativeApplication.autoExit равно true .

  • Выбор команды выхода из приложения через операционную систему, например, когда пользователь выбирает команду выхода из меню по умолчанию. (Это возможно только в Mac OS. В Windows и Linux нет команды выхода из приложения через системный Chrome.)

  • Выключение компьютера.

Когда команда выхода передается через операционную систему одним из указанных маршрутов, NativeApplication отправляет событие exiting . Если ни один из прослушивателей не отменяет событие exiting , закрываются все открытые окна. Каждое окно отправляет событие closing , а затем close . Если какие-либо окна отменяют событие closing , то процесс завершения работы прерывается.

Если в написанном вами приложении важен порядок закрытия, прослушивайте событие exiting объекта NativeApplication и закрывайте окна в нужном порядке. Вам это может потребоваться, например, при работе с окном документа, содержащим панель инструментов. Если система уже закрыла панели, но пользователь решил не выходить из приложения, а сначала сохранить данные, могут возникнуть сложности. В Windows событие exiting отправляется только после закрытия последнего окна (когда свойство autoExit объекта NativeApplication равно true ).

Чтобы поведение было одинаковым на всех платформах, следуйте приведенным ниже рекомендациям (неважно, каким образом было закрыто приложение: через системный Chrome, команды меню или логику приложения).

  1. Всегда отправляйте событие exiting через объект NativeApplication, и только потом вызывайте метод exit() в коде приложения, а также проверяйте, чтобы другой компонент приложения не отменил это событие.

    public function applicationExit():void { 
        var exitingEvent:Event = new Event(Event.EXITING, false, true); 
        NativeApplication.nativeApplication.dispatchEvent(exitingEvent); 
        if (!exitingEvent.isDefaultPrevented()) { 
            NativeApplication.nativeApplication.exit(); 
        } 
    } 
  2. Прослушивайте событие exiting в приложении из объекта NativeApplication.nativeApplication , а все окна закрывайте в обработчике (сначала необходимо отправить событие closing ). После закрытия окон выполняйте все необходимые задачи по очистке, например сохранение данных приложения, удаление временных файлов. Для очистки используйте только синхронные методы, чтобы они наверняка завершились, прежде чем закроется приложение.

    Если порядок закрытия окон неважен, можно пройти массив NativeApplication.nativeApplication.openedWindows и закрыть окна по очереди. Если порядок важен , включите механизм для закрытия окон в нужной последовательности.

    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. Все окна должны обрабатывать собственную очистку путем прослушивания своих событий closing .

  4. Не используйте в приложении более одного прослушивателя exiting , так как ранее вызванные обработчики не могут знать, отменят ли последующие обработчики событие exiting (а на порядок выполнения полагаться не стоит).