Identifying mobile devices in Sitecore

Let’s face it. We don’t do websites anymore. Websites are what we did last year. Websites are something you develop with Drupal, Joomla or Umbraco.

Sitecore is no longer a Content Managent System. It’s a digital communication platform, allowing your customers to target their customers on every platform.

If we need to read or write to Facebook or Twitter, we build it. If we need to target desktop, tablet and mobile devices, we build it. In the same system. Not by creating parallel, almost-the-same-system systems. No, we make one system that will work on every digital platform we need it to work on.

One of the many Sitecore features that helps us achive this one-system-many-targets goal is the Device concept. It allows you to target different platforms with the same content. With this seperation of content from design, you can create device specific pages for mobile phones, printable pages or whatever you need.

ENOUGH TALK, LETS CODE

Devices are set up in /sitecore/layout/Devices:

Sitecore Devices

Sitecore Devices

When devices are set up, you can add layouts, sublayouts and renderings to each device on your template, or you can create one default fallback device:

Layout Fallback

Layout Fallback

But how are the devices changed? You can add the device to the <sites> section in the web.config. You can define an URL parameter that will change the device. Or you can develop a DeviceResolver processor and add it to the httpRequestBegin pipeline.

John West have an article on Using the Sitecore Rules Engine in a Custom Context: Setting the Context Device. This is a cool way to use the Sitecore Rules Engine to determine which device is the current.

But if you think that’s too complicated, or you just would like to know how to do it yourself, here is an example.

CREATING A httpRequestBegin PIPELINE PROCESSOR THAT CHANGES THE DEVICE BASED ON THE CURRENT BROWSER

This is an example on how to determine if the website is running on a Desktop PC, a Tablet (iPad) or a mobile phone (iPhone, Android, …) and change the Sitecore device accordingly.

First of all I will define my 3 devices, Default (Desktop PC), Tablet and Mobile:

public enum DeviceType
{
  Mobile,
  Tablet,
  Default
}

These 3 devices needs to be defined in my Sitecore installation.

Next step is to create a Device type retrieval service. This service uses the HTTP_USER_AGENT server variable to determine the current browser, and from the browser type I guess the device type.

using System.Linq;
using System.Web;

namespace PT.SiteRedirect
{
  public class DeviceTypeRetrievalService
  {
    public static DeviceType RetrieveContext()
    {
      //GETS THE CURRENT USER CONTEXT
      var context = HttpContext.Current;

      //FIRST TRY BUILT IN ASP.NET CHECK
      if (context.Request.Browser.IsMobileDevice)
      {
        return DeviceType.Mobile;
      }

      //THEN TRY CHECKING FOR THE HTTP_X_WAP_PROFILE HEADER
      if (context.Request.ServerVariables["HTTP_X_WAP_PROFILE"] != null)
      {
        return DeviceType.Mobile;
      }

      //THEN TRY CHECKING THAT HTTP_ACCEPT EXISTS AND CONTAINS WAP
      if (context.Request.ServerVariables["HTTP_ACCEPT"] != null &&
          context.Request.ServerVariables["HTTP_ACCEPT"].ToLower().Contains("wap"))
      {
        return DeviceType.Mobile;
      }

      //AND FINALLY CHECK THE HTTP_USER_AGENT
      //HEADER VARIABLE FOR ANY ONE OF THE FOLLOWING
      if (context.Request.ServerVariables["HTTP_USER_AGENT"] != null)
      {
        var userAgent = context.Request.ServerVariables["HTTP_USER_AGENT"].ToLower();

        var tablets =
          new[]
            {
              "ipad", "android 3", "xoom", "sch-i800", "tablet", "kindle", "playbook"
            };

        //Loop through each item in the list created above
        //and check if the header contains that text
        if (tablets.Any(userAgent.Contains) || (userAgent.Contains("android") && !userAgent.Contains("mobile")))
        {
          return DeviceType.Tablet;
        }

        //Create a list of all mobile types
        var mobiles =
          new[]
            {
              "midp", "j2me", "avant", "docomo",
              "novarra", "palmos", "palmsource",
              "240x320", "opwv", "chtml",
              "pda", "windows ce", "mmp/",
              "blackberry", "mib/", "symbian",
              "wireless", "nokia", "hand", "mobi",
              "phone", "cdm", "up.b", "audio",
              "SIE-", "SEC-", "samsung", "HTC",
              "mot-", "mitsu", "sagem", "sony"
              , "alcatel", "lg", "eric", "vx",
              "NEC", "philips", "mmm", "xx",
              "panasonic", "sharp", "wap", "sch",
              "rover", "pocket", "benq", "java",
              "pt", "pg", "vox", "amoi",
              "bird", "compal", "kg", "voda",
              "sany", "kdd", "dbt", "sendo",
              "sgh", "gradi", "jb", "dddi",
              "moto", "iphone", "Opera Mini"
            };

        //Loop through each item in the list created above
        //and check if the header contains that text
        if (mobiles.Any(userAgent.Contains))
        {
          return DeviceType.Mobile;
        }
      }

      return DeviceType.Default;
    }
  }
}

