Skip to content

Commit c1898b4

Browse files
authored
feat: Use userAgentData in favour of userAgent (#7979)
1 parent 1da9a76 commit c1898b4

File tree

3 files changed

+142
-263
lines changed

3 files changed

+142
-263
lines changed

src/js/tech/html5.js

+3-38
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ class Html5 extends Tech {
105105
// Our goal should be to get the custom controls on mobile solid everywhere
106106
// so we can remove this all together. Right now this will block custom
107107
// controls on touch enabled laptops like the Chrome Pixel
108-
if ((browser.TOUCH_ENABLED || browser.IS_IPHONE ||
109-
browser.IS_NATIVE_ANDROID) && options.nativeControlsForTouch === true) {
108+
if ((browser.TOUCH_ENABLED || browser.IS_IPHONE) && options.nativeControlsForTouch === true) {
110109
this.setControls(true);
111110
}
112111

@@ -675,10 +674,8 @@ class Html5 extends Tech {
675674
*/
676675
supportsFullScreen() {
677676
if (typeof this.el_.webkitEnterFullScreen === 'function') {
678-
const userAgent = window.navigator && window.navigator.userAgent || '';
679-
680-
// Seems to be broken in Chromium/Chrome && Safari in Leopard
681-
if ((/Android/).test(userAgent) || !(/Chrome|Mac OS X 10.5/).test(userAgent)) {
677+
// Still needed?
678+
if (browser.IS_ANDROID) {
682679
return true;
683680
}
684681
}
@@ -1330,38 +1327,6 @@ Html5.prototype.featuresTimeupdateEvents = true;
13301327
*/
13311328
Html5.prototype.featuresVideoFrameCallback = !!(Html5.TEST_VID && Html5.TEST_VID.requestVideoFrameCallback);
13321329

1333-
// HTML5 Feature detection and Device Fixes --------------------------------- //
1334-
let canPlayType;
1335-
1336-
Html5.patchCanPlayType = function() {
1337-
1338-
// Android 4.0 and above can play HLS to some extent but it reports being unable to do so
1339-
// Firefox and Chrome report correctly
1340-
if (browser.ANDROID_VERSION >= 4.0 && !browser.IS_FIREFOX && !browser.IS_CHROME) {
1341-
canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType;
1342-
Html5.TEST_VID.constructor.prototype.canPlayType = function(type) {
1343-
const mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i;
1344-
1345-
if (type && mpegurlRE.test(type)) {
1346-
return 'maybe';
1347-
}
1348-
return canPlayType.call(this, type);
1349-
};
1350-
}
1351-
};
1352-
1353-
Html5.unpatchCanPlayType = function() {
1354-
const r = Html5.TEST_VID.constructor.prototype.canPlayType;
1355-
1356-
if (canPlayType) {
1357-
Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType;
1358-
}
1359-
return r;
1360-
};
1361-
1362-
// by default, patch the media element
1363-
Html5.patchCanPlayType();
1364-
13651330
Html5.disposeMediaElement = function(el) {
13661331
if (!el) {
13671332
return;

src/js/utils/browser.js

+139-90
Original file line numberDiff line numberDiff line change
@@ -5,196 +5,245 @@
55
import * as Dom from './dom';
66
import window from 'global/window';
77

8-
const USER_AGENT = window.navigator && window.navigator.userAgent || '';
9-
const webkitVersionMap = (/AppleWebKit\/([\d.]+)/i).exec(USER_AGENT);
10-
const appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null;
11-
128
/**
139
* Whether or not this device is an iPod.
1410
*
1511
* @static
16-
* @const
1712
* @type {Boolean}
1813
*/
19-
export const IS_IPOD = (/iPod/i).test(USER_AGENT);
14+
export let IS_IPOD = false;
2015

2116
/**
2217
* The detected iOS version - or `null`.
2318
*
2419
* @static
25-
* @const
2620
* @type {string|null}
2721
*/
28-
export const IOS_VERSION = (function() {
29-
const match = USER_AGENT.match(/OS (\d+)_/i);
30-
31-
if (match && match[1]) {
32-
return match[1];
33-
}
34-
return null;
35-
}());
22+
export let IOS_VERSION = null;
3623

3724
/**
3825
* Whether or not this is an Android device.
3926
*
4027
* @static
41-
* @const
4228
* @type {Boolean}
4329
*/
44-
export const IS_ANDROID = (/Android/i).test(USER_AGENT);
30+
export let IS_ANDROID = false;
4531

4632
/**
47-
* The detected Android version - or `null`.
33+
* The detected Android version - or `null` if not Android or indeterminable.
4834
*
4935
* @static
50-
* @const
5136
* @type {number|string|null}
5237
*/
53-
export const ANDROID_VERSION = (function() {
54-
// This matches Android Major.Minor.Patch versions
55-
// ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
56-
const match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
57-
58-
if (!match) {
59-
return null;
60-
}
61-
62-
const major = match[1] && parseFloat(match[1]);
63-
const minor = match[2] && parseFloat(match[2]);
64-
65-
if (major && minor) {
66-
return parseFloat(match[1] + '.' + match[2]);
67-
} else if (major) {
68-
return major;
69-
}
70-
return null;
71-
}());
38+
export let ANDROID_VERSION;
7239

7340
/**
74-
* Whether or not this is a native Android browser.
41+
* Whether or not this is Mozilla Firefox.
7542
*
7643
* @static
77-
* @const
7844
* @type {Boolean}
7945
*/
80-
export const IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537;
46+
export let IS_FIREFOX = false;
8147

8248
/**
83-
* Whether or not this is Mozilla Firefox.
49+
* Whether or not this is Microsoft Edge.
8450
*
8551
* @static
86-
* @const
8752
* @type {Boolean}
8853
*/
89-
export const IS_FIREFOX = (/Firefox/i).test(USER_AGENT);
54+
export let IS_EDGE = false;
9055

9156
/**
92-
* Whether or not this is Microsoft Edge.
57+
* Whether or not this is any Chromium Browser
9358
*
9459
* @static
95-
* @const
9660
* @type {Boolean}
9761
*/
98-
export const IS_EDGE = (/Edg/i).test(USER_AGENT);
62+
export let IS_CHROMIUM = false;
9963

10064
/**
101-
* Whether or not this is Google Chrome.
65+
* Whether or not this is any Chromium browser that is not Edge.
10266
*
10367
* This will also be `true` for Chrome on iOS, which will have different support
10468
* as it is actually Safari under the hood.
10569
*
70+
* Depreacted, as the behaviour to not match Edge was to prevent Legacy Edge's UA matching.
71+
* IS_CHROMIUM should be used instead.
72+
* "Chromium but not Edge" could be explicitly tested with IS_CHROMIUM && !IS_EDGE
73+
*
10674
* @static
107-
* @const
75+
* @deprecated
10876
* @type {Boolean}
10977
*/
110-
export const IS_CHROME = !IS_EDGE && ((/Chrome/i).test(USER_AGENT) || (/CriOS/i).test(USER_AGENT));
78+
export let IS_CHROME = false;
11179

11280
/**
113-
* The detected Google Chrome version - or `null`.
81+
* The detected Chromium version - or `null`.
11482
*
11583
* @static
116-
* @const
11784
* @type {number|null}
11885
*/
119-
export const CHROME_VERSION = (function() {
120-
const match = USER_AGENT.match(/(Chrome|CriOS)\/(\d+)/);
86+
export let CHROMIUM_VERSION = null;
12187

122-
if (match && match[2]) {
123-
return parseFloat(match[2]);
124-
}
125-
return null;
126-
}());
88+
/**
89+
* The detected Google Chrome version - or `null`.
90+
* This has always been the _Chromium_ version, i.e. would return on Chromium Edge.
91+
* Depreacted, use CHROMIUM_VERSION instead.
92+
*
93+
* @static
94+
* @deprecated
95+
* @type {number|null}
96+
*/
97+
export let CHROME_VERSION = null;
12798

12899
/**
129100
* The detected Internet Explorer version - or `null`.
130101
*
131102
* @static
132-
* @const
103+
* @deprecated
133104
* @type {number|null}
134105
*/
135-
export const IE_VERSION = (function() {
136-
const result = (/MSIE\s(\d+)\.\d/).exec(USER_AGENT);
137-
let version = result && parseFloat(result[1]);
138-
139-
if (!version && (/Trident\/7.0/i).test(USER_AGENT) && (/rv:11.0/).test(USER_AGENT)) {
140-
// IE 11 has a different user agent string than other IE versions
141-
version = 11.0;
142-
}
143-
144-
return version;
145-
}());
106+
export let IE_VERSION = null;
146107

147108
/**
148109
* Whether or not this is desktop Safari.
149110
*
150111
* @static
151-
* @const
152112
* @type {Boolean}
153113
*/
154-
export const IS_SAFARI = (/Safari/i).test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
114+
export let IS_SAFARI = false;
155115

156116
/**
157117
* Whether or not this is a Windows machine.
158118
*
159119
* @static
160-
* @const
161120
* @type {Boolean}
162121
*/
163-
export const IS_WINDOWS = (/Windows/i).test(USER_AGENT);
122+
export let IS_WINDOWS = false;
164123

165124
/**
166-
* Whether or not this device is touch-enabled.
125+
* Whether or not this device is an iPad.
167126
*
168127
* @static
169-
* @const
170128
* @type {Boolean}
171129
*/
172-
export const TOUCH_ENABLED = Boolean(Dom.isReal() && (
173-
'ontouchstart' in window ||
174-
window.navigator.maxTouchPoints ||
175-
window.DocumentTouch && window.document instanceof window.DocumentTouch));
130+
export let IS_IPAD = false;
176131

177132
/**
178-
* Whether or not this device is an iPad.
133+
* Whether or not this device is an iPhone.
179134
*
180135
* @static
181-
* @const
182136
* @type {Boolean}
183137
*/
184-
export const IS_IPAD = (/iPad/i).test(USER_AGENT) ||
185-
(IS_SAFARI && TOUCH_ENABLED && !(/iPhone/i).test(USER_AGENT));
138+
// The Facebook app's UIWebView identifies as both an iPhone and iPad, so
139+
// to identify iPhones, we need to exclude iPads.
140+
// http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/
141+
export let IS_IPHONE = false;
186142

187143
/**
188-
* Whether or not this device is an iPhone.
144+
* Whether or not this device is touch-enabled.
189145
*
190146
* @static
191147
* @const
192148
* @type {Boolean}
193149
*/
194-
// The Facebook app's UIWebView identifies as both an iPhone and iPad, so
195-
// to identify iPhones, we need to exclude iPads.
196-
// http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/
197-
export const IS_IPHONE = (/iPhone/i).test(USER_AGENT) && !IS_IPAD;
150+
export const TOUCH_ENABLED = Boolean(Dom.isReal() && (
151+
'ontouchstart' in window ||
152+
window.navigator.maxTouchPoints ||
153+
window.DocumentTouch && window.document instanceof window.DocumentTouch));
154+
155+
const UAD = window.navigator && window.navigator.userAgentData;
156+
157+
if (UAD) {
158+
// If userAgentData is present, use it instead of userAgent to avoid warnings
159+
// Currently only implemented on Chromium
160+
// userAgentData does not expose Android version, so ANDROID_VERSION remains `null`
161+
162+
IS_ANDROID = UAD.platform === 'Android';
163+
IS_EDGE = Boolean(UAD.brands.find(b => b.brand === 'Microsoft Edge'));
164+
IS_CHROMIUM = Boolean(UAD.brands.find(b => b.brand === 'Chromium'));
165+
IS_CHROME = !IS_EDGE && IS_CHROMIUM;
166+
CHROMIUM_VERSION = CHROME_VERSION = (UAD.brands.find(b => b.brand === 'Chromium') || {}).version || null;
167+
IS_WINDOWS = UAD.platform === 'Windows';
168+
}
169+
170+
// If the broser is not Chromium, either userAgentData is not present which could be an old Chromium browser,
171+
// or it's a browser that has added userAgentData since that we don't have tests for yet. In either case,
172+
// the checks need to be made agiainst the regular userAgent string.
173+
if (!IS_CHROMIUM) {
174+
const USER_AGENT = window.navigator && window.navigator.userAgent || '';
175+
176+
IS_IPOD = (/iPod/i).test(USER_AGENT);
177+
178+
IOS_VERSION = (function() {
179+
const match = USER_AGENT.match(/OS (\d+)_/i);
180+
181+
if (match && match[1]) {
182+
return match[1];
183+
}
184+
return null;
185+
}());
186+
187+
IS_ANDROID = (/Android/i).test(USER_AGENT);
188+
189+
ANDROID_VERSION = (function() {
190+
// This matches Android Major.Minor.Patch versions
191+
// ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
192+
const match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
193+
194+
if (!match) {
195+
return null;
196+
}
197+
198+
const major = match[1] && parseFloat(match[1]);
199+
const minor = match[2] && parseFloat(match[2]);
200+
201+
if (major && minor) {
202+
return parseFloat(match[1] + '.' + match[2]);
203+
} else if (major) {
204+
return major;
205+
}
206+
return null;
207+
}());
208+
209+
IS_FIREFOX = (/Firefox/i).test(USER_AGENT);
210+
211+
IS_EDGE = (/Edg/i).test(USER_AGENT);
212+
213+
IS_CHROMIUM = ((/Chrome/i).test(USER_AGENT) || (/CriOS/i).test(USER_AGENT));
214+
215+
IS_CHROME = !IS_EDGE && IS_CHROMIUM;
216+
217+
CHROMIUM_VERSION = CHROME_VERSION = (function() {
218+
const match = USER_AGENT.match(/(Chrome|CriOS)\/(\d+)/);
219+
220+
if (match && match[2]) {
221+
return parseFloat(match[2]);
222+
}
223+
return null;
224+
}());
225+
226+
IE_VERSION = (function() {
227+
const result = (/MSIE\s(\d+)\.\d/).exec(USER_AGENT);
228+
let version = result && parseFloat(result[1]);
229+
230+
if (!version && (/Trident\/7.0/i).test(USER_AGENT) && (/rv:11.0/).test(USER_AGENT)) {
231+
// IE 11 has a different user agent string than other IE versions
232+
version = 11.0;
233+
}
234+
235+
return version;
236+
}());
237+
238+
IS_SAFARI = (/Safari/i).test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
239+
240+
IS_WINDOWS = (/Windows/i).test(USER_AGENT);
241+
242+
IS_IPAD = (/iPad/i).test(USER_AGENT) ||
243+
(IS_SAFARI && TOUCH_ENABLED && !(/iPhone/i).test(USER_AGENT));
244+
245+
IS_IPHONE = (/iPhone/i).test(USER_AGENT) && !IS_IPAD;
246+
}
198247

199248
/**
200249
* Whether or not this is an iOS device.

0 commit comments

Comments
 (0)