4. Device Libraries
Just looking at the HTTP headers and
the UAProf will not give us enough useful information about the mobile
devices that are accessing our websites. This is where device libraries
come to our help. Device libraries are offline databases (or online web
services) that take a user-agent string (or all of the request headers)
and return to us dozens of properties about the detected device, from
screen size, to Java ME compatibility, to Ajax support and video codec
compatibility.
4.1. WURFL
Wireless Universal Resource File (known as WURFL) is a
community-based, open source device capabilities repository created
and maintained by the developer Luca Passani (http://passani.it),
a fellow member of the Forum Nokia Champion program and author of the
preceding section on transcoders.
The library is available in the form of an XML file. While
updates to WURFL data happen every day on the WURFL DB, a publicly
available “snapshot” of the DB is produced and published about once
per month on the WURFL website.
WURFL can be downloaded for free from http://wurfl.com, and any suggestions, questions, or
bugs can be discussed in the mailing list, http://tech.groups.yahoo.com/group/wmlprogramming.
Note:
If you are having doubts about how to pronounce WURFL, you can
find a WURFL pronunciation link on the library’s home page, where
you can listen to the word in English and Italian.
The sources of information include official technical
information published by manufacturers, UAProf files, and data
collected by the community after testing on real devices. Today, the
WURFL database contains thousands of devices (11,000 profiles, 7,000
of which have a unique brand and model), with information on
subversions, operating systems, firmware and hardware variations, and
hundreds of attributes that we can query for each one.
4.1.1. Architecture
WURFL groups the devices into a hierarchy of devices and
attributes. Some devices are equivalent to other devices from the
same series, possibly with some new features, so there is a fallback mechanism in WURFL allowing a
device to extend the features of another one. The same applies for
different models in the same brand or even different brands with the
same operating system.
Also, there is a feature called “actual device root” that
manages multiple subversions (different firmware) of the same
device, so the information is not duplicated in two records; the
subversion will be based on the main record with any added or
different abilities noted.
The WURFL database has a root fallback device called “generic
device” that is matched when the device, the brand, and the series
can’t be determined.
4.1.2. Patch file
What should you do if you need to make changes to the WURFL
XML, whether to identify new devices or bugs that you’ve found or to
add new private or public capabilities to be queried? Changing the
original WURFL XML would be impractical, because you would have
problems in the future when you wanted to download updates from the
site.
That is why a patch file is included in
the WURFL architecture. A patch is like a mini-WURFL (similar
syntax, but typically a lot smaller in size). The WURFL API will
merge the patch information with the information in the WURFL
database when the service starts.
Note:
If you find a bug, new devices, or capabilities that aren’t
private to your development, report them to the WURFL team or
apply to become a WURFL contributor.
You can register to become a contributor by following the
instructions at http://db.wurflpro.com/static/become_a_contributor.htm.
You will be required to study religiously the WURFL conventions,
available at http://db.wurflpro.com/static/top.htm.
Remember, this is a community project, and we are all part
of the community.
WURFL is intended for use on mobile websites; that is why this
library does not detect desktop browsers, or if they are detected
misidentifies them as some fallback mobile. If users may access your
mobile website from their desktops and you want to be able to detect
that using WURFL, you can download a web patch
that will detect desktop web browsers like Firefox and Internet
Explorer. You’ll need to merge this patch with the main XML.
Note:
If you find a generic_device, this is a device that is
not included in the WURFL database. It’s good practice to log and
report this information and the user agent received so it can be
investigated and recognized in the future.
4.1.3. Capabilities
Every ability, property, or attribute is called a
capability in the WURFL world. Capabilities are
organized into groups. Each capability for each device has an
optional string value (taken from the device itself, or from the
fallback mechanism). That value can be converted to a Boolean, a
number, a string, or an empty string.
The most useful groups at the time of this writing are shown
in Table 3.
Table 3. Most useful WURFL capability groups
Group
name | Capabilities
related to |
---|
product_info | Device information,
such as the brand, model, operating system, and
browser |
wml_ui | WML rendering,
including soft key support, WTAI support, and table
support |
chtml_ui | cHTML
rendering |
xhtml_ui | XHTML rendering,
including tel URI scheme
support, accesskey
support, iframe support, and file upload
support |
ajax | Ajax and DOM support,
including support for getElementById, innerHTML, and CSS
manipulation |
markup | Markup
compatibility |
cache | Cache
support |
display | The screen and
display (physical dimensions, resolution, line rows,
etc.) |
image_format | Image formats,
including support for Animated GIF and SVG |
wta | WTAI, including voice
call support |
security | Encryption, including
HTTPS support |
bearer | Networks, including
WiFi and VPN support |
storage | Limits (e.g., max URL
length) |
object_download | Formats and object
downloading support for each typical format |
streaming | Audio and video
streaming per format and codec |
wap_push | WAP Push attribute
support |
j2me | Java ME configuration
and profile versions and API compatibility |
mms | MMS
support |
sms | SMS
support |
sound_format | Support for audio
codecs and formats |
flash_lite | Flash support on the
browser, for standalone applications, and for wallpaper or
screensavers |
css | CSS
properties |
transcoding | Whether the client is
detected as a transcoder |
rss | RSS
support |
pdf | PDF viewing
support |
playback | Formats that can be
played by the device |
As you can see, the information that the XML provides is
really complete. If you want to browse all the capabilities, you can
browse the XML with any reader or use the tools that come with the
Java API. You can check the first device definition, as the generic
device and fallback for all devices. If any property is not defined
in the generic device, there will be no fallback value to use if the
device does not define it.
Table 4 shows the
most important capabilities we can query. Remember that there are
dozens of other properties that you can query; take a look at the
library so you’ll have an idea of all the possibilities.
Table 4. Most useful WURFL capabilities
Capability
name | Type | Indicates... |
---|
brand_name | String | The device’s brand
name (e.g., Apple, Nokia, or HTC) |
model_name | String | The device’s model
name (e.g., iPhone, N97, Nexus One) |
marketing_name | String | The device’s
marketing name, including the brand, model, and possibly
another part of the name (e.g., Pearl, Touch) |
is_wireless_device | Boolean | Whether the device is
a mobile device (true) or
a desktop/notebook |
pointing_method | String | Which pointing method
is accepted (joystick, stylus, touchscreen, clickwheel, or
the empty string) |
has_qwerty_keyboard | Boolean | Whether the device
has a QWERTY keyboard (virtual or physical) |
nokia_series | Integer | The series (40, 60),
for Nokia devices |
nokia_edition | Integer | The edition of the
series, for Nokia devices |
nokia_feature_pack | Integer | The feature pack of
the series, for Nokia devices |
device_os | String | The name of the
operating system |
device_os_version | String | The version of the
OS |
mobile_browser | String | The name of the
browser |
mobile_browser_version | String | The version of the
browser |
resolution_width | Integer | The screen width in
pixels |
resolution_height | Integer | The screen height in
pixels |
max_image_width | Integer | The display’s usable
width in pixels |
max_image_height | Integer | The display’s usable
height in pixels |
xhtml_support_level | Integer | The level of XHTML
compatibility, from −1 to
4: −1: No
support 0: Basic
support (poor or no CSS support, basic form support,
basic or no table support) 1 and
2: Advanced basic
support (basic CSS and table support) 3: Medium
support, including excellent CSS support) 4: Advanced
support, including Ajax support
|
preferred_markup | String | The markup best
supported by the device (even if it supports a newer
one) |
xhtml_format_as_css_property | Boolean | Whether -wap-input-format is
available |
xhtml_make_phone_call_string | String | The prefix preferred
for making phone calls in a URL |
xhtml_send_sms_string | String | Whether and how the
device supports triggering the SMS client from a link (can
be sms:, smsto:, or the empty string,
meaning not supported) |
xhtml_file_upload | String | Whether the device
allows file uploading (returns not_supported, supported, or supported_user_intervention) |
xhtml_supports_iframe | String | Whether the device
supports iframes (returns none, partial, or full) |
ajax_supports_javascript | Boolean | Whether the device
supports JavaScript with basic operations (dialogs, form
values, timers, and document.location) |
ajax_supports_getelementbyid | Boolean | Whether document.getElementById works on
the device |
ajax_xhr_type | String | Which syntax to use
when creating an XMLHTTPRequest object (none, standard for the native XHR
object, msxml2 for the
normal Microsoft ActiveX object, and legacy_microsoft for the older
one) |
ajax_support_inner_html | Boolean | Whether we can change
the innerHTML property
dynamically |
ajax_manipulate_dom | Boolean | Whether typical DOM
methods are available |
ajax_support_event_listener | Boolean | Whether the browser
allows event registration through event
listeners |
html_wi_oma_xhtmlmp_1_0 | Boolean | Whether the browser
supports XHTML MP 1.0 |
html_web_3_0 | Boolean | Whether the browser
supports HTML 3 |
html_web_4_0 | Boolean | Whether the browser
supports HTML 4 |
gif_animated | Boolean | Whether Animated GIF
is supported |
svgt_1_1 | Boolean | Whether SVG 1.1 is
supported |
svgt_1_1_plus | Boolean | Whether SVG 1.1+ is
supported |
flash_lite_version | String | Which version of
Flash is supported |
fl_browser | Boolean | Whether the browser
supports Flash content |
is_transcoder | Boolean | Whether a transcoder
was detected as a proxy from the real device |
transcoder_ua_header | String | Which header we can
find the original device’s user-agent string in, if a
transcoder was detected |
multipart_support | Boolean | Whether the browser
supports multipart documents |
4.2. WURFL usage
You can use WURFL by browsing the file as you would any other
XML file and matching user-agent strings, but the wheel has already
been invented, and on the same website where you can download the XML
you will find APIs for the most common server platforms: Java, PHP,
and .NET (in beta at the time of this writing). Generally speaking you
should use the new APIs available on the website, but for
compatibility purposes you can still find old APIs to download.
These APIs allow us to use WURFL in a couple of lines, with many
advantages:
Automatic device detection using the header
information
Two-step user agent analysis (optimized and clever
user-agent searching inside the XML)
Detection of transcoders and proxies, and matching of the
correct user agent and device information
Merging of the static XML provided by WURFL with patches
(the web patch or your own), providing a simple and unique way to
query capabilities
Caching of the XML parsing for the best performance on every
request
4.2.1. PHP API installation
To use WURFL in PHP, you should download the PHP API from
http://wurfl.sourceforge.net/nphp and extract
the contents of the GZIP file. The package contains documentation,
examples, resources, unit tests, and a WURFL folder where the API
resides.
Note:
The PHP WURFL API allows us to save persistence and cache
information using memcache instead of using the filesystem.
To make it work, follow these steps:
Copy the WURFL folder
into your web server root folder.
Copy the resources or
examples/resources folder
into your web server root folder (you can change the
name).
Download the latest wurfl-<version>.zip file from
the website and copy it to the new resources folder (along with the
web_browsers_patch.xml
file, if you need it).
Create a cache folder
inside the resources folder
(or in another place, with a different name if you like) and
verify that it PHP scripts have write permissions for this
folder.
Edit the resources/wurfl-config.xml file and
check that the <main-file> tag matches the name
of the ZIP file containing the main XML repository. It can also
be a decompressed XML file.
Edit the resources/wurfl-config.xml file, go
to the persistence node, and check that the <params> tag matches the name of
the cache folder, as in
<params>dir=cache</params>.
The path needs to be relative to the config XML folder.
Once WURFL is installed, we can create our first PHP script
that uses the repository. Using version 1.0 of the API, the code
will be:
<?php
require_once('WURFL/WURFLManagerProvider.php');
$configFile='resources/wurfl-config.xml';
$wurflManager=WURFL_WURFLManagerProvider::getWURFLManager($configFile);
$device=$wurflManager->getDeviceForHttpRequest($_SERVER);
?>
In API 1.1, the objects were changed and WURFLManagerProvider was deprecated. So,
the preceding code should be:
<?php
define("WURFL_DIR", dirname(__FILE__) . 'WURFL/');
require_once(WURFL_DIR . 'Application.php');
$configFile='resources/wurfl-config.xml';
$wurflConfig=new WURFL_Configuration_XmlConfig($configFile);
$wurflManagerFactory=new WURFL_WURFLManagerFactory($wurflConfig);
$wurflManager=$wurflManagerFactory->create();
$device=$wurflManager->getDeviceForHttpRequest($_SERVER);
?>
If you run this file on your web server (local or remote), you
will need to wait 1 or 2 minutes the first time while it creates the
cache folder to enable quick detection in future requests. If you
receive a blank page, great! If you get an error, you need to check
all the steps again.
Warning:
If you’re working on a local server and are going to upload
your website to another server using FTP or some other protocol,
it will be better to not upload the cache folder because it will
contain thousands of files. It is better to leave the server to
recreate them locally.
4.2.2. Using the PHP API
The PHP API is an object-oriented API. Once you have the
WURFLManager object, regardless of whether you
are using version 1.0 or 1.1 of the API, you can use it.
Warning:
If your server is too loaded, you may get a timeout error
when processing WURFL the first time. If this happens, ask your
server provider how to increase the maximum script time limit or
change the PHP.ini
file.
A typical usage is getting a device object using the manager’s
methods:
If you want to access the capabilities of the current device
accessing your website, the first option is the best one. If you
want to get properties for other devices, you can use the user_agent method or the deviceId method. Every device in WURFL has
an ID that we can store in our databases for statistics or logs. We
can then look for its capabilities later, after the mobile
request.
Note:
You can browse the WURFL devices database using the free
online tool Tera-WURFL Explorer, available at http://www.tera-wurfl.com/explore.
You can also get all the possible groups and capabilities
using getListOfGroups() and
getCapabilitiesNameForGroup(groupId), both
methods of the manager.
Once you have the device object, you can get all properties
with the getAllCapabilities()
method or query for one particular feature with getCapability($capabilityName).
If you are using the desktop web patch, you can determine
whether the client is a desktop or a mobile device:
if ($device->getCapability('is_wireless_device')==false) {
// It is not a mobile device
header('Location: http://yourdomain.com');
}
To detect if it is an iPhone or iPod Touch, use:
if ($device->getCapability('brand_name')=='Apple') {
// It is an iPhone, redirect to a prepared version
header('Location: http://yourdomain.com/iphone');
}
With the capability, you can then decide whether or not to
provide some feature. For example:
if ($device->getCapability('xhtml_file_upload')=='supported') {
echo '<input type="file" />';
}
A great option if you are offering content is to explicitly
display to the user his phone model in the marketing
information:
echo 'Download compatible content for your ' .
$device->getCapability('marketing_name');
Note:
If you want to test whether your WURFL code is working on
your desktop browser, you can use Firefox and the free plug-in
User Agent Switcher that allows Firefox to change its user-agent
string to that of any other device of your liking.
4.2.3. WURFL-related products
A lot of related tools, utilities, and frameworks are
available at http://wurfl.sourceforge.net.
These include:
Device Thumbnails (a repository of device images for
thumbnails on websites)
Image Server (a Java servlet for dynamic conversion,
scaling, and delivery of images to mobile devices)
Tera-WURFL (a PHP and MySQL implementation of the WURFL
repository)
GAIA Image Transcoder
PHP Image Rendering Library (works with an old version of
the PHP API)
Apache Mobile Filter
Note:
The Apache Mobile Filter is an open source solution for
redirecting users to different versions using filters in an Apache
module that looks into the WURFL database. It also supports image
resizing. The project is available at http://sourceforge.net/projects/mobilefilter.
4.3. DeviceAtlas
In February 2008 (many years later than WURFL), the
dotMobi company, which owns the .mobi top-level
domain, launched its own device database that is similar in many ways
to WURFL.
DeviceAtlas is a commercial product (with a free testing version
for developers) available at http://deviceatlas.com that has partnerships with many
data providers. According to dotMobi, this is not only the largest but
also the most accurate device database on the market.
The main features are:
Monthly, weekly, daily, or constant updates to the database,
depending on your license
A data explorer to browse the database from the Web
JSON data format support
APIs for PHP, Java, .NET, Python, and Ruby
Apache server module (with the enterprise license)
At the time of this writing, the basic license costs $99 per
server per year and includes monthly updates but excludes the
possibility to merge private data and other options available in
higher license options.
4.3.1. Installation
You can apply for a free developer evaluation version at the
website or buy a commercial version and then download the data and
API from http://deviceatlas.com/downloads. You
will receive by email the license key, which is valid for one year.
You will also receive the direct links to download the data file (in
JSON format) in ZIP format.
Note:
The W3C is trying to standardize the device database
repositories in the Device Descriptions Working Group, currently
in draft at http://www.w3.org/TR/DDR-Simple-API. DeviceAtlas is
offering its database in this new format as a preview.
You can get an automatic update of the JSON file using the URL
https://deviceatlas.com/getJSON.php?licencekey=<license>&format=zip
(inserting your license key in the URL).
4.3.2. Properties
The data available in DeviceAtlas is segmented into
categories. The most important properties per category are:
Device name: vendor,
model
Hardware: displayHeight, displayWidth, mobileDevice, touchScreen
Environment: developerPlatform, developerPlatformVersion, osAndroid, osLinux, osOsx, osProprietary, osRim, osSymbian, osWindows, osVersion
Web browser: markup.xhtmlMp10, memoryLimitMarkup, uriSchemeSms,
uriSchemeSmsTo, uriSchemeSmsTel, vCardDownload, usableDisplayWidth, usableDisplayHeight
Network protocols: EDGE, GPRS, HDSPA
JavaVM: cldc, jsr118, jsr139, jsr30, jsr37, midp
AudioPlayer: aac,
amr, mp3
Streaming: stream.3gp.aac.lc, stream.3gp.h263, stream.3gp.h264.level1, stream.mp4.aac.lc
VideoPlayer: 3gp.h263,
3gp.h264.level1, mp4.aac.lc, wmv
DRM: drmOmaCombinedDelivery, drmOmaForwardLock, drmOmaSeparateDelivery
You can browse all the data available with your license at
http://deviceatlas.com/explorer.
Warning:
Remember that if you have a developer account your database
file will not be updated if you download it again, and if you have
a basic license with monthly downloads a new file will not be
available until 30 days from when you downloaded the previous
version.
4.3.3. PHP API
Inside the PHP API package you will find a doc folder containing PHPDoc
documentation, a sample folder
containing examples of usage, and a Mobi folder containing the API. The PHP
API requires PHP version 5.2.3 with JSON support.
You need to copy the Mobi
folder with all of its content into your website root, but you can
put the JSON data file in any place you want. In your PHP file, you
must include the file Mobi/Mtld/DA/Api.php.
A typical project will look like the following:
<?php
include('Mobi/Mtld/DA/Api.php');
// We get a tree object loading the JSON
$tree = Mobi_Mtld_DA_Api::getTreeFromFile("deviceatlas.json");
// We get all the properties for the User Agent
$properties = Mobi_Mtld_DA_Api::getProperties($tree,
$_SERVER['HTTP_USER_AGENT']);
// Or we can get one property at a time using
$value = Mobi_Mtld_DA_Api::getProperty($tree, $ua, 'some-property');
?>
If you want a cache implementation, you’ll need to do it
yourself or have memcache installed on the server and save the
entire tree as the sample provided by the API. The Java and .NET
APIs have better support for caching techniques.
4.4. The ASP.NET Mobile Device Browser File
If you work with the ASP.NET platform, you can find an
open source mobile browser database at http://mdbf.codeplex.com, released by the Mobile Browse
Platform Team at Microsoft. This file is attached to the current
ASP.NET browser detection mechanism and is updated frequently. The
sources of the information include WURFL, UAProf files, contributions
from the community, and others.
To use it, all you need to do is download the mobile.browser file from the website,
create a folder called App_Browsers (if you don’t already have
one) with a mobile subfolder, and
copy the downloaded file into that folder. That’s it!
Warning:
The ASP.NET Mobile Device Browser File is only compatible with
.NET Framework 2.0 and newer versions.
You can use the existing Request.Browser object in ASP to get
information about the requesting
device. IsMobileDevice will tell
you whether or not it is a mobile browser, Platform will tell you the operating system,
ScreenPixelsWidth and ScreenPixelsHeight will
tell you the screen dimensions, and you can query any other property
using Request.Browser as a Collection.
Here is an example in C#:
if (Request.Browser.IsMobileDevice) {
Response.Write("This is a " + Request.Browser.Platform + " device");
if (Request.Browser["SupportsTouchScreen"]) {
// It is a touch-based device
}
}
4.4.1. Capabilities
A full list of capabilities can be found at http://mdbf.codeplex.com/wikipage?title=capabilities,
but the most important are included in Table 5. There are
capabilities for each video, audio, and image property.
Table 5. Common capabilities of the ASP.NET Mobile Device Browser
File
Capability | Return
class | Indicates… |
---|
AcceptsImageSVG | Boolean | Whether the device
supports SVG 1.1 |
AjaxCanManipulateCss | Boolean | Whether we can change
CSS properties from JavaScript |
AjaxSupportsFullDom | Boolean | Whether we can use
full DOM methods |
AjaxSupportsGetElementByID | Boolean | Whether we can use
getElementById from
JavaScript |
AjaxSupportsInnerHtml | Boolean | Whether we can use
innerHTML without
problems |
AjaxXmlHttpRequestConstructorSyntax | String | Which syntax to use
when creating an XMLHTTPRequest object (none for no Ajax support, standard for the native XHR
object, or msxml2 for IE
syntax) |
InputType | String | Which input type is
supported (keyboard,
telephoneKeypad, or
virtualKeyboard) |
IsMobileDevice | Boolean | Whether or not the
current device is a mobile device |
JavaScript | Boolean | Whether the device
supports JavaScript |
MobileDeviceManufacturer | String | The device’s brand
name |
MobileDeviceModel | String | The device’s model
name |
PreferredRenderingMime | String | The preferred MIME
type for XHTML content |
SupportedFlashVersion | String | Which Flash version
is supported (none or the
version number) |
SupportsAccesskeyAttribute | Boolean | Whether the device
supports the accesskey
value |
SupportsCssBackgroundImage | Boolean | Whether the device
supports defining background images |
SupportsEmbeddedFlashInWebPages | Boolean | Whether the device
supports embedding a SWF file |
SupportsTouchScreen | Boolean | Whether the device is
touch-based |
SupportsWapPush | Boolean | Whether the device
supports WAP Push |
SupportsXhtmlRendering | Boolean | Whether the device
supports XHTML |
4.5. Service-based solutions
You may not want to write all this yourself. Services are
available to help; we’ll look at a few of them here.
4.5.1. Movila DetectFree
Movila Detection (http://www.moviladetection.com) is a server-side Java
solution to detect in 500 microseconds which device is using an
embedded repository. It also
works as a tool for URL rewrites. However, Movila’s most-used
feature is the free service called DetectFree.
DetectFree is a free light version of the service available
for PHP and JavaScript (and for any other platform that sends HTTP
requests) that allows you to detect whether the connecting device is
a mobile device. You can find samples and documentation at http://www.moviladetection.com/detectfree. Just to
illustrate how easy it is to use, the following sample is a
JavaScript detection mechanism:
<script src="http://detectfree.moviladetection.com/detectfree.js"
type="text/javascript"></script>
<script type="text/javascript">
if (is_mobile) {
alert("This is a mobile device");
}
</script>
4.5.2. DetectRight
DetectRight is a detection engine, device database,
analytics engine, and API/SDK with both service-based and dedicated
server options. Free noncommercial/developer licenses are available,
and a shared-service license begins at 399 euros per month. It
features SOAP and REST access, unique custom identification,
country-level geolocation, and profiles in WURFL, DeviceAtlas,
UAProf, DetectRight, and Java ME Polish–compatible formats. It
features over 20,000 devices at the time of this writing.
Note:
If you want easy and quick mobile detection, at http://www.detectmobilebrowsers.mobi you will find
a little PHP code that allows you to determine whether the user is
using a mobile browser without any repository, database, or service
call.
If you register at http://www.detectright.com, you will receive via
email a key that enables you to access a variety of PHP, .NET, and
SOAP samples and APIs.
Remember that this is a service-based solution, so you don’t
need to download or update any database on your server. Every
request will be sent over the Internet to the DetectRight
servers.
Warning:
Remember that when using service-based solutions, your
mobile website’s performance will depend on the reliability of the
third-party server to which you are connecting.
You can download the PHP or .NET API for easy usage for those
platforms.
In PHP, once you’ve downloaded the API you can use the service
as shown in the following sample:
include_once("detectRight.php");
DetectRight::$druser = '<detectright.com username>';
DetectRight::$drpassword = '<detectright.com password>';
// possible values: DR, WURFL, W3C, UAProfile, J2MEPolish
DetectRight::$defaultSchema = 'DR';
$profile=DR_Customer::deduceCustomer($_SERVER);
$value = $profile['<property>'];
The API can also be used to download lists of manufacturers
and handsets, and to request individual ones by manufacturer/model
name.