The final piece of code is the device resolver processor itself, the piece of code that is exposed in the httpRequestBegin pipeline.

using System.Web;
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Pipelines.HttpRequest;

namespace PT.SiteRedirect
{
  public class DeviceResolver : HttpRequestProcessor
  {
    public override void Process(HttpRequestArgs args)
    {
      HttpContext currentHttpContext = HttpContext.Current;

      if (currentHttpContext == null || Context.Database == null)
        return;

      if (Context.Site.Name.ToLower() != "website")
        return;

      DeviceType deviceType = DeviceTypeRetrievalService.RetrieveContext();
      switch (deviceType)
      {
        case DeviceType.Default:
          break;
        case DeviceType.Mobile:
          SetDevice("Mobile");
          break;
        case DeviceType.Tablet:
          SetDevice("Tablet");
          break;
      }
    }

    private void SetDevice(string deviceName)
    {
      DeviceItem device = Context.Database.Resources.Devices["Default"];
      device = Context.Database.Resources.Devices[deviceName];
      Context.Device = device;
    }
  }
}

The processor is added to the httpRequestBegin pipeline:

  ...
  <processor type="Sitecore.Pipelines.HttpRequest.BeginDiagnostics, Sitecore.Kernel" />
  <!-- My porocessor -->
  <processor type="PT.SiteRedirect.DeviceResolver, PT.SiteRedirect" />
  <!-- My porocessor -->
  <processor type="Sitecore.Pipelines.HttpRequest.DeviceResolver, Sitecore.Kernel" />
  ...

CONCLUSION

When the processor is added it will change the device to Default, Tablet or Mobile depending on the user agent string.

When using a fallback device to render the layout, it’s still the original device that you can read:

public string CurrentDevice
{
  get
  {
    return Sitecore.Context.Device.Name;
  }
}

With this information in hand you can start making server-side based decisions on how content should be rendered. One example could be that you render images in different sizes depending on the device:

</pre>
<div class="Logo"><a href="/">

 </a></div>
<pre>
protected void Page_Load(object sender, EventArgs e)
{
  switch (Sitecore.Context.Device.Name.ToLower())
  {
    case "default":
      break;
    case "tablet":
      break;
    case "mobile":
      logoImage.MaxWidth = logoImage.MaxWidth / 2;
      break;
  }
  logoImage.DataBind();
}

MORE INFORMATION

Thanks to Kim Schiøtt for the initial device resolver.

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in c#, Sitecore 6 and tagged , , , , , . Bookmark the permalink.

2 Responses to Identifying mobile devices in Sitecore

  1. Ivan says:

    And here is WURFL-based mobile device detection for Sitecore CMS http://sitecoresnippets.blogspot.com/2011/03/wurfl-based-mobile-detection-solution.html

    Like

  2. Gareth says:

    A nice simple solution. I ended up removing the .NET detection as it was detecting iPad as a mobile as opposed to a tablet. Another nice enhancement is reading the mobiles and tablet strings out of config.

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.