Can AIR Communicate with the Flash Player in the Browser?

This came up on the Flex Coders list recently, and my first response was..

"There is no way that AIR and the browser can communicate. It would violate the security sandbox of the browser."

Someone mentioned that AIR can do this now. They were right. Here is how to do it

The answer is with the local connection class. LocalConnection is used to allow two swfs to communicate with each other. Tradiitonally you'd use this for two swfs in a single HTML page, or when one swf is loaded by another. I'm not sure of the use case for having AIR all a browser swf (or vice versa), but you can get it to work.

First import the LocalConnection class and create a few variables, one for the outgoing connection and one for the incoming connection:

import flash.net.LocalConnection;

private var incomingConn:LocalConnection;
private var outGoingConn:LocalConnection;

I initialized each connection in an CreationComplete event. First initialize the outgoing connection:

outGoingConn = new LocalConnection();
outGoingConn.addEventListener(StatusEvent.STATUS, onStatus);

This is really easy, just two lines. It creates the new outgoing connection, and calls the method onStatus whenever a call is made to that connection. Here is the onStatus function:

private function onStatus(event:StatusEvent):void {
Alert.show(event.toString());
switch (event.level) {
case "status":
Alert.show("LocalConnection.send() succeeded");
break;
case "error":
Alert.show("LocalConnection.send() failed");
break;
}
}

For our test purposes, this "dumps" the event, and tells us what actually happened. In a real world application you probably won't want as may status messages.

Back to the CreationComplete method, we need to initialize the swf to accept incoming connections:

incomingConn = new LocalConnection();
incomingConn.allowDomain('*');
incomingConn.client = this;
try {
incomingConn.connect("browserConnection");
}
catch (error:ArgumentError) {
Alert.show("Can't connect...the connection name is already being used by another SWF");
}

We initialize the connection with the new Keyword. Next we need to tell the connection what domains to allow. For the purposes of this sample, I specified the wildcard. You'll probably want to be more specific in a real world app.

The client attribute tells us what object receives the method calls when an outside swf connects to this one. I'm using 'this', but in real world app you'll probably want to encapsulate it a but more.

Next the connect method is called. This method is named a bit odd for the incoming connection. We aren't actually connecting to anything, just preparing to accept connections from allowed sources (as specified in the 'allowDomain' method. I added some error checking around the connect method, which is mainly copy and paste from the documentation. It just makes sure that the connection name is unique. I believe this is unique on a per machine basis. Be sure that your AIR application and browser should have different connection names.

We need two more methods here. The first one is easy. It is the method that needs to be called via the incoming connection:

public function lcHandler(msg:String):void {
Alert.show(msg);
}

I just created something simple that accepts a string and shows an Alert. No reference to the connections is needed for this method.

The second method is a bit more complex. It calls the other swf through the outgoing connection:

private function sendMessage():void { outGoingConn.send("app#AIR.communicateWithBrowserSWF:AIRConnection",
"lcHandler", 'Swf to AIR');
}

It uses the send method, and specifies the URL of the outgoing connection and the name of the connection. Finally it specifies the name of the method to call and the arguments to it. Simple right?

One more thing is needed. A button to trigger the send event:

<mx:Button label="Send Message" click="sendMessage()" />

The code is almost identical in the AIR application vs the browser application. Just the name of the connection is different, and the URL to connect to is different. Notice that the URL for the AIR app is nothing like a web URL. You can get the URL easy, like this:

<mx:Button label="Find Domain" click="{Alert.show(outGoingConn.domain);}" />

Download the code (I included my Flex Builder 3 projects for each portion of the app), compile it, and you'll see these two working. It boggles my mind that this is allowed.

I'm still surprised that this works against my intuition.

Comments
Evan Mullins's Gravatar Hey Jeffry,
Thanks for this post it's helping me out. I'm having troubles making this source function fully.
I've got the connection from AIR to the browser just fine, but the other direction is giving me problems. When I press the button in the browser to "send message" to AIR, I get the error, LocalConnection.send() failed. Any insights?
# Posted By Evan Mullins | 3/5/08 5:23 PM
Evan Mullins's Gravatar Never fails, you post a question and as you send it you get an idea and it works!

The issue was the name of my project had changes and thus "app#AIR.communicateWithBrowserSWF:AIRConnection" didn't work anymore, I had to update it to the current file name: "app#AIRCommunicateWithBrowser:AIRConnection"

Thanks again for the post Jeffry!
# Posted By Evan Mullins | 3/5/08 5:28 PM
Jeffry Houser's Gravatar Evan,

Glad to help. I have not tested this code on the AIR 1 release. Are you working on the production version? It's be good to know that this has not changed.
# Posted By Jeffry Houser | 3/5/08 6:00 PM
Greg North's Gravatar Jeffry,

I'm glad I stumbled onto your post. I've was trying to figure out why my AIR app wasn't receiving the connection. Turns out it was that file name.

FYI. It works with AIR 1.0

THANKS!
# Posted By Greg North | 4/12/08 6:08 PM
All Content Copyright 2005, 2006, 2007 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.8.