We have two mobile sites, one plain HTML for old devices and one built using Sencha Touch 2 for newer devices. When it came time to deploy them, I started looking for ways to make sure users ended up at the correct site based on their device's capabilities.
I did some searching, but didn't find anything that was quite the right fit for my purposes. With that in mind, here's what I've finally come up with. It's working with a pretty simple set of rules right now, but we'll probably expand on them some now that we're sure that it is working correctly. Maybe this will give someone else who might be looking for a similar solution a headstart.
The first step was reliably detecting the user's device. There are quite a few options out there, but I settled on http://wurfl.sourceforge.net/. Specifically, their PHP API. I took a hard look at http://www.apachemobilefilter.org/, which can use WURFL data to handle device detection using Perl and an Apache module, but in testing it had problems accurately detecting devices, despite using the same data set as the WURFL PHP API. In the end, the PHP API seemed like the most reliable solution.
I wasn't sure how Sencha would play with PHP, but it actually works just fine.
Obviously, you'll need to have PHP installed and working on your webserver. I'm using Apache on CentOS, so that's pretty painless. I installed the WURFL data and PHP API into my application directory following their instructions and tested it by writing a quick 'detect.php' file:
Code:
<?php include_once './wurfl_config.php';
$requestingDevice = $wurflManager->getDeviceForHttpRequest($_SERVER);
$is_wireless = ($requestingDevice->getCapability('is_wireless_device') == 'true');
$is_smarttv = ($requestingDevice->getCapability('is_smarttv') == 'true');
$is_tablet = ($requestingDevice->getCapability('is_tablet') == 'true');
$is_phone = ($requestingDevice->getCapability('can_assign_phone_number') == 'true');
$is_mobile_device = ($is_wireless || $is_tablet);
$os_name = $requestingDevice->getCapability('device_os');
$os_version = $requestingDevice->getCapability('device_os_version');
if (!$is_mobile_device)
{
if ($is_smarttv)
{
echo "This is a Smart TV";
}
else
{
echo "This is a Desktop Web Browser";
}
}
else
{
echo "<p><p>Device OS: " . $requestingDevice->getCapability('device_os') . " " . $requestingDevice->getCapability('device_os_version');
echo "<p>Browser: " . $requestingDevice->getCapability('mobile_browser') . " " . $requestingDevice->getCapability('mobile_browser_version');
}
?>
That actually turned out to be pretty useful since I went to a couple of local Verizon & AT&T stores and hit that page with every device they had to see what kind of response I'd get. It was so handy, in fact, I left it up: http://a.fayobserver.com/detect.php
Once I had WURFL up and running correctly, I renamed my app's index.html page 'index.php' and added the following PHP to the top:
Code:
<?php
if ($_SERVER['REMOTE_ADDR'] != '127.0.0.1')
{
include_once './wurfl_config.php';
$requestingDevice = $wurflManager->getDeviceForHttpRequest($_SERVER);
$is_wireless = ($requestingDevice->getCapability('is_wireless_device') == 'true');
$is_smarttv = ($requestingDevice->getCapability('is_smarttv') == 'true');
$is_tablet = ($requestingDevice->getCapability('is_tablet') == 'true');
$is_phone = ($requestingDevice->getCapability('can_assign_phone_number') == 'true');
$is_mobile_device = ($is_wireless || $is_tablet);
$os_name = $requestingDevice->getCapability('device_os');
$os_version = $requestingDevice->getCapability('device_os_version');
# -- Build the redirect URL
$url = $_SERVER["SCRIPT_URL"];
if ($_GET["path"])
{
$url = $url . 'articles' . $_GET["path"];
}
# -- If this is Android
if ($os_name == 'Android')
{
# -- New versions scroll like , send them to the basic site for now
if ($os_version >= 4) { header('Location: http://m.fayobserver.com' . $url); exit; }
# -- Old versions also go to the basic site
if ($os_version <= 2.2) { header('Location: http://m.fayobserver.com' . $url); exit; }
}
# -- If this is IOS
else if ($os_name == 'iPhone OS')
{
# -- Old versions go to the basic site
if ($os_version < 4) { header('Location: http://m.fayobserver.com' . $url); exit; }
}
# -- If this is a Blackberry
else if ($os_name = 'RIM OS')
{
# -- Old versions go to the basic site
if ($os_version < 6)
{
header('Location: http://m.fayobserver.com' . $url); exit;
}
}
# -- If it's not Android, iOS or Blackberry, it goes to the basic site
else
{
header('Location: http://m.fayobserver.com' . $url);
}
# -- If we came with a query parameter from the desktop site, reformat it for our app
if ($_GET["path"])
{
header('Location: http://a.fayobserver.com/#articles' . $_GET["path"]);
}
}
?>
The first conditional statement just keeps the code from executing on my dev box while I work and when I use the build tools. There are also some definitions for tablets and TVs that I'm not using yet, but I'll need them later. The rest is pretty self-explanatory.
We're using a similar script on the basic site to redirect more advanced devices to the advanced Sencha site if they can handle it.
I've had to do some additional rewriting in Apache to handle deep-linking and that anchor tag that Sencha uses for routes, but that wouldn't apply to most people.
Finally, I updated the indexHtmlPath entry in app.json to point to index.php instead of index.html. In addition, the build tools incorrectly put 'index.html' in the cache.manifest file, so I have to update that manually after each build, but other than that, it works like a champ.