Deep Linking / SEO with Flex

I’ve made an update to this blog post with a new manager to help simplify the Deep Linking process – Revisiting Deep Linking. This should make it infinitely easier to deal with deep linking in a Flex application.

Many web programmers these days are using Flex not just for applications but for some truly innovative and engaging websites – we at UnitedMindset are inundated with these requests. However, many people quickly find themselves annoyed with the fact that you can’t easily do helpful deep linking in Flex, the back button causes a handful of problems, and on top of that search engines still aren’t playing friendly with the Flash Player.

So one day I sat down and created a trick to getting it to work just the way I wanted. You can see it in action at D-Flex.org, and also see pages from D-Flex found by Google and these links will take you right to the correct application state.

For this trick we are going to pull together a few different systems. I want to make sure you know that this trick does take some setup and works much better when your content is all run via a database (such as from a CMS) and can be fully customized for full control over the URL. In this example we will hardcode the values into the application, though your would never do that in your actual application.

One more note, there are currently no standards to deep linking in Flex. Users are still unsure what will happen when they hit the back button from a Flex application, but if you do this right many users will not notice they are interacting with a Flex based site at all.

The technologies pulled together for this trick are: SWFObject, your server side technology of choice, Google Sitemaps, and Flex.

HA! I’m sure you thought this was going to be difficult… nope. This should take you about 30 minutes to an hour to set up.

So, now onto what you scrolled down to see, the code.

First, lets look at the Flex Application that we have put together. Notice that I turned historyManagementEnabled to false to make sure that Flex doesn’t do any automatic historyManagement.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" historyManagementEnabled="false">
    <mx:Accordion width="100%" height="100%" id="accordion">
        <mx:VBox label="Header 1" width="100%" height="100%">
            <mx:Text width="100%" height="100%" text="Lorem ipsum dolor sit amet, damnum premo abdo velit, commodo mauris, qui natu eros genitus ille volutpat hendrerit. Nulla validus, minim tincidunt ea antehabeo gemino, feugait pneum nulla, melior erat neque. Vel suscipere tincidunt consectetuer os consequat dignissim consectetuer opto indoles turpis. Vicis, vereor feugait lobortis jugis saepius, capto dolore. Consequat, tation bis sit nonummy voco exputo delenit eros elit ymo quae in esse. Ne wisi consequat in cogo consequat esse amet. Eligo, loquor enim, duis praemitto quadrum patria haero aptent neo utinam."/>
        </mx:VBox>
        <mx:VBox label="Header 2" width="100%" height="100%">
            <mx:Text width="100%" height="100%" text="Feugait reprobo tamen vicis vulpes, huic consectetuer zelus esse abbas imputo. Neque aliquip at, sit exerci usitas duis jus valde premo vereor refero. Illum foras feugiat gravis nostrud iustum nostrud saluto eum, premo, nibh luptatum exerci eros. Duis jumentum exputo abico scisco turpis augue nutus refoveo mauris. At vel validus ingenium importunus jugis neque metuo nostrud ut eum facilisis imputo te sudo. "/>
        </mx:VBox>
        <mx:VBox label="Header 3" width="100%" height="100%">
            <mx:Text width="100%" height="100%" text="Comis acsi, consequat feugiat ullamcorper caecus velit veniam paratus dolor vel hos. Modo volutpat vel natu, distineo interdico, nibh. Vel et, opto nulla nimis esse velit regula roto, nonummy tation ingenium inhibeo populus illum. Iusto facilisi ea probo valde tristique sino. Caecus opto nisl accumsan appellatio, vel. Esca aliquip validus luptatum in iaceo metuo aliquip sed quae. "/>
        </mx:VBox>
    </mx:Accordion>
</mx:Application>

This produces:
picture-2
A very simple 3 view Flex application using an Accordion to show content.

