This section
discusses the ways in which an installed Adobe® AIR® application
can be invoked, as well as options and considerations for closing
a running application.
Note:
The NativeApplication, InvokeEvent, and BrowserInvokeEvent
objects are only available to SWF content running in the AIR application
sandbox. SWF content running in the Flash Player runtime, within
the browser or the standalone player (projector), or in an AIR application
outside the application sandbox, cannot access these classes.
For a quick explanation and code examples of invoking and terminating
AIR applications, see the following quick start articles on the
Adobe Developer Connection:
Application invocation
An AIR application is invoked when
the user (or the operating system):
-
Launches the application from the desktop shell.
-
Uses the application as a command on a command line shell.
-
Opens a type of file for which the application is the default
opening application.
-
(Mac OS X) clicks the application icon in the dock taskbar
(whether or not the application is currently running).
-
Chooses to launch the application from the installer (either
at the end of a new installation process, or after double-clicking
the AIR file for an already installed application).
-
Begins an update of an AIR application when the installed
version has signaled that it is handling application updates itself
(by including a
<customUpdateUI>true</customUpdateUI>
declaration
in the application descriptor file).
-
(iOS) Receives a notification from the Apple Push Notification
service (APNs).
-
Invokes the application via a URL.
-
Visits a web page hosting a Flash badge or application that
calls
com.adobe.air.AIR launchApplication()
method
specifying the identifying information for the AIR application.
(The application descriptor must also include a
<allowBrowserInvocation>true</allowBrowserInvocation>
declaration
for browser invocation to succeed.)
Whenever an AIR
application is invoked, AIR dispatches an InvokeEvent object of type
invoke
through
the singleton NativeApplication object. To allow an application
time to initialize itself and register an event listener,
invoke
events
are queued instead of discarded. As soon as a listener is registered,
all the queued events are delivered.
Note:
When an application is invoked using the browser
invocation feature, the NativeApplication object only dispatches
an
invoke
event if the application is not already
running.
To
receive
invoke
events, call the
addEventListener()
method
of the NativeApplication object (
NativeApplication.nativeApplication)
. When
an event listener registers for an
invoke
event,
it also receives all
invoke
events that occurred
before the registration. Queued
invoke
events are dispatched
one at a time on a short interval after the call to
addEventListener()
returns.
If a new
invoke
event occurs during this process,
it may be dispatched before one or more of the queued events. This event
queuing allows you to handle any
invoke
events
that have occurred before your initialization code executes. Keep
in mind that if you add an event listener later in execution (after
application initialization), it will still receive all
invoke
events
that have occurred since the application started.
Only one instance of an AIR application is started. When an already
running application is invoked again, AIR dispatches a new
invoke
event
to the running instance. It is the responsibility of an AIR application
to respond to an
invoke
event and take the appropriate
action (such as opening a new document window).
An
InvokeEvent
object
contains any arguments passed to the application, as well as the
directory from which the application has been invoked. If the application
was invoked because of a file-type association, then the full path
to the file is included in the command line arguments. Likewise,
if the application was invoked because of an application update,
the full path to the update AIR file is provided.
When multiple files are opened in one operation a single InvokeEvent
object is dispatched on Mac OS X. Each file is included in the
arguments
array.
On Windows and Linux, a separate InvokeEvent object is dispatched
for each file.
Your application can handle
invoke
events by
registering a listener with its NativeApplication object:
NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvokeEvent);
And defining an event listener:
var arguments:Array;
var currentDir:File;
public function onInvokeEvent(invocation:InvokeEvent):void {
arguments = invocation.arguments;
currentDir = invocation.currentDirectory;
}
Capturing command line arguments
The
command line arguments associated with the invocation of an AIR
application are delivered in the InvokeEvent object dispatched by
the NativeApplication object. The InvokeEvent
arguments
property
contains an array of the arguments passed by the operating system
when an AIR application is invoked. If the arguments contain relative
file paths, you can typically resolve the paths using the
currentDirectory
property.
The arguments passed to an AIR program are treated as white-space
delimited strings, unless enclosed in double quotes:
Arguments
|
Array
|
tick tock
|
{tick,tock}
|
tick "tick tock"
|
{tick,tick tock}
|
"tick" “tock”
|
{tick,tock}
|
\"tick\" \"tock\"
|
{"tick","tock"}
|
The
currentDirectory
property of an InvokeEvent
object contains a File object representing the directory from which
the application was launched.
When an application is invoked
because a file of a type registered by the application is opened,
the native path to the file is included in the command line arguments
as a string. (Your application is responsible for opening or performing the
intended operation on the file.) Likewise, when an application is programmed
to update itself (rather than relying on the standard AIR update user
interface), the native path to the AIR file is included when a user
double-clicks an AIR file containing an application with a matching
application ID.
You can access the file using the
resolve()
method
of the
currentDirectory
File object:
if((invokeEvent.currentDirectory != null)&&(invokeEvent.arguments.length > 0)){
dir = invokeEvent.currentDirectory;
fileToOpen = dir.resolvePath(invokeEvent.arguments[0]);
}
You should also validate that an argument is indeed a path to
a file.
Example: Invocation event log
The following example demonstrates how to register listeners
for and handle the
invoke
event. The example logs
all the invocation events received and displays the current directory
and command line arguments.
ActionScript example
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 example
<?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>
Invoking an AIR application on user login
An AIR application
can be set to launch automatically when the current user logs in
by setting the NativeApplication
startAtLogin
property
to
true
. Once set, the application automatically
starts whenever the user logs in. It continues to launch at login
until the setting is changed to
false
, the user
manually changes the setting through the operating system, or the
application is uninstalled. Launching at login is a run-time setting.
The setting only applies to the current user. The application must
be installed to successfully set the
startAtLogin
property
to
true
. An error is thrown if the property is
set when an application is not installed (such as when it is launched
with ADL).
Note:
The application does not launch when the computer
system starts. It launches when the user logs in.
To determine whether an application has launched automatically
or as a result of a user action, you can examine the
reason
property
of the InvokeEvent object. If the property is equal to
InvokeEventReason.LOGIN
,
then the application started automatically. For other invocation
paths, the
reason
property is set as follows:
-
InvokeEventReason.NOTIFICATION
(iOS
only) - The application was invoked through APNs. For more information
on APNs, see
Use
push notifications
.
-
InvokeEventReason.OPEN_URL
- The application
was invoked by another application or by the system.
-
InvokeEventReason.Standard
- All other cases.
To access the
reason
property, your application
must target AIR 1.5.1 or higher (by setting the correct namespace
value in the application descriptor file).
The following, simplified application uses the InvokeEvent reason
property to decide how to behave when an invoke event occurs. If
the reason property is "login", then the application remains in
the background. Otherwise, it makes the main application visible.
An application using this pattern typically starts at login so that
it can carry out background processing or event monitoring and opens
a window in response to a user-triggered invoke event.
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();
}
}
}
}
Note:
To see the difference in behavior, package and install the
application. The
startAtLogin
property can only
be set for installed applications.
Invoking an AIR application from the browser
Using the browser invocation
feature, a web site can launch an installed AIR application to be
launched from the browser. Browser invocation is only permitted
if the application descriptor file sets
allowBrowserInvocation
to
true
:
<allowBrowserInvocation>true</allowBrowserInvocation>
When the application is invoked via the browser, the application’s
NativeApplication object dispatches a BrowserInvokeEvent object.
To receive
BrowserInvokeEvent events, call the
addEventListener()
method
of the NativeApplication object (
NativeApplication.nativeApplication
)
in the AIR application. When an event listener registers for a BrowserInvokeEvent
event, it also receives all BrowserInvokeEvent events that occurred
before the registration. These events are dispatched after the call
to
addEventListener()
returns, but not necessarily
before other BrowserInvokeEvent events that might be received after registration.
This allows you to handle BrowserInvokeEvent events that have occurred
before your initialization code executes (such as when the application was
initially invoked from the browser). Keep in mind that if you add
an event listener later in execution (after application initialization)
it still receives all BrowserInvokeEvent events that have occurred
since the application started.
The BrowserInvokeEvent
object includes the following properties:
Property
|
Description
|
arguments
|
An array of arguments (strings) to pass
to the application.
|
isHTTPS
|
Whether the content in the browser uses
the https URL scheme (
true
) or not (
false
).
|
isUserEvent
|
Whether the browser invocation resulted
in a user event (such as a mouse click). In AIR 1.0, this is always
set to
true
; AIR requires a user event to the browser
invocation feature.
|
sandboxType
|
The sandbox type for the content in the
browser. Valid values are defined the same as those that can be
used in the
Security.sandboxType
property, and
can be one of the following:
-
Security.APPLICATION
—
The content is in the application security sandbox.
-
Security.LOCAL_TRUSTED
— The content is
in the local-with-filesystem security sandbox.
-
Security.LOCAL_WITH_FILE
— The content is
in the local-with-filesystem security sandbox.
-
Security.LOCAL_WITH_NETWORK
— The content
is in the local-with-networking security sandbox.
-
Security.REMOTE
— The content is in a remote
(network) domain.
|
securityDomain
|
The security domain for the content in the
browser, such as
"www.adobe.com"
or
"www.example.org"
. This
property is only set for content in the remote security sandbox
(for content from a network domain). It is not set for content in
a local or application security sandbox.
|
If
you use the browser invocation feature, be sure to consider security
implications. When a web site launches an AIR application, it can
send data via the
arguments
property of the BrowserInvokeEvent
object. Be careful using this data in any sensitive operations,
such as file or code loading APIs. The level of risk depends on
what the application is doing with the data. If you expect only
a specific web site to invoke the application, the application should
check the
securityDomain
property of the BrowserInvokeEvent
object. You can also require the web site invoking the application
to use HTTPs, which you can verify by checking the
isHTTPS
property
of the BrowserInvokeEvent object.
The
application should validate the data passed in. For example, if
an application expects to be passed URLs to a specific domain, it
should validate that the URLs really do point to that domain. This
can prevent an attacker from tricking the application into sending
it sensitive data.
No application should use BrowserInvokeEvent arguments that might
point to local resources. For example, an application should not
create File objects based on a path passed from the browser. If
remote paths are expected to be passed from the browser, the application
should ensure that the paths do not use the
file://
protocol
instead of a remote protocol.
Application termination
The quickest way
to terminate an application is to call the NativeApplication exit()
method. This works fine when your application has no data to save
or external resources to clean up. Calling
exit()
closes
all windows and then terminates the application. However, to allow
windows or other components of your application to interrupt the
termination process, perhaps to save vital data, dispatch the proper
warning events before calling
exit()
.
Another consideration in gracefully shutting down an application
is providing a single execution path, no matter how the shut-down
process starts. The user (or operating system) can trigger application
termination in the following ways:
-
By closing the
last application window when
NativeApplication.nativeApplication.autoExit
is
true
.
-
By selecting the application exit command from the operating
system; for example, when the user chooses the exit application
command from the default menu. (This only happens on Mac OS; Windows
and Linux do not provide an application exit command through system
chrome.)
-
By shutting down the computer.
When an exit command is mediated through the
operating system by one of these routes, the NativeApplication dispatches
an
exiting
event. If no listeners cancel the
exiting
event,
any open windows are closed. Each window dispatches a
closing
and
then a
close
event. If any of the windows cancel
the
closing
event, the shut-down process stops.
If the order of window closure is an issue for your application,
listen for the
exiting
event from the NativeApplication
and close the windows in the proper order yourself. You might need
to do this, for example, if you have a document window with tool
palettes. It could be inconvenient, or worse, if the system closed
the palettes, but the user decided to cancel the exit command to
save some data. On Windows, the only time you will get the
exiting
event
is after closing the last window (when the
autoExit
property
of the NativeApplication object is set to
true
).
To provide consistent behavior on all platforms, whether the
exit sequence is initiated via operating system chrome, menu commands,
or application logic, observe the following good practices for exiting
the application:
-
Always dispatch an
exiting
event through
the NativeApplication object before calling
exit()
in
application code and check that another component of your application
doesn’t cancel the event.
public function applicationExit():void {
var exitingEvent:Event = new Event(Event.EXITING, false, true);
NativeApplication.nativeApplication.dispatchEvent(exitingEvent);
if (!exitingEvent.isDefaultPrevented()) {
NativeApplication.nativeApplication.exit();
}
}
-
Listen for the application
exiting
event
from the
NativeApplication.nativeApplication
object
and, in the handler, close any windows (dispatching a
closing
event
first). Perform any needed clean-up tasks, such as saving application
data or deleting temporary files, after all windows have been closed.
Only use synchronous methods during cleanup to ensure that they
finish before the application quits.
If the order in which
your windows are closed doesn’t matter, then you can loop through
the
NativeApplication.nativeApplication.openedWindows
array and
close each window in turn. If order
does
matter, provide
a means of closing the windows in the correct sequence.
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
}
}
-
Windows should always handle their own clean up by listening
for their own
closing
events.
-
Only use one
exiting
listener in your application
since handlers called earlier cannot know whether subsequent handlers
will cancel the
exiting
event (and it would be
unwise to rely on the order of execution).
|
|
|