As of Adobe AIR 2, AIR applications can run and communicate with
other native processes via the command line. For example, an AIR
application can run a process and communicate with it via the standard
input and output streams.
To communicate with native processes, package an AIR application
to be installed via a native installer. The file type of native
installer is specific to the operating system for which it is created:
-
It is a DMG file on Mac OS.
-
It is an EXE file on Windows.
-
It is an RPM or DEB package on Linux.
These applications are known as extended desktop profile applications.
You can create a native installer file by specifying the
-target native
option
when calling the
-package
command using ADT.
Overview of native process communications
An AIR application in the extended desktop profile can execute
a file, as if it were invoked by the command line. It can communicate
with the standard streams of the native process. Standard streams
include the standard input stream (stdin), the output stream (stdout),
the standard error stream (stderr).
Note:
Applications in the extended desktop profile can also launch
files and applications using the
File.openWithDefaultApplication()
method.
However, using this method does not provide the AIR application
with access to the standard streams. For more information, see
Opening files with the default system application
The following code sample shows how to launch a test.exe application
in the application directory. The application passes the argument
"hello"
as
a command-line argument, and it adds an event listener to the process’s
standard output stream:
var nativeProcessStartupInfo = new air.NativeProcessStartupInfo();
var file = air.File.applicationDirectory.resolvePath("test.exe");
nativeProcessStartupInfo.executable = file;
var processArgs = new air.Vector["<String>"]();
processArgs.push("hello");
nativeProcessStartupInfo.arguments = processArgs;
process = new air.NativeProcess();
process.addEventListener(air.ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
process.start(nativeProcessStartupInfo);
public function onOutputData(event)
{
var stdOut = process.standardOutput;
var data = stdOut.readUTFBytes(process.standardOutput.bytesAvailable);
air.trace("Got: ", data);
}
Launching and closing a native process
To launch a native process, set up a NativeProcessInfo object
to do the following:
-
Point to the file you want to launch
-
Store command-line arguments to pass to the process when
launched (optional)
-
Set the working directory of the process (optional)
To start the native process, pass the NativeProcessInfo object
as the parameter of the
start()
method of a NativeProcess
object.
For example, the following code shows how to launch a test.exe
application in the application directory. The application passes
the argument
"hello"
and sets the user’s documents
directory as the working directory:
var nativeProcessStartupInfo = new NativeProcessStartupInfo();
var file = air.File.applicationDirectory.resolvePath("test.exe");
nativeProcessStartupInfo.executable = file;
var processArgs = new air.Vector["<String>"]();;
processArgs[0] = "hello";
nativeProcessStartupInfo.workingDirectory = air.File.documentsDirectory;
nativeProcessStartupInfo.arguments = processArgs;
process = new air.NativeProcess();
process.start(nativeProcessStartupInfo);
To terminate the process, call the
exit()
method
of the NativeProcess object.
If you want a file to be executable in your installed application,
make sure that it's executable on the file system when you package
your application. (On Mac and Linux, you can use chmod to set the
executable flag, if needed.)
Communicating with a native process
Once an AIR application has started a native process, it can
communicate with the standard input, standard output, and standard
error streams of the process.
You read and write data to the streams using the following properties
of the NativeProcess object:
-
standardInput
—Contains access to the
standard input stream data.
-
standardOutput
—Contains access to the standard
output stream data.
-
standardError
—Contains access to the standard
error stream data.
Writing to the standard input stream
You
can write data to the standard input stream using the write methods
of the
standardInput
property of the NativeProcess
object. As the AIR application writes data to the process, the NativeProcess
object dispatches
standardInputProgress
events.
If
an error occurs in writing to the standard input stream, the NativeProcess object
dispatches an
ioErrorStandardInput
event.
You
can close the input stream by calling the
closeInput()
method
of the NativeProcess object. When the input stream closes, the NativeProcess
object dispatches a
standardInputClose
event.
var nativeProcessStartupInfo = new NativeProcessStartupInfo();
var file = air.File.applicationDirectory.resolvePath("test.exe");
nativeProcessStartupInfo.executable = file;
process = new air.NativeProcess();
process.start(nativeProcessStartupInfo);
process.standardInput.writeUTF("foo");
if(process.running)
{
process.closeInput();
}
Reading from the standard output stream
You
can read data from the standard output stream using the read methods
of this property. As the AIR application gets output stream data
from the process, the NativeProcess object dispatches
standardOutputData
events.
If
an error occurs in writing to the standard output stream, the NativeProcess object
dispatches a
standardOutputError
event.
When
process closes the output stream, the NativeProcess object dispatches
a
standardOutputClose
event.
When reading
data from the standard input stream, be sure to read data as it
is generated. In other words, add an event listener for the
standardOutputData
event.
In the
standardOutputData
event listener, read
the data from the
standardOutput
property of the
NativeProcess object. Do not simply wait for the
standardOutputClose
event
or the
exit
event to read all data. If you do not
read data as the native process generates the data, the buffer can
fill up, or data can be lost. A full buffer can cause the native
process to stall when trying to write more data. However, if you
do not register an event listener for the
standardOutputData
event,
then the buffer will not fill and the process will not stall. In
this case, you will not have access to the data.
var nativeProcessStartupInfo = new NativeProcessStartupInfo();
var file = air.File.applicationDirectory.resolvePath("test.exe");
nativeProcessStartupInfo.executable = file;
process = new air.NativeProcess();
process.addEventListener(air.ProgressEvent.STANDARD_OUTPUT_DATA, dataHandler);
process.start(nativeProcessStartupInfo);
var bytes = new air.ByteArray();
function dataHandler(event)
{
bytes.writeBytes(process.standardOutput.readBytes(process.standardOutput.bytesAvailable);
}
Reading from the standard error stream
You
can read data from the standard error stream using the read methods
of this property. As the AIR application reads error stream data
from the process, the NativeProcess object dispatches
standardErrorData
events.
If
an error occurs in writing to the standard error stream, the NativeProcess
object dispatches an
standardErrorIoError
event.
When
process closes the error stream, the NativeProcess object dispatches
a
standardErrorClose
event.
When reading
data from the standard error stream, be sure to read data as it
is generated. In other words, add an event listener for the
standardErrorData
event.
In the
standardErrorData
event listener, read the
data from the
standardError
property of the NativeProcess
object. Do not simply wait for the
standardErrorClose
event
or the
exit
event to read all data. If you do not
read data as the native process generates the data, the buffer can
fill up, or data can be lost. A full buffer can cause the native
process to stall when trying to write more data. However, if you
do not register an event listener for the
standardErrorData
event,
then the buffer will not fill and the process will not stall. In
this case, you will not have access to the data.
var nativeProcessStartupInfo = new NativeProcessStartupInfo();
var file = air.File.applicationDirectory.resolvePath("test.exe");
nativeProcessStartupInfo.executable = file;
process = new air.NativeProcess();
process.addEventListener(air.ProgressEvent.STANDARD_ERROR_DATA, errorDataHandler);
process.start(nativeProcessStartupInfo);
var errorBytes = new air.ByteArray();
function errorDataHandler(event)
{
errorBytes.writeBytes(process.standardError.readBytes(process.standardError.bytesAvailable);
}
Security considerations for native process communication
The native process API can run any executable on the user’s system.
Take extreme care when constructing and executing commands. If any
part of a command to be executed originates from an external source,
carefully validate that the command is safe to execute. Likewise,
your AIR application should validate any data passed to a running
process.
However, validating input can be difficult. To avoid such difficulties,
it is best to write a native application (such as an EXE file on
Windows) that has specific APIs. These APIs should process only
those commands defined by the application. For example, the application
may accept only a limited set of instructions via the standard input
stream.
AIR on Windows does not allow you to run .bat files directly.
The command interpreter application (cmd.exe) executes Windows .bat
files. When you invoke a .bat file, this command application can
interpret arguments passed to the command as additional applications
to launch. A malicious injection of extra characters in the argument
string could cause cmd.exe to execute a harmful or insecure application.
For example, without proper data validation, your AIR application
may call
myBat.bat myArguments c:/evil.exe
. The
command application would launch the evil.exe application in addition
to running your batch file.
|
|
|