Next the ViewManager.as, this is what will manage your Flex Views, including the browser manager. This singleton object will manage our application’s view, along with setting and parsing the applications URL. We will need to tie this back into the application so that when the application starts up the url is parsed and the initial state of the application is set.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package com.unitedmindset.managers
{
    import flash.events.Event;
   
    import mx.containers.Accordion;
    import mx.core.Application;
    import mx.events.BrowserChangeEvent;
    import mx.events.IndexChangedEvent;
    import mx.managers.BrowserManager;
    import mx.managers.IBrowserManager;
    import mx.utils.URLUtil;
   
    /**
     * This class is a singleton object, check out my explaination of singleton objects if you need more information on this.
     * @author jonbcampos
     *
     */

    public class ViewManager
    {
        /**
         * Instance Object
         */
   
        private static var _instance:ViewManager;
       
        /**
         * Constructor
         * <p>Can only be referenced through the getInstance Method,
         * sets the browser manager event listener</p>
         */
   
        public function ViewManager(enforcer:SingletonEnforcer)
        {
            // retrieves reference to the BrowserManager Singleton Object
            var bm:IBrowserManager = BrowserManager.getInstance();
            // adds event listener to browser url changes
            bm.addEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE,parseURL);
            // sets the initial application title, it is important to include this init() function
            bm.init(null,"Deep Linking / SEO with Flex");
        }
       
        /**
         * Creates or Returns an Instance of the ViewManager singleton object
         * @return
         *
         */
   
        public static function getInstance():ViewManager
        {
            if(ViewManager._instance==null)
                ViewManager._instance = new ViewManager(new SingletonEnforcer());
            return ViewManager._instance;
        }
       
        // held reference to accodion display object
        private var _accordion:Accordion;
        /**
         * A reference to the managers view component - in this case the accordian, this adds the event listeners
         * @param value
         *
         */

        public function set accordion(value:Accordion):void
        {
            // sets the accordion
            this._accordion = value;
            // updates the url if the selected index changes
            this._accordion.addEventListener(IndexChangedEvent.CHANGE,updateURL);
            // updates the url when the accordion is set
            this.updateURL();
        }
        public function get accordion():Accordion
        {
            //if there is no accordion references, return a new accordion so that the function doesn't fail
            if(!this._accordion)
                return new Accordion();
            // returns the saved accordion
            return this._accordion;
        }
       
        // reference to the accordion object
        // good to hold queued index if the object
        // hasn't been created yet
        private var _queuedAccordionIndex:int = 0;
        /**
         * Accodion Index
         * @param value
         *
         */
   
        public function set accordionIndex(value:int):void
        {
            //if there is an accordion return, set the selected value
            if(this.accordion)
                this.accordion.selectedIndex = value;
            // also set the queued index value
            this._queuedAccordionIndex = value;
        }
       
        /**
         * The initial parameters set in the FlashVars are used to set the initial view
         * @param o
         *
         */
   
        public function set initialURL(o:Object):void
        {
            // set parsing true so no other parsing requests come in, stops recursive changes
            this.parsing = true;
            // the title we will set
            var title:String = new String();
            // sets the view for a view, in this case, the accordion
            if(o.view==0)
            {
                this.accordion.selectedIndex = 0;
                title = "Header 1";
            } else if(o.view==1)
            {
                this.accordion.selectedIndex = 1;
                title = "Header 2";
            } else if(o.view==2)
            {
                this.accordion.selectedIndex = 2;
                title = "Header 3";
            }
            // calls the validate now on accordion
            this.accordion.validateNow();
            // set parsing to false when parsing is done
            this.parsing = false;
        }
       
        /**
         * @private
         * Actually updates the url
         *
         */
   
        private function actuallyUpdateURL():void
        {
            var o:Object = new Object();
            o.view = this.accordion.selectedIndex;
            var s:String = URLUtil.objectToString(o);
            var bm:IBrowserManager = BrowserManager.getInstance();
            bm.setFragment(s);
            var title:String = "Deep Linking / SEO with Flex";
            if(this.accordion.selectedIndex==0)
            {
                title +=" :: Header 1";
            }
            if(this.accordion.selectedIndex==1)
            {
                title +=" :: Header 2";
            }
            if(this.accordion.selectedIndex==2)
            {
                title +=" :: Header 3";
            }
            bm.setTitle(title);
        }
       
        /**
         * Call to update the URL
         * @param event
         *
         */
   
        private function updateURL(event:Event=null):void
        {
            if(!this.parsing)
                Application.application.callLater(actuallyUpdateURL);
        }
       
        /**
         * @private
         * Sets the parsing flag, so that we don't parse multiple times
         */
   
        private var parsing:Boolean = false;
        /**
         * Parse the URL if the URL changes during the application
         * @param event
         *
         */
   
        public function parseURL(event:Event=null):void
        {
            // set parsing true so no other parsing requests come in, stops recursive changes
            this.parsing = true;
            // retrieves reference to the BrowserManager Singleton Object
            var bm:IBrowserManager = BrowserManager.getInstance();
            // turns the fragment to an object
            var o:Object = URLUtil.stringToObject(bm.fragment);
            // title of the application page
            var title:String = "Deep Linking / SEO with Flex";
            // sets the view for a view, in this case, the accordion
            if(o.view==0) {
                this.accordionIndex = 0;
                title +=" :: Header 1";
            } else if(o.view==1) {
                this.accordionIndex = 1;
                title +=" :: Header 2";
            } else if(o.view==2) {
                this.accordionIndex = 2;
                title +=" :: Header 3";
            }
            //set the browser manager title
            bm.setTitle(title);
            // calls the validate now on accordion
            this.accordion.validateNow();
            // set parsing to false when parsing is done
            this.parsing = false;
        }

    }
}
class SingletonEnforcer{}

