Accessibility

Macromedia Flash Article

Server-Side Flash Detection Using BrowserHawk

Aaron Johnson

Aaron Johnson
www.mindseye.com

As of April 2003, there are over 522 million users with Macromedia Flash Player, comprising 98% of all web users. Even so, there are still some users who don't have Macromedia Flash Player installed and others who don't have the latest installation of it. Since its release in April of 1998, BrowserHawk (produced by cyScape) has been the favorite server-side tool used by developers to accurately detect Macromedia Flash. Macromedia Flash Detection Kit is the preferred method for client-side Flash detection. In this article, I'll touch on various methods of performing Flash detection and then take a detailed look at using BrowserHawk to detect Macromedia Flash in ASP, C#, ColdFusion MX, and JSP/Servlet environments.

Code Attachments

download Download the sample code files for this article.

  • ASP Example: bh_asp.asp
  • CFMX Example: bh_cfmx.cfm
  • .NET/C# Example: bh_csharp.aspx
  • JSP Example: bh_jsp.jsp
  • Servlet Example: BrowserHawkServlet.java

Macromedia Flash Detection: Why?

The need for Macromedia Flash detection generally boils down to one or both of the following:

  • The presence of embedded functionality within a Macromedia Flash movie requiring a specific version of Macromedia Flash Player. (I'll call this "version detection.")
  • The need to present alternative content for non-Flash users, which requires a knowledge of whether or not the user has any version of Macromedia Flash Player installed. ("I'll call this "presence detection.")

Macromedia Flash Detection: What?

Macromedia Flash detection comes in a variety of flavors. As mentioned previously, BrowserHawk provides both Macromedia Flash presence and version detection to server-side developers using a multitude of programming languages including ASP/VBScript, ASP.NET, ColdFusion, and Java. Shortly after BrowserHawk was released in April of 1998, Colin Moock released the Moock FPI, which also provides both presence and version detection to client-side developers using JavaScript. Macromedia provides its own software in Macromedia Flash Detection Kit. Although I will not address either the Moock FPI or Macromedia Flash Detection Kit, they are well documented and free, so I encourage you to check them out on your own time.

BrowserHawk Flash Presence and Version Detection

Before getting into the tutorial, let's make sure you're all set up. To follow the examples in this article, you need access to one or more of the following programming languages: ASP/VBScript, ASP.NET, Java, or ColdFusion. You could certainly do this in another language; you only need to choose from the list for this article. Next, download and install an evaluation version of BrowserHawk ActiveX and BrowserHawk4J. Finally, fire up your favorite IDE (Macromedia Dreamweaver, Macromedia Homesite+, BBEdit, Notepad, etc.).

At this point, I should point out that the BrowserHawk object can give you much more information than just Macromedia Flash version and presence. It can report on JavaScript availability, connection speed, whether or not cookies are enabled, platform (Windows, Macintosh, Linux), etc. I recommend that you check out the full list of available properties on the BrowserHawk website.

ColdFusion MX and BrowserHawk

According to the BrowserHawk documentation:

"BrowserHawk ActiveX/COM has the ability to detect disabled cookies and other advanced features, such as whether JavaScript is disabled or not. Although these features are available to ASP developers, they are not directly usable from ColdFusion at this time."

cyScape recommends using an ASP bridge (assuming that the users environment supports ASP) to use the advanced features if you're using ColdFusion 5 or earlier. But because ColdFusion MX is now based on Java technology, you can seamlessly use the BrowserHawk 4J component in ColdFusion MX.

As with any Java technology that you want to use with ColdFusion, you have to configure your ColdFusion server appropriately. First, you'll need to copy the bhawk4j.jar into [cfmx_home]\wwwroot\WEB-INF\lib\ and the bhaw_sp.dat, browserhawk.properties, maindefs.bdd, and eval.lic files to the [cfmx_home]\wwwroot\WEB-INF\classes directory. After placing these files into the appropriate directories, restart the ColdFusion MX service. You're ready to look at code now, so open up your favorite IDE (if you don't already have it open).

First, use the CreateObject() function to get two Java objects:

<cfscript>
 ebi = CreateObject("java", "com.cyscape.browserhawk.ExtendedBrowserInfo");

 options = CreateObject("java", "com.cyscape.browserhawk.ExtendedOptions");
</cfscript>

Then, using the ExtendedOptions object, set the request type to 'options.REQUEST_TYPE_AUTO' (which means that BrowserHawk will use the its default method of detection). Set the TCP/IP ports to check (the port in this case is "8500", which is the default port for the ColdFusion MX embedded web server; in production, you'll most likely be using port 80). Finally, add the two Macromedia Flash properties that you want information about.

<cfscript>
 options.setRequestType(options.REQUEST_TYPE_AUTO);
 options.setPortsToCheck("8500");
 options.addProperty(ebi.PLUGIN_FLASH);
 options.addProperty(ebi.PLUGIN_FLASHVEREX);
</cfscript>

Next, using the getPageContext() method (which is new to ColdFusion MX), get a HttpServletRequest and HttpServletResponse object to pass to the BrowserHawk object. Then, get and initialize a BrowserHawk object and retrieve the Macromedia Flash presence and version information using the getExtendedBrowserInfo() method of the BrowserHawk object.

<cfscript>
 // retrieve an HttpServletRequest and HttpServletResponse
 req = getPageContext().getRequest(); 
 res = getPageContext().getResponse(); 
 
 // get a browserhawk object
 bh = CreateObject("java", "com.cyscape.browserhawk.BrowserHawk");
 bh.init();
 
 // retrieve the Macromedia Flash properties
 ebi = bh.getExtendedBrowserInfo(req, res, options);
</cfscript>

After calling the getExtendedBrowserInfo method, you can write your logic to transfer the user to a different resource or write content directly into the response stream.

Example 1: Transfer the user to a different resource:

<cfif isdefined("url.bhcp")>
 <cfset flashInstalled = ebi.getPluginFlash()>
 <cfset flashVersion = ebi.getPluginFlashVerEx()>

   <!--- METHOD A --->
 <!--- redirect user to a resource --->
 <cfif flashInstalled LT 1>
  <cfscript>
  getPageContext().forward("noflash.html");
  </cfscript>
 <cfelse>
  <cfscript>
 getPageContext().forward("flash.html");
  </cfscript>
 </cfif>

</cfif>

Example 2: Write content directly to the response stream:

<cfif isdefined("url.bhcp")>
 <cfset flashInstalled = ebi.getPluginFlash()>
 <cfset flashVersion = ebi.getPluginFlashVerEx()>
 
 <!--- METHOD B --->
 <!--- show different content based on the version of Macromedia Flash --->
 <cfif Left(flashVersion, 1) >= "6">
  <cfoutput>You have version 6 or higher.</cfoutput>
 <cfelse>
  <cfoutput>You have version 5 or lower.</cfoutput>
 </cfif>
</cfif>

JSP/Servlets and BrowserHawk

If you've been following along through the entire article, you'll notice that you just finished the ColdFusion MX example. The JSP example, which obviously uses Java syntax, is not much different from ColdFusion MX.

Just like the ColdFusion MX version, you need to configure your servlet container (Tomcat, JRUN, WebSphere, etc.) by copying the bhawk4j.jar into [your_app]\WEB-INF\lib\ and the bhaw_sp.dat, browserhawk.properties, maindefs.bdd, and eval.lic files to the [your_app]\WEB-INF\classes directory. After doing so, you'll most likely need to restart the servlet container. Now you're ready to begin coding.

Using your IDE, create a new file and save it as 'browserhawk.jsp' into the [your_app] directory (where [your_app] is the directory you've configured your servlet container to respond to for this example). With browserhawk.jsp open, add this line of code:

<%@ page import = "com.cyscape.browserhawk.*" %>

The above line imports the cyScape BrowserHawk classes into this JSP's namespace so that you can use those classes without typing the full class name. Next, create the ExtendedOptions object, the ExtendedBrowserInfo object, and the BrowserHawk object and then call the getExtendedBrowserInfo() method just like you did in ColdFusion MX.

<%
ExtendedOptions options = new ExtendedOptions();
options.setRequestType(ExtendedOptions.REQUEST_TYPE_AUTO);
options.setPortsToCheck("8080");
options.addProperty(ExtendedBrowserInfo.PLUGIN_FLASH);
options.addProperty(ExtendedBrowserInfo.PLUGIN_FLASHVEREX);


ExtendedBrowserInfo b = null;
b = BrowserHawk.getExtendedBrowserInfo(request, response, options);
// A null return value indicates JavaScript has been sent and 
// we should immediately return
if (b == null) return;
%>

Note that the port you're using has changed from "8500" to "8080". (I'm using Jakarta Tomcat as my servlet container.) During production use, you'll normally use port 80. Unlike ColdFusion MX, you don't have to worry about creating a javax.servlet.HttpServletRequest or javax.servlet.HttpServletResponse object. In a JSP environment, those objects are implicit as "request" and "response."

Finally, you can use the exact same logic you used in the previous example to either forward the user on to a resource or write directly to the response stream:

Example 1: Forward user on to a different resource:

<%
int flashInstalled = b.getPluginFlash();
String flashVersion = b.getPluginFlashVerEx();


if (flashInstalled == 0 || flashInstalled == -1) {
 RequestDispatcher rd = request.getRequestDispatcher("noflash.html");
 rd.forward(request, response); 
} else {
 RequestDispatcher rd = request.getRequestDispatcher("flash.html");
 rd.forward(request, response); 
}
%>

Example 2: Write directly to the response stream:

<%
int flashInstalled = b.getPluginFlash();
String flashVersion = b.getPluginFlashVerEx();

if (flashVersion.startsWith("6")) {
 out.write("You have version 6.");
} else {
 out.write("You have version 5 of lower.");
}

%>

Since JSP best practices dictate that you shouldn't have Java code in your JSP, I will also show an example using a servlet. Writing a servlet requires additional setup in your servlet container but uses almost the exact same syntax as the JSP example above. (I'll leave it up to you to figure out how to add a servlet to your servlet container; consult your servlet container documentation for more information.) Here is the code for a servlet:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

import com.cyscape.browserhawk.*;

public class BrowserHawkServlet extends HttpServlet {

public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doGet(req, res);
}

public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {

    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

   ExtendedOptions options = new ExtendedOptions();
 options.setRequestType(ExtendedOptions.REQUEST_TYPE_AUTO);
 options.setPortsToCheck("8080");
 options.addProperty(ExtendedBrowserInfo.PLUGIN_FLASH);
 options.addProperty(ExtendedBrowserInfo.PLUGIN_FLASHVEREX);


 ExtendedBrowserInfo b = null;
 b = BrowserHawk.getExtendedBrowserInfo(req, res, options);
 // A null return value indicates JavaScript has been sent and 
 // we should immediately return
 if (b == null) return;
 
 int flashInstalled = b.getPluginFlash();
 String flashVersion = b.getPluginFlashVerEx();

Example 2: Write directly to the response stream:

//show different content based on the version of Macromedia Flash
 if (flashVersion.startsWith("6")) {
  out.write("You have version 6 or higher.");
 } else {
  out.write("You have version 5 of lower.");
 }
}
}


ASP and BrowserHawk

In a Windows/IIS environment, you'll be using BrowserHawk as server-side ActiveX component. As with any ActiveX component, you'll first need to create an instance of the ActiveX component in your ASP page:

<% set bh = Server.CreateObject("cyScape.browserObj") %>

The code above uses the ASP Server object and calls the CreateObject method, passing "cyScape.browserObj" as the argument to the method. This will return a BrowserHawk object into the variable 'bh'. Because there are so many properties available to retrieve and because some of the properties require special invocations on the client browser, BrowserHawk lets you specify only the properties you want to retrieve. So in the next line of code, you're going to specify that you want the "plugin_flash" and the "plugin_flashverex" properties to be retrieved.

<% bh.SetExtProperties "plugin_flash, plugin_flashverex" %>

Specifically, you're calling the SetExtProperties method of the bh object that you created a few moments ago. Finally, because you're using these advanced properties, you need to call the GetExtPropertiesEx method:

<% bh.GetExtPropertiesEx 0, "", "Please wait...", "&nbsp;Performing   browser test." %>

At this point, you have a page that determines both the presence of Macromedia Flash and the version of Macromedia Flash if it's available. If you've been following along in your IDE, save the file now as flashdetection.asp to a folder within a web-accessible directory (I've chosen c:\inetpub\wwwroot\browserhawk\) and then browse to http://localhost/browserhawk/flashdetection.asp. You should see a short message ("Performing browser test."), and then the page should refresh to a blank page.

At this point you're probably saying, "Gee Aaron, I don't see anything! That didn't help me very much at all! I need to be able to redirect my users to a different page or include different content based on the version of Macromedia Flash the user has installed." And you're right. Our page doesn't really do anything yet. So let's get working again! With the file 'flashdetection.asp' open, add the following lines of code to your script below the 'bh.GetExtPropertiesEx' method:

<%
  flashInstalled = bh.plugin_flash
  flashVersion = bh.plugin_flashverex
%>

The code above creates two variables: "flashInstalled" and "flashVersion" and initializes them to values given to us by the BrowserHawk object. The plugin_flash property of the bh object returns -1 if it is not possible to detect if the Macromedia Flash plug-in is installed, returns 0 if the Macromedia Flash plug-in is not installed, or returns the version of Macromedia Flash. The plugin_flashverex property returns a string with the build number of the Macromedia Flash plug-in, if it is installed (for example, "6,0,79,0" under IE on Windows, or "6.0 r79" under Netscape).

Now you can go down one of two roads: You can transfer the user to a different page, or you can display different content to the user based on the two variables above.

Here's an example of using BrowserHawk's information to redirect the user to a different resource depending on whether or not he has Macromedia Flash installed:

<%
'redirect user based on whether or not they flash installed
if flashInstalled = 0 or flashInstalled = -1 then
 server.transfer("/browserhawk/noflash.html")
else 
 server.transfer("/browserhawk/flash.html")
end if
%>

This is an example of using BrowserHawk's information to show different content based on the version of Macromedia Flash the user has installed:

<%
'show different content based on the version of Macromedia Flash
if left(flashVersion, 1) = 6 then
 response.write "You have version 6."
else 
 response.write "You have Macromedia Flash version 5 or lower."
end if
%>


ASP.NET and BrowserHawk

ASP.NET uses the same ActiveX component that the ASP version uses but the syntax is a bit different. Additionally, if you're using version 6 or older of BrowserHawk, you'll need to do one of the following:

  1. Add a reference to the BrowserHawk component to your project by choosing Project>Add Reference from the main menu of the Visual Studio editor with your source .aspx open, and selecting BrowserHawk 6.x from the COM section of that dialog.
  2. Copy the Interop.CYLib.dll from your \Program Files\BrowserHawk (or your BH install directory, if different) directory into the Bin directory for your .NET web application.

Once you've done one of the above, you can get started with ASP.NET.

Unlike the ASP example, there are a couple things you need to do before you start using the BrowserHawk object. Because you can write ASP.NET pages in multiple languages, you must first specify the language of your choice using the Page directive:

<%@ Page Language="c#" ASPCompat="true" %>

Two things of note here: First, I've chosen to use C# as the programming language on this page; second, you must use the ASPCompat="true" attribute within the Page directive. This lets the page call COM+ 1.0 components that require access to the unmanaged Active Server Pages (ASP) built-in objects (i.e.: the BrowserHawk ActiveX component).

Next, import the BrowserHawk object library into this page's namespace:

<%@ Import Namespace="CYLib" %>

After importing the BrowserHawk library, you can begin writing C# code to instantiate a BrowserHawk object and add the properties that you want to retrieve:

<%
BrowserObj bh = new BrowserObj();
bh = (BrowserObj)Server.CreateObject("cyScape.browserObj");
bh.SetExtProperties("Plugin_Flash, Plugin_FlashVerEx", false);
bh.GetExtPropertiesEx(0, "", "Please wait...", "&nbsp;Performing browser test. Please wait...");
%>

Finally, redirect the user to an appropriate page:

<%
int flashInstalled = bh.Plugin_Flash;
String flashVersion = bh.Plugin_FlashVerEx;

// redirect user to a resource based on whether or not they Macromedia Flash installed
if (flashInstalled == 0 || flashInstalled == -1) {
 Server.Transfer("/browserhawk/noflash.html");
} else {
 Server.Transfer("/browserhawk/flash.html");
}
%>

Alternatively, you can write content directly into the response stream:

<%
int flashInstalled = bh.Plugin_Flash;
String flashVersion = bh.Plugin_FlashVerEx;

//show different content based on the version of Macromedia Flash
if (flashVersion.StartsWith("6")) {
 Response.Write("You have version 6.");
} else {
 Response.Write("You have version 5 of lower.");
}
%>


Final Thoughts and Considerations

This article has given you an in-depth understanding of the powerful and versatile BrowserHawk tool and also a solid foundation for your future work detecting the presence and version of the Macromedia Flash Player. I encourage you (if you haven't already) to download the evaluation version of BrowserHawk or BrowserHawk4J and test out other features such as the ability to test for the existence of the QuickTime plug-in or the Adobe Acrobat PDF Viewer plug-in.

Finally, this article did not touch on the extraction of data from BrowserHawk. BrowserHawk includes an API for saving information automatically to a local database and also offers a web-based reporting solution to track exactly what percentage of your site visitors are using the Macromedia Flash Player. At MINDSEYE, we've used BrowserHawk to give clients like FootJoy and FAO Schwarz a crystal clear picture of what percentage of their users have the Macromedia Flash Player and how many users have various versions of the Macromedia Flash Player. BrowserHawk gives them concrete numbers that they can use to make informed business decisions about the features and functions on their websites today and tomorrow.

Related Links:


About the author

Aaron Johnson is a Senior Software Architect for Mindseye, Inc. and has been developing large-scale websites for companies like FAO Schwarz, FootJoy, and Macromedia using ColdFusion, ASP, C#, and Java since 1996. He is a Certified ColdFusion Developer and a Microsoft Certified Systems Engineer. You can find out more about Aaron via his blog.