Skip to content

Commit

Permalink
feat(device): add browser/webview version to getInfo() (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasvidas authored Dec 17, 2020
1 parent 911ae71 commit 48c49c1
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 6 deletions.
7 changes: 4 additions & 3 deletions device/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ Get the device's current language locale code.

#### DeviceInfo

| Prop | Type | Description | Since |
| --------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
| Prop | Type | Description | Since |
| --------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
| **`name`** | <code>string</code> | The name of the device. For example, "John's iPhone". This is only supported on iOS and Android 7.1 or above. | 1.0.0 |
| **`model`** | <code>string</code> | The device model. For example, "iPhone". | 1.0.0 |
| **`platform`** | <code>'ios' \| 'android' \| 'web'</code> | The device platform (lowercase). | 1.0.0 |
Expand All @@ -86,7 +86,8 @@ Get the device's current language locale code.
| **`isVirtual`** | <code>boolean</code> | Whether the app is running in a simulator/emulator. | 1.0.0 |
| **`memUsed`** | <code>number</code> | Approximate memory used by the current app, in bytes. Divide by 1048576 to get the number of MBs used. | 1.0.0 |
| **`diskFree`** | <code>number</code> | How much free disk space is available on the the normal data storage. path for the os, in bytes | 1.0.0 |
| **`diskTotal`** | <code>number</code> | The total size of the normal data storage path for the OS, in bytes. | 1.0.0 |
| **`diskTotal`** | <code>number</code> | The total size of the normal data storage path for the OS, in bytes. | 1.0.0 |
| **`webViewVersion`** | <code>string</code> | The web view browser version | 1.0.0 |


#### DeviceBatteryInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.provider.Settings;
import android.webkit.WebView;

public class Device {

Expand Down Expand Up @@ -78,4 +81,27 @@ public String getName() {

return null;
}

public String getWebViewVersion() {
PackageInfo info = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
info = WebView.getCurrentWebViewPackage();
} else {
String webViewPackage = "com.google.android.webview";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
webViewPackage = "com.android.chrome";
}
PackageManager pm = this.context.getPackageManager();
try {
info = pm.getPackageInfo(webViewPackage, 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
if (info != null) {
return info.versionName;
}

return android.os.Build.VERSION.RELEASE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public void getInfo(PluginCall call) {
r.put("uuid", implementation.getUuid());
r.put("isVirtual", implementation.isVirtual());
r.put("name", implementation.getName());
r.put("webViewVersion", implementation.getWebViewVersion());

call.resolve(r);
}
Expand Down
3 changes: 2 additions & 1 deletion device/ios/Plugin/DevicePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public class DevicePlugin: CAPPlugin {
"platform": "ios",
"manufacturer": "Apple",
"uuid": UIDevice.current.identifierForVendor!.uuidString,
"isVirtual": isSimulator
"isVirtual": isSimulator,
"webViewVersion": UIDevice.current.systemVersion
])
}

Expand Down
8 changes: 6 additions & 2 deletions device/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
"native"
],
"scripts": {
"test": "uvu -r esm -r ts-node/register src/__tests__",
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..",
"verify:android": "cd android && ./gradlew clean build test && cd ..",
"verify:web": "npm run build",
"verify:web": "npm run build && npm test",
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- autocorrect --format",
"eslint": "eslint . --ext ts",
Expand All @@ -51,12 +52,15 @@
"@ionic/prettier-config": "~1.0.1",
"@ionic/swiftlint-config": "^1.1.2",
"eslint": "^7.11.0",
"esm": "^3.2.25",
"prettier": "~2.2.0",
"prettier-plugin-java": "~1.0.0",
"rimraf": "^3.0.0",
"rollup": "^2.29.0",
"swiftlint": "^1.0.1",
"typescript": "~4.0.3"
"ts-node": "^9.1.1",
"typescript": "~4.0.3",
"uvu": "^0.5.1"
},
"peerDependencies": {
"@capacitor/core": "^3.0.0-alpha.9"
Expand Down
115 changes: 115 additions & 0 deletions device/src/__tests__/useragent.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import type { WebPluginConfig } from '@capacitor/core';
import { test } from 'uvu';
import * as assert from 'uvu/assert';

import { DeviceWeb } from '../web';

const config: WebPluginConfig = { name: 'DevicePlugin' };
const web = new DeviceWeb(config);

test('Chrome', () => {
// Mock empty navigator/window objects
(global as any).navigator = {};
(global as any).window = { chrome: true };

const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', // Chrome 87 on Windows
'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', // Chrome 87 MacOS
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', // Chrome 87 on Linux
'Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.86 Mobile Safari/537.36', // Chrome 87 Android
'Mozilla/5.0 (Linux; Android 10; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.86 Mobile Safari/537.36', // Chrome 87 on Android (Samsung)
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/87.0.4280.77 Mobile/15E148 Safari/604.1', // "ChromeRevision" 87 on iPhone
];

const expected = [
'87.0.4280.88',
'87.0.4280.88',
'87.0.4280.88',
'87.0.4280.86',
'87.0.4280.86',
'87.0.4280.77',
];

for (const [index, ua] of userAgents.entries()) {
const parsed = web.parseUa(ua);
const actual = parsed.browserVersion;
assert.is(actual, expected[index]);
}
});

test('Firefox', () => {
(global as any).navigator = {};
(global as any).window = { InstallTrigger: true };
const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0', // Firefox 83 on Windows
'Mozilla/5.0 (Macintosh; Intel Mac OS X 11.0; rv:83.0) Gecko/20100101 Firefox/83.0', // Firefox 83 on MacOS
'Mozilla/5.0 (X11; Linux i686; rv:83.0) Gecko/20100101 Firefox/83.0', // Firefox 83 on Linux
'Mozilla/5.0 (Android 11; Mobile; rv:68.0) Gecko/68.0 Firefox/83.0', // Firefox 83 on Android
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/29.0 Mobile/15E148 Safari/605.1.15', // Firefox Mobile 29 on iPhone
];

const expected = ['83.0', '83.0', '83.0', '83.0', '29.0'];

for (const [index, ua] of userAgents.entries()) {
const parsed = web.parseUa(ua);
const actual = parsed.browserVersion;
assert.is(actual, expected[index]);
}
});

