Skip to content

Commit d1252b3

Browse files
committed
Mobile device detection is now a custom implementation based on UAParser. Also detects some commonly used Tablets (iPad, Nexus 10, Kindle etc.) and renders the desktop view by default. Removed 51Degrees library completely.
1 parent 8c87756 commit d1252b3

10 files changed

Lines changed: 259 additions & 172 deletions

File tree

src/Libraries/SmartStore.Services/Common/IUserAgent.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,31 @@ namespace SmartStore.Services.Common
99

1010
public interface IUserAgent
1111
{
12+
string RawValue { get; set; }
13+
1214
UserAgentInfo UserAgent { get; }
1315
DeviceInfo Device { get; }
1416
OSInfo OS { get; }
17+
18+
bool IsBot { get; }
19+
bool IsMobileDevice { get; }
20+
bool IsTablet { get; }
21+
bool IsPdfConverter { get; }
1522
}
1623

1724
public sealed class DeviceInfo
1825
{
19-
public DeviceInfo(string family, bool isBot, bool isPdfConverter)
26+
public DeviceInfo(string family, bool isBot)
2027
{
2128
this.Family = family;
2229
this.IsBot = isBot;
23-
this.IsPdfConverter = isPdfConverter;
2430
}
2531
public override string ToString()
2632
{
2733
return this.Family;
2834
}
2935
public string Family { get; private set; }
3036
public bool IsBot { get; private set; }
31-
public bool IsPdfConverter { get; private set; }
3237
}
3338

3439
public sealed class OSInfo

src/Libraries/SmartStore.Services/Common/MobileDeviceHelper.cs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public partial class MobileDeviceHelper : IMobileDeviceHelper
1515
private readonly ThemeSettings _themeSettings;
1616
private readonly IWorkContext _workContext;
1717
private readonly IStoreContext _storeContext;
18-
private readonly HttpContextBase _httpConttext;
18+
private readonly IUserAgent _userAgent;
1919

2020
#endregion
2121

@@ -26,13 +26,16 @@ public partial class MobileDeviceHelper : IMobileDeviceHelper
2626
/// </summary>
2727
/// <param name="workContext">Work context</param>
2828
/// <param name="storeContext">Store context</param>
29-
public MobileDeviceHelper(ThemeSettings themeSettings, IWorkContext workContext,
30-
IStoreContext storeContext, HttpContextBase httpContext)
29+
public MobileDeviceHelper(
30+
ThemeSettings themeSettings,
31+
IWorkContext workContext,
32+
IStoreContext storeContext,
33+
IUserAgent userAgent)
3134
{
3235
this._themeSettings = themeSettings;
3336
this._workContext = workContext;
3437
this._storeContext = storeContext;
35-
this._httpConttext = httpContext;
38+
this._userAgent = userAgent;
3639
}
3740