And now we make a change in our main Application to include the ViewManager Singleton Class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
    historyManagementEnabled="false"
    initialize="this.onInitialize(event)"
    creationComplete="this.onCreationComplete(event)">
    <mx:Script>
        <![CDATA[
            import com.unitedmindset.managers.ViewManager;
            import mx.events.FlexEvent;
           
            private function onInitialize(event:FlexEvent):void
            {
                ViewManager.getInstance().accordion = this.accordion;
            }
           
            private function onCreationComplete(event:FlexEvent):void
            {
                var o:Object = new Object();
                o.view = Application.application.parameters.view;
                ViewManager.getInstance().initialURL = o;
            }
        ]]>
    </mx:Script>
    <mx:Accordion width="100%" height="100%" id="accordion">
        <mx:VBox label="Header 1" width="100%" height="100%">
            <mx:Text width="100%" height="100%" text="Lorem ipsum dolor sit amet, damnum premo abdo velit, commodo mauris, qui natu eros genitus ille volutpat hendrerit. Nulla validus, minim tincidunt ea antehabeo gemino, feugait pneum nulla, melior erat neque. Vel suscipere tincidunt consectetuer os consequat dignissim consectetuer opto indoles turpis. Vicis, vereor feugait lobortis jugis saepius, capto dolore. Consequat, tation bis sit nonummy voco exputo delenit eros elit ymo quae in esse. Ne wisi consequat in cogo consequat esse amet. Eligo, loquor enim, duis praemitto quadrum patria haero aptent neo utinam."/>
        </mx:VBox>
        <mx:VBox label="Header 2" width="100%" height="100%">
            <mx:Text width="100%" height="100%" text="Feugait reprobo tamen vicis vulpes, huic consectetuer zelus esse abbas imputo. Neque aliquip at, sit exerci usitas duis jus valde premo vereor refero. Illum foras feugiat gravis nostrud iustum nostrud saluto eum, premo, nibh luptatum exerci eros. Duis jumentum exputo abico scisco turpis augue nutus refoveo mauris. At vel validus ingenium importunus jugis neque metuo nostrud ut eum facilisis imputo te sudo. "/>
        </mx:VBox>
        <mx:VBox label="Header 3" width="100%" height="100%">
            <mx:Text width="100%" height="100%" text="Comis acsi, consequat feugiat ullamcorper caecus velit veniam paratus dolor vel hos. Modo volutpat vel natu, distineo interdico, nibh. Vel et, opto nulla nimis esse velit regula roto, nonummy tation ingenium inhibeo populus illum. Iusto facilisi ea probo valde tristique sino. Caecus opto nisl accumsan appellatio, vel. Esca aliquip validus luptatum in iaceo metuo aliquip sed quae. "/>
        </mx:VBox>
    </mx:Accordion>
   
</mx:Application>

Before showing the server side code we need to discuss some specifics about the browser.

There are three parts of the url that we need to be very aware of. The first, is the path itself. In the case of this page it is:

http://www.unitedmindset.com/jonbcampos/2009/01/27/deep-linking-seo-with-flex/..

The second part is the query string, the string that follows the ‘?’ in a URL:

…with-flex/?action=edit&id=123123413..

And the third part is the fragment, everything beyond the ‘#’:

…id=123123413#table=top,openWindow=meeting…

Here is the issue. Flex can only update the fragment of the url, because anything before the fragment will cause a page refresh and reset our application, not cool. The other problem is that google and search engines only index pages up to the fragment – the path and the query string. So how do we get the fragment information into the Flex application? Not surprising at all, using the path and fragment.