test('Safari', () => {
(global as any).navigator = {};
(global as any).window = { ApplePaySession: true };
const userAgents = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.1 Safari/605.1.15', // Safari 14 on MacOS
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', // Safari 14 on iPhone
];

const expected = ['14.0.1', '14.0'];

for (const [index, ua] of userAgents.entries()) {
const parsed = web.parseUa(ua);
const actual = parsed.browserVersion;
assert.is(actual, expected[index]);
}
});

test('Edge', () => {
// this is true on early chromium edge, and false for older and latest versions. It should pass for both true or false
(global as any).window = { chrome: true };
(global as any).navigator = {};

const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763', // Edge 18 on Windows 10
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134', // Edge 17 on Windows 10
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 Edg/85.0.564.63', // Edge 85 on Windows 10
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.57', // Edge 87 on Windows 10
'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.57', // Edge 87 on MacOS
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 EdgiOS/45.11.1 Mobile/15E148 Safari/605.1.15', // Edge 45 on iOS
];

const expected = [
'18.17763',
'17.17134',
'85.0.564.63',
'87.0.664.57',
'87.0.664.57',
'45.11.1',
];

for (const [index, ua] of userAgents.entries()) {
const parsed = web.parseUa(ua);
const actual = parsed.browserVersion;
assert.is(actual, expected[index]);
}

(global as any).window = { chrome: false };
(global as any).navigator = {};
for (const [index, ua] of userAgents.entries()) {
const parsed = web.parseUa(ua);
const actual = parsed.browserVersion;
assert.is(actual, expected[index]);
}
});

test.run();
7 changes: 7 additions & 0 deletions device/src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ export interface DeviceInfo {
* @since 1.0.0
*/
diskTotal?: number;

/**
* The web view browser version
*
* @since 1.0.0
*/
webViewVersion: string;
}

export interface DeviceBatteryInfo {
Expand Down
55 changes: 55 additions & 0 deletions device/src/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ declare global {
getBattery: any;
oscpu: any;
}

interface Window {
InstallTrigger?: any;
ApplePaySession?: any;
chrome?: any;
}
}

export class DeviceWeb extends WebPlugin implements DevicePlugin {
Expand All @@ -31,6 +37,7 @@ export class DeviceWeb extends WebPlugin implements DevicePlugin {
manufacturer: navigator.vendor,
isVirtual: false,
uuid: this.getUid(),
webViewVersion: uaFields.browserVersion,
};
}

Expand Down Expand Up @@ -106,6 +113,54 @@ export class DeviceWeb extends WebPlugin implements DevicePlugin {
uaFields.operatingSystem = 'unknown';
}

// Check for browsers based on non-standard javascript apis, only not user agent
const isFirefox = !!window.InstallTrigger;
const isSafari = !!window.ApplePaySession;
const isChrome = !!window.chrome;
const isEdge = /Edg/.test(ua);
const isFirefoxIOS = /FxiOS/.test(ua);
const isChromeIOS = /CriOS/.test(ua);
const isEdgeIOS = /EdgiOS/.test(ua);

// FF and Edge User Agents both end with "/MAJOR.MINOR"
if (
isSafari ||
(isChrome && !isEdge) ||
isFirefoxIOS ||
isChromeIOS ||
isEdgeIOS
) {
// Safari version comes as "... Version/MAJOR.MINOR ..."
// Chrome version comes as "... Chrome/MAJOR.MINOR ..."
// FirefoxIOS version comes as "... FxiOS/MAJOR.MINOR ..."
// ChromeIOS version comes as "... CriOS/MAJOR.MINOR ..."
let searchWord: string;
if (isFirefoxIOS) {
searchWord = 'FxiOS';
} else if (isChromeIOS) {
searchWord = 'CriOS';
} else if (isEdgeIOS) {
searchWord = 'EdgiOS';
} else if (isSafari) {
searchWord = 'Version';
} else {
searchWord = 'Chrome';
}

const words = ua.split(' ');
for (const word of words) {
if (word.includes(searchWord)) {
const version = word.split('/')[1];
uaFields.browserVersion = version;
}
}
} else if (isFirefox || isEdge) {
const reverseUA = ua.split('').reverse().join('');
const reverseVersion = reverseUA.split('/')[0];
const version = reverseVersion.split('').reverse().join('');
uaFields.browserVersion = version;
}

return uaFields;
}

Expand Down

0 comments on commit 48c49c1

Please sign in to comment.