Recipe 18.1.
Creating Local Connections
Problem
You want to communicate from one or more Flash movie(s) to
another Flash movie playing on the same client computer.
Solution
Use the LocalConnection class in the
flash.net package to invoke a function in the receiving
movie from the sending movie. Use LocalConnection.connect( ) to
listen for messages in the receiving movie and define the function
that will be invoked. Use LocalConnection.send( ) from the
sending movie(s) to invoke a function in the remote movie. Both the
sending and receiving movies must specify the same named channel
for communication.
Discussion
When two or more Flash movies are playing on the
same client computer, they can communicate with one another via a
local connection created with the flash.net.LocalConnection
class. As long as the movies are playing on the same computer, a
connection can be made regardless of the domains from which the
movies are being served.
|
By default, movies accept communications from
movies on the same domain only. However, you can configure them to
receive from other domains as well. See Recipe
18.4.
|
|
To successfully communicate between multiple
movies on the same computer, you must do three things:
-
Configure the receiving movie to listen for
communications.
-
Tell the receiving movie what to do when
messages are received.
-
Send messages to the receiving movie from the
sending movie(s).
A receiving movie must listen for messages over
a specific, named local connection. To establish this communication
channel, you should create a local connection object in the
receiving movie and tell it to listen to a named connection using
the connect( )
method:
import flash.net.LocalConnection;
// Create the local connection object in the receiving movie.
var receiver:LocalConnection = new LocalConnection( );
// Instruct the local connection instance to listen for messages
// sent over the "_exampleChannel" channel.
receiver.connect( "_exampleChannel" );
As shown in the preceding example, the best
practice is to name your communication channel (not the local
connection object) with an initial underscore (_). Naming
your connections in this way also simplifies communicating across
domains. By starting the connection name with an underscore, the
Flash Player does not augment the connection name with
domain-specific information behind the scenes. When an underscore
is not the first character in the connection name, the connection
name string is converted into domain:connectionName
automatically, where domain is either the domain name that served
up the .swf file or local host when the .swf file is
run locally.
All communications over the local connection are
mapped by the receiving local connection instance. By default, the
receiving local connection object looks for methods defined on the
instance with the same name as the method sent in the request. For
example, if the sending movie sends a communication that looks for
a method named example( ), the receiving local connection
object looks for an example( ) method that it defines. In
previous versions of ActionScript, this was simply a matter of
creating a function and attaching it to the instance through a name
of example.
// Previous to ActionScript 3.0, this would create an example function
// that could be invoked through a local connection.
receiver.example = function ( ) {
output.text = "communication received";
};
However, in ActionScript 3.0, this will not
work. By default, the LocalConnection class does not allow
properties and methods to be created on class instances at runtime.
That means there are three basic solutions:
-
Create a dynamic LocalConnection subclass, and use instances of
that for all receiving local connections.
-
Create a LocalConnection subclass that defines the
methods you intend to call from the sending .swf.
-
Redirect requests to a client object.
We'll next look at each of these solutions.
To allow runtime modification of a class to then
attach functions to an instance, the class has to be declared
dynamic. The easiest
way to do this in ActionScript 3.0 is to extend the
LocalConnection class with a dynamic class, and use
the newly created class as the receiver to attach methods to. That
class would look like this:
package {
import flash.net.LocalConnection;
// Create a dynamic Location Connection class that we can
// attach functions to.
dynamic public class DynamicLocalConnection extends LocalConnection {
// Empty all we need is the dynamic keyword
}
}
Now use the DynamicLocalConnection in
place of the regular LocalConnection class and create a
receiving function as in previous versions of ActionScript:
// Create the local connection object in the receiving movie.
var receiver:DynamicLocalConnection = new DynamicLocalConnection( );
// Instruct the local connection instance to listen for messages
// sent over the "_exampleChannel" channel.
receiver.connect( "_exampleChannel" );
// Because the DynamicLocalConnection class is dynamic, we can
// create a new function on the instance to respond to local
// conection messages.
receiver.example = function( ):void {
trace( "communication received" );
};
This first solution has the advantage of being
very flexible. You can use the DynamicLocalConnection class
for all receiving local connections in all projects. The problem is
that it is so flexible that it doesn't lend itself to well-defined
interfaces, which is something you typically strive for in
object-oriented design.
The second solution requires you use a
well-defined API. You can create a LocalConnection subclass
that defines the specific method or methods you want to handle. For
example, the following class defines an example( ) method.
package {
import flash.net.LocalConnection;
public class ExampleLocalConnection extends LocalConnection {
public function ExampleLocalConnection( ) {}
public function example( ):void {
trace("communication received");
}
}
}
The next solution uses a LocalConnection
property called client to redirect requests to a different object
other than the receiving local connection instance. The client
object must define the requested methods as public methods. The
following example illustrates this:
package {
import flash.net.LocalConnection;
public class Example {
private var _localConnection:LocalConnection;
public function Example( ) {
_localConnection = new LocalConnection( );
_localConnection.connect( "_exampleChannel" );
_localConnection.client = this;
}
public function example( ):void {
trace("communication received");
}
}
}
If you want to define the requested methods as
private, then you have the option if you use a generic object as a
proxy, as shown in the following example:
package {
import flash.net.LocalConnection;
public class Example {
private var _localConnection:LocalConnection;
public function Example( ) {
_localConnection = new LocalConnection( );
_localConnection.connect( "_exampleChannel" );
_localConnection.client = {example: example};
}
private function example( ):void {
trace("communication received");
}
}
}
Now that we've configured the receiving
.swf, we next need to build the sending .swf. The
sending .swf uses the LocalConnection.send( ) method to
send a communication. The first parameter of the send( )
method is a string that specifies the name of a connection over
which to send the communication, enabling you to create multiple
discrete connections. The second parameter of the send( )
method is a string specifying the name of the method to call in the
receiving movie. When a movie receives a message, it invokes the
method of the same name on the receiving local connection
object.
The following example invokes a remote method
named example:
// Send a communication across the "_exampleChannel" channel that
// invokes a method named example( ) in the receiving movie.
var sender:LocalConnection = new LocalConnection( );
sender.send( "_exampleChannel", "example" );
When using the LocalConnection class,
communication is many-to-one. That is, there can be multiple
senders for a specific channel but only a single receiver. If a
receiver tries to connect to a channel that another receiver has
already opened, the connect( ) method throws an error and
won't allow the connection to be made. You can use a
try...catch block to test for a receiver being able to
successfully create a listening connection on a channel, like
this:
var receiver:LocalConnection = new LocalConnection( );
try {
receiver.connect( "_exampleChannel" );
} catch( e:Error ) {
// Error could not listen on _exampleChannel because another
// receiver has already claimed it.
}
For LocalConnection to work properly,
note that both the sending and receiving movies have to be playing
on the same computer at the same time. To communicate between
movies that play on the same computer at different times, use an
LSO. See Recipe
17.1 and Recipe
17.7 for information on using LSOs.
See Also
Recipes 17.1,
17.7,
and 18.2
|