Using this knowledge we will use the path and the query string to feed parameters to our Flex app via the flashVars. Now you can use your favorite server side language to generate the flashVars that set the initial state of the application using the url that a user or a link from google provided. At this point you can use any form of url variables that you want, and using your server side code you can parse the path and/or query string and use the parsed variables for the flashVars. Such as:

http://www.unitedmindset.com/window/information/1 or http://www.unitedmindset.com/?window=information&id=1

This url could be used to open an information window with information at id = 1 from a database table. This is just one quick example, but I just want to make sure that you get the idea that anything is possible.

Now we will modify the html wrapper to create the flashVars and enter them into the wrapper. In this case I will use PHP with the Flex HTML Wrapper.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?php

$query_string = $_SERVER['QUERY_STRING'];
$flash_vars = str_replace("&", ",", $query_string);

?>
<!-- saved from url=(0014)about:internet -->
<html lang="en">

<!--
Smart developers always View Source.

This application was built using Adobe Flex, an open source framework
for building rich Internet applications that get delivered via the
Flash Player or to desktops via Adobe AIR.

Learn more about Flex at http://flex.org
// -->

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<!--  BEGIN Browser History required section -->
<link rel="stylesheet" type="text/css" href="history/history.css" />
<!--  END Browser History required section -->

<title>${title}</title>
<script src="AC_OETags.js" language="javascript"></script>

<!--  BEGIN Browser History required section -->
<script src="history/history.js" language="javascript"></script>
<!--  END Browser History required section -->

<style>
body { margin: 0px; overflow:hidden }
</style>
<script language="JavaScript" type="text/javascript">
<!--
// -----------------------------------------------------------------------------
// Globals
// Major version of Flash required
var requiredMajorVersion = ${version_major};
// Minor version of Flash required
var requiredMinorVersion = ${version_minor};
// Minor version of Flash required
var requiredRevision = ${version_revision};
// -----------------------------------------------------------------------------
// -->
</script>
</head>

<body scroll="no">
<script language="JavaScript" type="text/javascript">
<!--
// Version check for the Flash Player that has the ability to start Player Product Install (6.0r65)
var hasProductInstall = DetectFlashVer(6, 0, 65);

// Version check based upon the values defined in globals
var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision);

if ( hasProductInstall && !hasRequestedVersion ) {
    // DO NOT MODIFY THE FOLLOWING FOUR LINES
    // Location visited after installation is complete if installation is required
    var MMPlayerType = (isIE == true) ? "ActiveX" : "PlugIn";
    var MMredirectURL = window.location;
    document.title = document.title.slice(0, 47) + " - Flash Player Installation";
    var MMdoctitle = document.title;

    AC_FL_RunContent(
        "src", "playerProductInstall",
        "FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle='+MMdoctitle+'&flashVars=<?php echo $flash_vars; ?>'+"",
        "width", "${width}",
        "height", "${height}",
        "align", "middle",
        "id", "${application}",
        "quality", "high",
        "bgcolor", "${bgcolor}",
        "name", "${application}",
        "allowScriptAccess","sameDomain",
        "type", "application/x-shockwave-flash",
        "pluginspage", "http://www.adobe.com/go/getflashplayer"
    );
} else if (hasRequestedVersion) {
    // if we've detected an acceptable version
    // embed the Flash Content SWF when all tests are passed
    AC_FL_RunContent(
            "src", "${swf}",
            "width", "${width}",
            "height", "${height}",
            "align", "middle",
            "id", "${application}",
            "quality", "high",
            "bgcolor", "${bgcolor}",
            "name", "${application}",
            "allowScriptAccess","sameDomain",
            "type", "application/x-shockwave-flash",
            "pluginspage", "http://www.adobe.com/go/getflashplayer"
           "flashVars", "<?php echo $flash_vars; ?>"
    );
  } else {  // flash is too old or we can't detect the plugin
    var alternateContent = 'Alternate HTML content should be placed here. '
    + 'This content requires the Adobe Flash Player. '
    + '<a href=http://www.adobe.com/go/getflash/>Get Flash</a>';
    document.write(alternateContent);  // insert non-flash content
  }
