Understanding the BrowserManager Class and Deep Linking - Search Engine Optimization for Flash
by Todd PerkinsOne way you can
enable two-way communication between the browser and your Flex
applications is when you use the BrowserManager class. The BrowserManager class lets you capture and use
URL fragments—name
value pairs used as named anchors. This ability lets you update a
Flex application based on its URL. It also lets you update URLs
based on Flex input, so just like using SWFAddress in Flash, you
can create two-way communication between your Flex application and
the web browser.
This excerpt is from Search Engine Optimization for Flash. Search Engine Optimization for Flash dispels the myth that Flash-based websites won't show up in a web search by demonstrating exactly what you can do to make your site fully searchable -- no matter how much Flash it contains. You'll learn best practices for using HTML, CSS and JavaScript, as well as SWFObject, for building sites with Flash that will stand tall in search rankings.
Before you begin using the BrowserManager class to control two-way
communication between the browser and your Flex application,
it’s important to understand how the BrowserManager class works. This section explains
the important parts of working with the BrowserManager class that you should be familiar
with before implementing it in your applications.
Look at the BrowserManager properties,
methods, and events you’ll be working with for the
BrowserManager example.
Table 6.1, “BrowserManager properties, methods, and
events” is a brief list of the BrowserManager class’s features. For more
features, see Flex Help.
Table 6.1. BrowserManager properties, methods, and events
Since the
BrowserManager uses strings only as a data type for getting and
setting URL fragments, in order to access the fragment values of
the string, you need to do some processing. For example, a fragment
string may be view=1, and in order to
use the data you have to separate the property (view) from the
value (1).
That’s where the URLUtil class comes in. Using the URLUtil
class helps you skip the step of processing strings, and gives you
easy object access to fragment properties and values. It converts
strings to objects for processing fragments using its stringToObject() method, and converts objects to
strings for sending fragments using its objectToString() method. That way, you can use an
object to represent the fragment and access its property names and
values using object notation. For example, you can get the value of
the view fragment through your fragment’s view property, so the code would be fragment.view.
Now you’ll look at using the BrowserManager class to build an application that uses two-way deep linking. Here’s a complete application that uses this technique:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.managers.IBrowserManager;
import mx.managers.BrowserManager;
import mx.events.BrowserChangeEvent;
import mx.utils.URLUtil;
import mx.controls.Text;
import mx.containers.VBox;
private var req:URLRequest = new URLRequest("data.xml");
private var loader:URLLoader = new URLLoader();
private var xmlData:XML;
private var manager:IBrowserManager;
private function initApp():void
{
manager = BrowserManager.getInstance();
manager.addEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE,
parseURL);
manager.init("","Wedgekase Wii Games");
loader.addEventListener(Event.COMPLETE,loadComplete);
loader.load(req);
}
private function loadComplete(event:Event):void
{
xmlData = new XML(loader.data);
for each(var game:XML in xmlData.game)
{
var vbox:VBox = new VBox();
var field:Text = new Text();
field.text = game.description;
vbox.label = game.title;
navigator.addChild(vbox);
vbox.addChild(field);
field.width = 375;
field.height = 100;
}
}
private function parseURL(event:BrowserChangeEvent):void
{
var fragment:Object = URLUtil.stringToObject(manager.fragment);
if(fragment.view == undefined)
{
fragment.view = 0;
}
navigator.selectedIndex = fragment.view;
manager.setTitle(xmlData.game[navigator.selectedIndex].title);
}
private function updateURL():void
{
var newFragment:Object = {};
var fragmentStr:String = "";
newFragment.view = navigator.selectedIndex;
fragmentStr = URLUtil.objectToString(newFragment);
manager.setFragment(fragmentStr);
manager.setTitle(xmlData.game[navigator.selectedIndex].title);
}
]]>
</mx:Script>
<mx:TabNavigator id="navigator" width="400" height="150" change=
"updateURL()">
</mx:TabNavigator>
</mx:Application>
Take a look at how this application uses the BrowserManager class. First, note that it’s the same application you used in the last section, with a few updates. The first update is the extra import statements:
import mx.managers.IBrowserManager; import mx.managers.BrowserManager; import mx.events.BrowserChangeEvent; import mx.utils.URLUtil;
These statements import the necessary classes for working with the BrowserManager class. Note the IBrowserManager class is imported, because an instance of IBrowserManager will be used to work with the BrowserManager because the BrowserManager class is a type of class that never gets instantiated.
The only new variable is manager, which is data typed to be an instance of any class that implements the IBrowserManager interface:
private var manager:IBrowserManager;
Note
An interface is a list of methods. Any class that implements an interface must contain all the methods in that interface. See Essential ActionScript 3.0 by Colin Moock for more details.
Next, look at the initApp()
function:
private function initApp():void
{
manager = BrowserManager.getInstance();
manager.addEventListener
(BrowserChangeEvent.BROWSER_URL_CHANGE, parseURL);
manager.init("","Wedgekase Wii Games");
loader.addEventListener(Event.COMPLETE,loadComplete);
loader.load(req);
}
The initApp() function has three
new lines of code. First, the manager variable is set to
BrowserManager.getInstance(), which
returns an instance that implements IBrowserManager. Next, an event
listener is added to the manager instance, listening for the
browser’s URL to change. Upon changing, the parseURL() function runs. Finally, the
BrowserManager is initialized using its init() method. The first parameter represents the
initial URL fragment, which is left blank here. The second
represents the initial browser title.
Now you’ll discuss the parseURL() function:
private function parseURL(event:BrowserChangeEvent):void
{
var fragment:Object = URLUtil.stringToObject(manager.fragment);
if(fragment.view == undefined)
{
fragment.view = 0;
}
navigator.selectedIndex = fragment.view;
manager.setTitle(xmlData.game[navigator.selectedIndex].title);
}
This function gets triggered when the browser’s URL
changes. First, the fragment object
uses the URLUtil to convert the manager’s fragment from a string to an object. Then, if the
view property of the fragment is undefined, it is set to 0. Then, the navigator’s selected index is set to
whatever value is in the fragment’s view
property, which updates the TabNavigator according to the current
URL fragment. Finally, the page’s title is updated using the
manager’s setTitle() method. The title is set to the value
of the game title that corresponds to the current selected index of
the TabNavigator component (which was
previously received from the URL fragment).
So far you’ve looked at what happens when the URL is
updated, but not at what makes a change in the URL. The first thing
that initiates the change is the change event of the TabNavigator,
which is set to run the updateURL()
function:
<mx:TabNavigator id="navigator" width="400" height="150" change="updateURL()"> </mx:TabNavigator>
The updateURL() function looks like
this:
private function updateURL():void
{
var newFragment:Object = {};
var fragmentStr:String
newFragment.view = navigator.selectedIndex;
fragmentStr = URLUtil.objectToString(newFragment);
manager.setFragment(fragmentStr);
manager.setTitle(xmlData.game[navigator.selectedIndex].title);
}
First, this function creates a new empty object to represent the
new fragment that will appear in the URL (newFragment) and a new empty string that will
represent the string version of newFragment (fragmentStr). Next, the newFragment object’s view property is set to the selected index of the
TabNavigator (i.e. the index
number of whatever tab was clicked to initiate the change event).
Then, a string version of the newFragment object is held in fragmentStr, and set as the current fragment using
the BrowserManager’s setFragment() method. Finally, the page’s
title is set to the current game’s title from the XML
file.
You need a server to test this application’s two-way communication. The files in the history folder created by Flex Builder should also be copied to your server, since they’re the supporting files that control communication between the browser and the Flex application. When testing this file on your server, click through the tabs to watch the URLs update (Figure 6.13, “Viewing the BrowserManager class in two-way communication action.”), and change the view number in the URL to watch the application update.
Though the BrowserManager class is a powerful tool for two-way communication between the browser and the application, it’s lacking an important SEO feature. The problem with the BrowserManager class as you’ve used it here is that in order to navigate to an application state, the application must first be initialized. That means, if you pass in a fragmented URL to your application, desiring to start on view 2, the application would start at view 0. Once at view 0, the application can then be moved to view 2 via a URL change. Even though this feature allows two-way communication, and with an extra step allows for saving URLs, you’re still better off going with a system like SWFAddress for deep linking.
Note
Deep linking in Flex is possible without using SWFAddress or any third party code, but it’s more complex than the example shown here. For information about deep linking in Flex that supports fragment URLs when an application is first initialized, in Flex Help, see Deep Linking.
The BrowserManager class doesn’t
work in every web browser. Currently,
the BrowserManager class is not supported by Safari, Chrome, or
Opera. This doesn’t harm how spiders index your site, but it
can decrease traffic on your site for anyone using those browsers,
so it’s best to use SWFAddress or another method that’s
more broadly supported.