3841
#endregion
@@ -47,20 +50,7 @@ public MobileDeviceHelper(ThemeSettings themeSettings, IWorkContext workContext,
4750
/// <returns>Result</returns>
4851
public virtual bool IsMobileDevice()
4952
{
50-
if (_themeSettings.EmulateMobileDevice)
51-
return true;
52-
53-
//comment the code below if you want tablets to be recognized as mobile devices.
54-
//SmartStore.NET uses the free edition of the 51degrees.mobi library for detecting browser mobile properties.
55-
//by default this property (IsTablet) is always false. you will need the premium edition in order to get it supported.
56-
bool isTablet = false;
57-
if (bool.TryParse(_httpConttext.Request.Browser["IsTablet"], out isTablet) && isTablet)
58-
return false;
59-
60-
if (_httpConttext.Request.Browser.IsMobileDevice)
61-
return true;
62-
63-
return false;
53+
return _themeSettings.EmulateMobileDevice || (_userAgent.IsMobileDevice && !_userAgent.IsTablet);
6454
}
6555

6656
/// <summary>
Lines changed: 187 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System.Text.RegularExpressions;
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text.RegularExpressions;
24
using System.Web;
35
using uap = UAParser;
46

@@ -10,12 +12,108 @@ public class UAParserUserAgent : IUserAgent
1012
private readonly static uap.Parser s_uap;
1113
private static readonly Regex s_pdfConverterPattern = new Regex(@"wkhtmltopdf", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
1214

15+
# region Mobile UAs, OS & Devices
16+
17+
private static readonly HashSet<string> s_MobileOS = new HashSet<string>
18+
{
19+
"Android",
20+
"iOS",
21+
"Windows Mobile",
22+
"Windows Phone",
23+
"Windows CE",
24+
"Symbian OS",
25+
"BlackBerry OS",
26+
"BlackBerry Tablet OS",
27+
"Firefox OS",
28+
"Brew MP",
29+
"webOS",
30+
"Bada",
31+
"Kindle",
32+
"Maemo"
33+
};
34+
35+
private static readonly HashSet<string> s_MobileBrowsers = new HashSet<string>
36+
{
37+
"Android",
38+
"Firefox Mobile",
39+
"Opera Mobile",
40+
"Opera Mini",
41+
"Mobile Safari",
42+
"Amazon Silk",
43+
"webOS Browser",
44+
"MicroB",
45+
"Ovi Browser",
46+
"NetFront",
47+
"NetFront NX",
48+
"Chrome Mobile",
49+
"Chrome Mobile iOS",
50+
"UC Browser",
51+
"Tizen Browser",
52+
"Baidu Explorer",
53+
"QQ Browser Mini",
54+
"QQ Browser Mobile",
55+
"IE Mobile",
56+
"Polaris",
57+
"ONE Browser",
58+
"iBrowser Mini",
59+
"Nokia Services (WAP) Browser",
60+
"Nokia Browser",
61+
"Nokia OSS Browser",
62+
"BlackBerry WebKit",
63+
"BlackBerry", "Palm",
64+
"Palm Blazer",
65+
"Palm Pre",
66+
"Teleca Browser",
67+
"SEMC-Browser",
68+
"PlayStation Portable",
69+
"Nokia",
70+
"Maemo Browser",
71+
"Obigo",
72+
"Bolt",
73+
"Iris",
74+
"UP.Browser",
75+
"Minimo",
76+
"Bunjaloo",
77+
"Jasmine",
78+
"Dolfin",
79+
"Polaris",
80+
"Skyfire"
81+
};
82+
83+
private static readonly HashSet<string> s_MobileDevices = new HashSet<string>
84+
{
85+
"BlackBerry",
86+
"MI PAD",
87+
"iPhone",
88+
"iPad",
89+
"iPod",
90+
"Kindle",
91+
"Kindle Fire",
92+
"Nokia",
93+
"Lumia",
94+
"Palm",
95+
"DoCoMo",
96+
"HP TouchPad",
97+
"Xoom",
98+
"Motorola",
99+
"Generic Feature Phone",
100+
"Generic Smartphone"
101+
};
102+
103+
#endregion
104+
13105
private readonly HttpContextBase _httpContext;
14106

107+
private string _rawValue;
15108
private UserAgentInfo _userAgent;
16109
private DeviceInfo _device;
17110
private OSInfo _os;
18111

112+
private bool? _isBot;
113+
private bool? _isMobileDevice;
114+
private bool? _isTablet;
115+
private bool? _isPdfConverter;
116+
19117
static UAParserUserAgent()
20118
{
21119
s_uap = uap.Parser.GetDefault();
@@ -25,61 +123,131 @@ public UAParserUserAgent(HttpContextBase httpContext)
25123
{
26124
this._httpContext = httpContext;
27125
}
28-
29-
public UserAgentInfo UserAgent
126+
127+
public string RawValue
128+
{
129+
get
130+
{
131+
if (_rawValue == null)
132+
{
133+
if (_httpContext.Request != null)
134+
{
135+
_rawValue = _httpContext.Request.UserAgent.EmptyNull();
136+
}
137+
else
138+
{
139+
_rawValue = "";
140+
}
141+
}
142+
143+
return _rawValue;
144+
}
145+
// for (unit) test purpose
146+
set
147+
{
148+
_rawValue = value;
149+
_userAgent = null;
150+
_device = null;
151+
_os = null;
152+
_isBot = null;
153+
_isMobileDevice = null;
154+
_isTablet = null;
155+
_isPdfConverter = null;
156+
}
157+
}
158+
159+
public virtual UserAgentInfo UserAgent
30160
{
31161
get
32162
{
33163
if (_userAgent == null)
34164
{
35-
var tmp = s_uap.ParseUserAgent(GetUaString());
165+
var tmp = s_uap.ParseUserAgent(this.RawValue);
36166
_userAgent = new UserAgentInfo(tmp.Family, tmp.Major, tmp.Minor, tmp.Patch);
37167
}
38168
return _userAgent;
39169
}
40170
}
41171

42-
public DeviceInfo Device
172+
public virtual DeviceInfo Device
43173
{
44174
get
45175
{
46176
if (_device == null)
47177
{
48-
var uaString = GetUaString();
49-
var tmp = s_uap.ParseDevice(uaString);
50-
var isPdfConverter = false;
51-
if (tmp.Family.IsCaseInsensitiveEqual("Other"))
52-
{
53-
isPdfConverter = s_pdfConverterPattern.IsMatch(uaString);
54-
}
55-
_device = new DeviceInfo(tmp.Family, tmp.IsSpider, isPdfConverter);
178+
var tmp = s_uap.ParseDevice(this.RawValue);
179+
_device = new DeviceInfo(tmp.Family, tmp.IsSpider);
56180
}
57181
return _device;
58182
}
59183
}
60184

61-
public OSInfo OS
185+
public virtual OSInfo OS
62186
{
63187
get
64188
{
65189
if (_os == null)
66190
{
67-
var tmp = s_uap.ParseOS(GetUaString());
191+
var tmp = s_uap.ParseOS(this.RawValue);
68192
_os = new OSInfo(tmp.Family, tmp.Major, tmp.Minor, tmp.Patch, tmp.PatchMinor);
69193
}
70194
return _os;
71195
}
72196
}
73197

74-
private string GetUaString()
198+
public virtual bool IsBot
75199
{
76-
if (_httpContext.Request != null)
200+
get
77201
{
78-
return _httpContext.Request.UserAgent.EmptyNull();
202+
if (!_isBot.HasValue)
203+
{
204+
_isBot = _httpContext.Request.Browser.Crawler || this.Device.IsBot;
205+
}
206+
return _isBot.Value;
79207
}
208+
}
80209

81-
return "";
210+
public virtual bool IsMobileDevice
211+
{
212+
get
213+
{
214+
if (!_isMobileDevice.HasValue)
215+
{
216+
_isMobileDevice =
217+
s_MobileOS.Contains(this.OS.Family) ||
218+
s_MobileBrowsers.Contains(this.UserAgent.Family) ||
219+
s_MobileDevices.Contains(this.Device.Family);
220+
}
221+
return _isMobileDevice.Value;
222+
}
82223
}
224+
225+
public virtual bool IsTablet
226+
{
227+
get
228+
{
229+
if (!_isTablet.HasValue)
230+
{
231+
_isTablet =
232+
Regex.IsMatch(this.Device.Family, "iPad|Kindle Fire|Nexus 10|Xoom|Transformer|MI PAD|IdeaTab", RegexOptions.CultureInvariant) ||
233+
this.OS.Family == "BlackBerry Tablet OS";
234+
}
235+
return _isTablet.Value;
236+
}
237+
}
238+
239+
public virtual bool IsPdfConverter
240+
{
241+
get
242+
{
243+
if (!_isPdfConverter.HasValue)
244+
{
245+
_isPdfConverter = s_pdfConverterPattern.IsMatch(this.RawValue);
246+
}
247+
return _isPdfConverter.Value;
248+
}
249+
}
250+
83251
}
84252

85253
}

src/Presentation/SmartStore.Web.Framework/WebWorkContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public Customer CurrentCustomer
141141
// in this case return built-in customer record for search engines
142142
if (customer == null || customer.Deleted || !customer.Active)
143143
{
144-
if (_userAgent.Device.IsBot)
144+
if (_userAgent.IsBot)
145145
{
146146
customer = _customerService.GetCustomerBySystemName(SystemCustomerNames.SearchEngine);
147147
}
@@ -151,7 +151,7 @@ public Customer CurrentCustomer
151151
// in this case return built-in customer record for the converter
152152
if (customer == null || customer.Deleted || !customer.Active)
153153
{
154-
if (_userAgent.Device.IsPdfConverter)
154+
if (_userAgent.IsPdfConverter)
155155
{
156156
customer = _customerService.GetCustomerBySystemName(SystemCustomerNames.PdfConverter);
157157
}

0 commit comments

Comments
 (0)