Note: This guide assumes that you have access to a running instance of the WURFL Microservice HTTP Server, either through ScientiaMobile's Docker Registry, the AWS Marketplace, the Azure Marketplace, or other distribution channels. The guide also assumes familiarity with Device Detection (WURFL) and WURFL Capabilities.
WURFL Capabilities: WURFL capabilities are device properties represented in WURFL. While users of the WURFL Microservice for Docker have access to the list of licensed capabilities, customers who obtained the product through one of the Marketplace will have access to the WURFL capability list, predefined for the product they have licensed. Please note that there are two types of capabilities supported in WURFL: Static and Virtual.
While the difference between the two is mostly immaterial for you as a user as far as their practical usage goes, you still need to use two separate methods to use one or the other.
WURFL Microservice Client API (wmclient
): Given an HTTP Request and a capability, the WURFL Client will return the property value.
Note: While the
wmclient
is an API, it requires interaction with the WURFL Microservice server to work. This introduces some latency (hugely mitigated by a built-in caching layer). For this reason, ScientiaMobile does not refer to the WURFL Microservice Client (wmclient
) as a "WURFL API". That name is reserved for the WURFL OnSite APIs.
wmclient
In order to use the wmclient
please follow these instructions:
Download example.go from WURFL repository.
Edit example.go
(in the package) by modifying the Create()
call to include the public IP address of your AMI instance, Azure VM instance or Docker container service (i.g. replacing localhost with the IP address of your running HTTP server, be it an AMI instance, Azure VM or Docker container service).
Note: There are multiple ways in which a service deployed through Docker can be exposed to the world around it. Please refer to your DevOps if in doubt of the actual address at which the service is running.*
go get ./…
), compile (go build example.go
), and run (./example
) the included example.go
file. Here's the code for your reference:package main
import (
"fmt"
"log"
"sort"
"strings"
"github.com/wurfl/wurfl-microservice-client-golang/v2/scientiamobile/wmclient"
)
// Implements sort.Interface for []wmclient.JSONModelMktName
type ByModelName []wmclient.JSONModelMktName
func (c ByModelName) Len() int {
return len(c)
}
func (c ByModelName) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}
func (c ByModelName) Less(i, j int) bool {
return c[i].ModelName < c[j].ModelName
}
func main() {
var err error
// First we need to create a WM client instance, to connect to our WM server API at the specified host and port.
ClientConn, err := wmclient.Create("http", "localhost", "80", "")
if err != nil {
// problems such as network errors or internal server problems
log.Fatal("wmclient.Create returned :", err.Error())
}
// By setting the cache size we are also activating the caching option in WM client. In order to not use cache, you just to need to omit setCacheSize call
ClientConn.SetCacheSize(100000)
// We ask Wm server API for some Wm server info such as server API version and info about WURFL API and file used by WM server.
info, ierr := ClientConn.GetInfo()
if ierr != nil {
fmt.Println("Error getting server info: " + ierr.Error())
} else {
fmt.Println("WURFL Microservice information:")
fmt.Println("Server version: " + info.WmVersion)
fmt.Println("WURFL API version: " + info.WurflAPIVersion)
fmt.Printf("WURFL file info: %s \n", info.WurflInfo)
}
// set the capabilities we want to receive from WM server
// Static capabilities
sCapsList := strings.Fields("model_name brand_name")
// Virtual capabilities
vCapsList := strings.Fields("is_smartphone form_factor")
ClientConn.SetRequestedStaticCapabilities(sCapsList)
ClientConn.SetRequestedVirtualCapabilities(vCapsList)
ua := "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3"
// Perform a device detection calling WM server API
JSONDeviceData, callerr := ClientConn.LookupUserAgent(ua)
if callerr != nil {
// Applicative error, ie: invalid input provided
log.Fatalf("Error getting device data %s\n", callerr.Error())
}
// Let's get the device capabilities and print some of them
fmt.Printf("WURFL device id : %s\n", JSONDeviceData.Capabilities["wurfl_id"])
// print brand & model (static capabilities)
fmt.Printf("This device is a : %s %s\n", JSONDeviceData.Capabilities["brand_name"], JSONDeviceData.Capabilities["model_name"])
// check if device is a smartphone (a virtual capability)
if JSONDeviceData.Capabilities["is_smartphone"] == "true" {
fmt.Println("This is a smartphone")
}
fmt.Printf("This device form_factor is %s\n", JSONDeviceData.Capabilities["form_factor"])
// Get all the device manufacturers, and print the first twenty
deviceMakes, err := ClientConn.GetAllDeviceMakes()
if err != nil {
log.Fatalf("Error getting device data %s\n", err.Error())
}
var limit = 20
fmt.Printf("Print the first %d Brand of %d\n", limit, len(deviceMakes))
// Sort the device manufacturer names
sort.Strings(deviceMakes)
for _, deviceMake := range deviceMakes[0:limit] {
fmt.Printf(" - %s\n", deviceMake)
}
// Now call the WM server to get all device model and marketing names produced by Apple
fmt.Println("Print all Model for the Apple Brand")
modelMktNames, err := ClientConn.GetAllDevicesForMake("Apple")
if err != nil {
log.Fatalf("Error getting device data %s\n", err.Error())
}
// Sort modelMktNames objects by their model name
sort.Sort(ByModelName(modelMktNames))
for _, modelMktName := range modelMktNames {
fmt.Printf(" - %s %s\n", modelMktName.ModelName, modelMktName.MarketingName)
}
// Now call the WM server to get all operative system names
fmt.Println("Print the list of OSes")
oses, err := ClientConn.GetAllOSes()
if err != nil {
log.Fatalf("Error getting device data %s\n", err.Error())
}
// Sort and print all OS names
sort.Strings(oses)
for _, os := range oses {
fmt.Printf(" - %s\n", os)
}
// Let's call the WM server to get all version of the Android OS
fmt.Println("Print all versions for the Android OS")
versions, err := ClientConn.GetAllVersionsForOS("Android")
if err != nil {
log.Fatalf("Error getting device data %s\n", err.Error())
}
// Sort all Android version numbers and print them.
sort.Strings(versions)
for _, version := range versions {
fmt.Printf(" - %s\n", version)
}
}
If you are using device detection from code running as part of an HTTP server, it is highly recommended that you pass the complete HTTP request to the LookupRequest
method as follows:
JsonDeviceData, err := ClientConn.LookupRequest(*r)
This will provide optimal detection accuracy (see httpserver-example.go
). For a complete reference of all static and virtual capabilities, you can refer to this document. Please note that WURFL Microservice for the AWS Marketplace comes with a predefined set of capabilities.
This is the ouput of the "godoc scientiamobile/wmclient" command for the wmclient package.
PACKAGE DOCUMENTATION
package wmclient
import "github.com/wurfl/wurfl-microservice-client-golang/v2/scientiamobile/wmclient"
FUNCTIONS
func GetAPIVersion() string
GetAPIVersion returns the version number of WM Client API
TYPES
type JSONDeviceData struct {
APIVersion string `json:"apiVersion"`
Capabilities map[string]string `json:"capabilities"`
Error string `json:"error, omitempty"`
Mtime int64 `json:"mtime"` // timestamp of this data structure creation, kpet for compatibility with old wurfl cloud
Ltime string `json:"ltime"` // time of last wurfl.xml file load
}
JSONDeviceData models a WURFL device data in JSON string only format
type JSONDeviceDataTyped struct {
APIVersion string `json:"apiVersion"`
Capabilities map[string]interface{} `json:"capabilities"`
Error string `json:"error, omitempty"`
Mtime int64 `json:"mtime"`
Ltime string `json:"ltime"`
}
JSONDeviceDataTyped models a WURFL device data in JSON typed format
type JSONDeviceOsVersions struct {
OsName string `json:"device_os"`
OsVersion string `json:"device_os_version"`
}
JSONDeviceOsVersions holds device os name and version
type JSONInfoData struct {
WurflAPIVersion string `json:"wurfl_api_version"`
WurflInfo string `json:"wurfl_info"`
WmVersion string `json:"wm_version"`
ImportantHeaders []string `json:"important_headers"`
StaticCaps []string `json:"static_caps"`
VirtualCaps []string `json:"virtual_caps"`
Ltime string `json:"ltime"`
}
JSONInfoData - server and API informations
type JSONMakeModel struct {
BrandName string `json:"brand_name"`
ModelName string `json:"model_name"`
MarketingName string `json:"marketing_name,omitempty"`
}
JSONMakeModel models simple device "identity" data in JSON format
type JSONModelMktName struct {
ModelName string `json:"model_name"`
MarketingName string `json:"marketing_name,omitempty"`
}
JSONModelMktName holds model_name and marketing_name
type Request struct {
LookupHeaders map[string]string `json:"lookup_headers"`
RequestedCaps []string `json:"requested_caps"`
RequestedVCaps []string `json:"requested_vcaps, omitempty"`
WurflID string `json:"wurfl_id, omitempty"`
TacCode string `json:"tac_code, omitempty"`
}
Request - data object that is sent to the WM server in POST requests
type WmClient struct {
StaticCaps []string
VirtualCaps []string
ImportantHeaders []string
// contains filtered or unexported fields
}
WmClient holds http connection data to WM server and the list of static
and virtual capabilities it must return in response.
func Create(Scheme string, Host string, Port string, BaseURI string) (*WmClient, error)
Create : creates object, checks for server visibility
func (c *WmClient) DestroyConnection()
DestroyConnection - Disposes resources used in connection to server and
clears cache and other shared data structures
func (c *WmClient) GetActualCacheSizes() (int, int)
GetActualCacheSizes return the values of cache size. The first value
being the device-id based cache, the second value being the size of the
headers-based one
func (c *WmClient) GetAllDeviceMakes() ([]string, error)
GetAllDeviceMakes returns a slice of all devices brand_name capabilities
in WM server
func (c *WmClient) GetAllDevicesForMake(brandName string) ([]JSONModelMktName, error)
GetAllDevicesForMake returns a slice of an aggregate containing
model_names and marketing_names for the given brand_name
func (c *WmClient) GetAllOSes() ([]string, error)
GetAllOSes returns a slice of all devices device_os capabilities in WM
server
func (c *WmClient) GetAllVersionsForOS(osName string) ([]string, error)
GetAllVersionsForOS returns a slice of an aggregate containing
device_os_version for the given os_name
func (c *WmClient) GetInfo() (*JSONInfoData, error)
GetInfo - Returns information about the running WM server and API
func (c *WmClient) HasStaticCapability(CapName string) bool
HasStaticCapability - returns true if the given CapName exist in this
client' static capability set, false otherwise
func (c *WmClient) HasVirtualCapability(CapName string) bool
HasVirtualCapability - returns true if the given CapName exist in this
client' virtual capability set, false otherwise
func (c *WmClient) LookupDeviceID(deviceID string) (*JSONDeviceData, error)
LookupDeviceID - Searches WURFL device data using its wurfl_id value
func (c *WmClient) LookupRequest(request http.Request) (*JSONDeviceData, error)
LookupRequest - detects a device and returns its data in JSON format
func (c *WmClient) LookupUserAgent(userAgent string) (*JSONDeviceData, error)
LookupUserAgent - Searches WURFL device data using the given user-agent
for detection
func (c *WmClient) SetCacheSize(uaMaxEntries int)
SetCacheSize : set UA cache size
func (c *WmClient) SetHTTPTimeout(connection int, transfer int)
SetHTTPTimeout sets the connection and transfer timeouts for this client
in seconds. This function should be called before performing any
connection to WM server
func (c *WmClient) SetRequestedCapabilities(CapsList []string)
SetRequestedCapabilities - set the given capability names to the set
they belong
func (c *WmClient) SetRequestedStaticCapabilities(CapsList []string)
SetRequestedStaticCapabilities - set list of standard static
capabilities to return
func (c *WmClient) SetRequestedVirtualCapabilities(CapsList []string)
SetRequestedVirtualCapabilities - set list of virtual capabilities to
return
func (c *WmClient) SetupCache(deviceMaxEntries int, uaMaxEntries int)
SetupCache Deprecated: Use SetCacheSize()
Error in case of Missing Capabilities
As mentioned above, depending on the configuration of your WURFL Microservice, one of the WURFL capabilities may not be available. In this case, the JSONDeviceData.Capabilities map will not contain an entry for that capability and caller will get the zero value for it (nil).
Presence of a capability can be checked with:
value, ok := JSONDeviceData.Capabilities["has_cellular_radio"]
And check for:
ok = true/false
Additional capabilities can always be obtained by upgrading to greater version of the AMIs in the AWS Marketplace or by contacting ScientiaMobile to license additional capabilities for the Docker Image or other products.
© 2024 ScientiaMobile Inc.
All Rights Reserved.
NOTICE: All information contained herein is, and remains the property of ScientiaMobile Incorporated and its suppliers, if any. The intellectual and technical concepts contained herein are proprietary to ScientiaMobile Incorporated and its suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or copyright law. Dissemination of this information or reproduction of this material is strictly forbidden unless prior written permission is obtained from ScientiaMobile Incorporated.