Detecting a Mobile Device with Spring Boot

Detecting mobiles is straight forward with Spring Boot when you know there’s a secret module that does the heavy lifting: Spring Mobile.

Overview

Spring Mobile helps in detection of mobile and tablet users for Spring MVC applications and also provides support for common use cases.

  1. Detection of the device
  2. Redirects to mobile sites using various strategies like Google redirects mobile users to m.google.com
  3. Site preferences - the user can set which site type he wants to access. The preference is by default stored in a cookie
  4. Rendering different Spring MVC Views depending on the device type

It also has its own Spring Boot starter, so the only thing we need to set up is adding its dependency to the pom:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mobile</artifactId>
</dependency>

Detection

Spring Mobile tries to detect the device by analyzing the user agent string and some headers. In return, you receive a Device instance containing the type (mobile, tablet and desktop) and the platform (android, ios or unknown).

The Device is available as a special Spring MVC method parameter and can be just added in your method signature.

@RequestMapping("/detect")
@ResponseBody
public String home(Device device) {
    String msg = null;
    if (device.isMobile()) {
        msg = "mobile";
    } else if (device.isTablet()) {
        msg = "tablet";
    } else {
        msg = "desktop";
    }
    return msg + " device on platform " + device.getDevicePlatform().name();
}

It can be helpful for serving different image sizes depending on the device or similar use cases.

Site preference

It is already set up by the Spring Boot starter and is ready to use as a Spring MVC parameter too.

Spring Mobile set it based on device autodetection or overriding it by the request parameter site_preference; if you set it to mobile with site_preference=mobile you will be handled as a mobile user even you are on a desktop.

In this example run a self-made version of serving different pages depending on the device.

@RequestMapping("/")
public String sitePref(SitePreference sitePreference, Model model) {
    if (sitePreference == SitePreference.NORMAL) {
        return "home";
    } else if (sitePreference == SitePreference.MOBILE) {
        return "home-mobile";
    } else if (sitePreference == SitePreference.TABLET) {
        return "home-tablet";
    } else {
        return "home";
    }
}

You can reduce service calls with it; if the mobile page of a product, i.e. book, only shows a fraction of the data of the regular page, you can reduce service and DB calls.

Device-specific Views

When using Spring MVC views, we can let Spring Mobile handle the template detection.

For this, we use LiteDeviceDelegatingViewResolver and delegate the actual rendering to our regular ViewResolver.

In your @Configuration define a Bean like:

@Bean
public LiteDeviceDelegatingViewResolver liteDeviceAwareViewResolver(@Qualifier("thymeleafViewResolver") ViewResolver delegate) {
    LiteDeviceDelegatingViewResolver resolver = new LiteDeviceDelegatingViewResolver(delegate);
    resolver.setMobilePrefix("mobile/");
    resolver.setTabletPrefix("tablet/");
    resolver.setOrder(1);
    return resolver;
}

I am using Thymeleaf in this example and pass it explicitly as a parameter with the @Qualifier annotation to our method. We also declare two directories where the LiteDeviceDelegatingViewResolver can look up mobile and tablet templates and set it to a high order in the view resolver hierarchy (otherwise it won’t be picked up).

Let’s say we have a @Controller endpoint like:

@RequestMapping("/")
public String deviceView(SitePreference sitePreference, Model model) {
    return "home";
}

When we access the endpoint now with a mobile, the liteDeviceAwareViewResolver detects the platform and will rename the view from home to mobile/home. And then passing it to the delegate.

If the template does not exist, the delegate will throw an exception. However, we can use setEnableFallback and enable a fallback for the liteDeviceAwareViewResolver. If it doesn’t find the specific template, it will fallback to the regular one; so when mobile/home does not exist, it will use home.

Switching Site

To configure site switching we must add the SiteSwitcherHandlerInterceptor to a @Configuration which extends WebMvcConfigurerAdapter.

In the example, we use the mDot strategy, which will redirect mobile users to m., here m.localhost. The second parameter declares if tablets are treated like mobiles.

@Bean
public SiteSwitcherHandlerInterceptor siteSwitcherHandlerInterceptor() {
    return SiteSwitcherHandlerInterceptor.mDot("localhost", true);
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(siteSwitcherHandlerInterceptor());
}

Also, we add it to the MVC Interceptors and are ready to go.

Side Note: The default implementation of each strategy names the domain cookie with a leading dot. This will not work with the latest Tomcat 8 version anymore as they use RFC 6265 by default.

The exception you might receive looks like:

java.lang.IllegalArgumentException: An invalid domain [.google.com] was specified for this cookie

For the tutorial, I just switched to Jetty, which still supports the leading dot. Alternatively, you can change the CookieProcessor in tomcat following this.

Conclusion

Spring Mobile is a neat little module in helping with common mobile detection and handling workflows. It’s ready to go with Spring Boot and easy to set up. No need for writing your own mobile detection.