// -->
</script>
<noscript>
    <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
            id="${application}" width="${width}" height="${height}"
            codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
            <param name="movie" value="${swf}.swf" />
            <param name="quality" value="high" />
            <param name="bgcolor" value="${bgcolor}" />
            <param name="allowScriptAccess" value="sameDomain" />
            <param name="flashVars" value="<?php echo $flash_vars; ?>" />
            <embed src="${swf}.swf" quality="high" bgcolor="${bgcolor}"
                width="${width}" height="${height}" name="${application}" align="middle"
                play="true"
                loop="false"
                quality="high"
                allowScriptAccess="sameDomain"
                type="application/x-shockwave-flash"
                pluginspage="http://www.adobe.com/go/getflashplayer">
            </embed>
    </object>
</noscript>
</body>
</html>

Wow, we have gone so far, yet we still have that two last things to do to make this worth while. Right now we have a working application that runs using the browser manager and accepts flashVars to set the initial state, and the server side code to create the flashVars. Now we need to create the content that is viewable to the search engine using the SWFObject and finally submitting your links to google to improve your standings. I am not going into how to submit your links to google because you can easily find information about creating sitemaps and other specific SEO fundamentals, but we will look at how to change the html template to produce the search engine readable content. One thing that is nice about this trick is that it will produce a working “mobile device safe” site (for people running on a browser that doesn’t support Flash Player), the final look of the html is up to you. If a user doesn’t have the Flash Player installed, they will see this alternative content. Here is the final html template with this alternative content.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?php

$i = "-1";
if (isset($_GET['view'])) {
  $i = (get_magic_quotes_gpc()) ? $_GET['view'] : addslashes($_GET['view']);
}

$html_content = '';

switch ($i) {
    case 0:
        $html_content = '<h1>Header 1</h1><p>Lorem ipsum dolor sit amet, damnum premo abdo velit, commodo mauris, qui natu eros genitus ille volutpat hendrerit. Nulla validus, minim tincidunt ea antehabeo gemino, feugait pneum nulla, melior erat neque. Vel suscipere tincidunt consectetuer os consequat dignissim consectetuer opto indoles turpis. Vicis, vereor feugait lobortis jugis saepius, capto dolore. Consequat, tation bis sit nonummy voco exputo delenit eros elit ymo quae in esse. Ne wisi consequat in cogo consequat esse amet. Eligo, loquor enim, duis praemitto quadrum patria haero aptent neo utinam.</p>';
        break;
    case 1:
        $html_content = '<h1>Header 2</h1><p>Feugait reprobo tamen vicis vulpes, huic consectetuer zelus esse abbas imputo. Neque aliquip at, sit exerci usitas duis jus valde premo vereor refero. Illum foras feugiat gravis nostrud iustum nostrud saluto eum, premo, nibh luptatum exerci eros. Duis jumentum exputo abico scisco turpis augue nutus refoveo mauris. At vel validus ingenium importunus jugis neque metuo nostrud ut eum facilisis imputo te sudo.</p>';
        break;
    case 2:
        $html_content = '<h1>Header 3</h1><p>Comis acsi, consequat feugiat ullamcorper caecus velit veniam paratus dolor vel hos. Modo volutpat vel natu, distineo interdico, nibh. Vel et, opto nulla nimis esse velit regula roto, nonummy tation ingenium inhibeo populus illum. Iusto facilisi ea probo valde tristique sino. Caecus opto nisl accumsan appellatio, vel. Esca aliquip validus luptatum in iaceo metuo aliquip sed quae.</p>';
        break;
    default:
        $html_content = '<h1>Main Page</h1><p>Main Page Content</p>';
    break;
}

$html_content .= '<p>Links: <a href="?view=0">Header 1</a> | <a href="?view=1">Header 2</a> | <a href="?view=2">Header 3</a></p>';

?>
<!-- saved from url=(0014)about:internet -->
<html lang="en">

<!--
Smart developers always View Source.

This application was built using Adobe Flex, an open source framework
for building rich Internet applications that get delivered via the
Flash Player or to desktops via Adobe AIR.

Learn more about Flex at http://flex.org
// -->

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<!--  BEGIN Browser History required section -->
<link rel="stylesheet" type="text/css" href="history/history.css" />
<!--  END Browser History required section -->

<title></title>
<script src="AC_OETags.js" language="javascript"></script>

<!--  BEGIN Browser History required section -->
<script src="history/history.js" language="javascript"></script>
<!--  END Browser History required section -->

<style>
body { margin: 0px; overflow:hidden }
</style>

<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
    var flashvars = {
        <?php if($i>-1){ echo 'view: "'.$i.'"'; } ?>
        };
    var params = {};
    var attributes = {
        id: "DeepLinking",
        name: "DeepLinking",
        bgcolor: "#869ca7",
        allowscriptaccess: "sameDomain",
        align: "middle",
        quality: "high"
        };
    swfobject.embedSWF("DeepLinking.swf", "myAlternateContent", "100%", "100%", "9.0.124", "expressInstall.swf", flashvars, params, attributes);
</script>
</head>

<body scroll="no">

<div id="myAlternateContent">
    <?php echo $html_content; ?>
    <a href="http://www.adobe.com/go/getflashplayer">
        <img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
    </a>
</div>

</body>
</html>

You will notice that I include a Link bar with the links to the other views, this is obviously for search engines and mobile users to find your other views/pages, and fits right into our application structure.

And… there you go. You now have an application that is able to show off it’s content to search engines and start on the correct state. Obviously there is much more possible including dynamically retrieving your content from a database, styling your html, and adding more views to the Flex.

Source Files: (requires you to have Flex 3 and PHP to run properly)
DeepLinking Zip

I’ve made an update to this blog post with a new manager to help simplify the Deep Linking process – Revisiting Deep Linking. This should make it infinitely easier to deal with deep linking in a Flex application.

  • Share/Bookmark

Comments (12)

AntonAugust 17th, 2009 at 1:29 pm

Thanks for this, very useful.
I have one problem when I am using the BrowserManager.
When I change the URL parameters while running the Flex application, it seems to hang the browser and somehow keeps refreshing the page.
Is this a known issue and do other people see this as well?
Is there a workaround to avoid this?

Thanks

Jonathan CamposAugust 17th, 2009 at 1:33 pm

I have definitely seen this problem before. Did you make sure to add a boolean flag to say that the url was being updated? The reason I ask is many people forget to limit the updating listener and so when you make a change you end up in an infinite loop because you keep trying to parse and update, parse and update, etc etc.

With this flag you limit the setting/parsing/updating to one cycle at a time. Let me know what you are finding.

AntonAugust 18th, 2009 at 2:27 am

Hi,

Thanks for your quick response.
I have tried this, but no luck.
In fact, when I remove the call to the BrowserManager.init() function the problem disappears. This is not a solution, because when I do that the BrowserManager doesn’t listen to the browserURLChange event.

The BrowserManager does listen to applicationURLChange events, so I think I can work around it using this event and Javascript. I will let you know how that goes.

Jonathan CamposAugust 18th, 2009 at 8:27 am

Definitely you need to keep the init() function. That is very important. What I was referring to was the “parsing” boolean flag from my example to protect yourself against infinite loops. If you keep having problems let me know and feel free to show whatever code you want (preferably just the pertinent parts).

AntonAugust 25th, 2009 at 10:33 am

A Great Help, but it does not work with Safari 4.0.2.
Do you have any hotfix?
Thank You!
Anton

Jonathan CamposAugust 25th, 2009 at 10:37 am

I’ll check it out tonight and make an update. When I made it though I know it worked in Safari (my browser of choice). Sorry for that.

Jonathan CamposAugust 29th, 2009 at 10:21 am

Are you sure that you have your php instance running? Mine works, current safari version 4.0.3.

Make sure that you are setting the ?view=1, not #view=1

ktutnikJanuary 12th, 2010 at 7:23 pm

wow..
nice post !! impress with the clean way of using alternate content.

but on my opinion either than passing flash vars i though that would be easier to parse the url form flex it self, by using IBrowserManager.url you will get the full url requested. so need a small modification on the html script and swf application has less dependencies with the html.
i don’t know maybe you have other purposes to do that.

anyway, i made a library for easier managing page navigation in flex. support deep linking and user authorization.
please check it out @ http://code.google.com/p/ticlib/

Best Regards
ktutnik

Jonathan CamposJanuary 12th, 2010 at 9:23 pm

That is a great idea and at the time, something I didn’t think of. I need to post my newer technique but I completely agree with you. I’ll check out your code though, I’m always looking for easier techniques.

d-hegJanuary 15th, 2010 at 1:59 am

D-Flex.org is no longer a Flex Page ?

[...] few months *cough *cough over a year ago I posted some thoughts on Deep Linking within a Flex Application. Since making this post I have worked on a variety of different applications using AIR, Flex, and [...]

Custom Software Development CompanyJune 18th, 2010 at 4:11 am

nice and informative.

Leave a comment

Your comment