All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.apkcloud.devicedetector.parser.OperatingSystem Maven / Gradle / Ivy

Go to download

通用设备检测库将解析任何UserAgent并检测浏览器、操作系统、使用的设备(桌面、平板、移动、电视、车载、游戏机等等)、品牌和型号。

There is a newer version: 1.0.7
Show newest version
package io.github.apkcloud.devicedetector.parser;

import io.github.apkcloud.devicedetector.entity.OS;

import java.util.*;

/**
 * 解析 UserAgent 以获取操作系统信息。
 * 

* 检测到的操作系统可以在 {@link #operatingSystems} 和 resources/regexes/oss.yml 中找到。 *

* 此类还定义了一些操作系统家族和获取具体操作系统家族的方法。 */ public class OperatingSystem extends AbstractParser { protected String fixtureFile = "regexes/oss.yml"; protected String parserName = "os"; /** * 已知的操作系统映射到其内部短代码 */ protected static Map operatingSystems = new HashMap() { { put("AIX", "AIX"); put("AND", "Android"); put("ADR", "Android TV"); put("AMZ", "Amazon Linux"); put("AMG", "AmigaOS"); put("ATV", "tvOS"); put("ARL", "Arch Linux"); put("BTR", "BackTrack"); put("SBA", "Bada"); put("BEO", "BeOS"); put("BLB", "BlackBerry OS"); put("QNX", "BlackBerry Tablet OS"); put("BOS", "Bliss OS"); put("BMP", "Brew"); put("CAI", "Caixa Mágica"); put("CES", "CentOS"); put("CST", "CentOS Stream"); put("CLR", "ClearOS Mobile"); put("COS", "Chrome OS"); put("CRS", "Chromium OS"); put("CHN", "China OS"); put("CYN", "CyanogenMod"); put("DEB", "Debian"); put("DEE", "Deepin"); put("DFB", "DragonFly"); put("DVK", "DVKBuntu"); put("FED", "Fedora"); put("FEN", "Fenix"); put("FOS", "Firefox OS"); put("FIR", "Fire OS"); put("FOR", "Foresight Linux"); put("FRE", "Freebox"); put("BSD", "FreeBSD"); put("FYD", "FydeOS"); put("FUC", "Fuchsia"); put("GNT", "Gentoo"); put("GRI", "GridOS"); put("GTV", "Google TV"); put("HPX", "HP-UX"); put("HAI", "Haiku OS"); put("IPA", "iPadOS"); put("HAR", "HarmonyOS"); put("HAS", "HasCodingOS"); put("IRI", "IRIX"); put("INF", "Inferno"); put("JME", "Java ME"); put("KOS", "KaiOS"); put("KAN", "Kanotix"); put("KNO", "Knoppix"); put("KTV", "KreaTV"); put("KBT", "Kubuntu"); put("LIN", "GNU/Linux"); put("LND", "LindowsOS"); put("LNS", "Linspire"); put("LEN", "Lineage OS"); put("LBT", "Lubuntu"); put("LOS", "Lumin OS"); put("VLN", "VectorLinux"); put("MAC", "Mac"); put("MAE", "Maemo"); put("MAG", "Mageia"); put("MDR", "Mandriva"); put("SMG", "MeeGo"); put("MCD", "MocorDroid"); put("MON", "moonOS"); put("MIN", "Mint"); put("MLD", "MildWild"); put("MOR", "MorphOS"); put("NBS", "NetBSD"); put("MTK", "MTK / Nucleus"); put("MRE", "MRE"); put("WII", "Nintendo"); put("NDS", "Nintendo Mobile"); put("NOV", "Nova"); put("OS2", "OS/2"); put("T64", "OSF1"); put("OBS", "OpenBSD"); put("OWR", "OpenWrt"); put("OTV", "Opera TV"); put("ORD", "Ordissimo"); put("PAR", "Pardus"); put("PCL", "PCLinuxOS"); put("PLA", "Plasma Mobile"); put("PSP", "PlayStation Portable"); put("PS3", "PlayStation"); put("PUR", "PureOS"); put("RHT", "Red Hat"); put("RED", "RedOS"); put("REV", "Revenge OS"); put("ROS", "RISC OS"); put("ROK", "Roku OS"); put("RSO", "Rosa"); put("ROU", "RouterOS"); put("REM", "Remix OS"); put("RRS", "Resurrection Remix OS"); put("REX", "REX"); put("RZD", "RazoDroiD"); put("SAB", "Sabayon"); put("SSE", "SUSE"); put("SAF", "Sailfish OS"); put("SEE", "SeewoOS"); put("SIR", "Sirin OS"); put("SLW", "Slackware"); put("SOS", "Solaris"); put("SYL", "Syllable"); put("SYM", "Symbian"); put("SYS", "Symbian OS"); put("S40", "Symbian OS Series 40"); put("S60", "Symbian OS Series 60"); put("SY3", "Symbian^3"); put("TEN", "TencentOS"); put("TDX", "ThreadX"); put("TIZ", "Tizen"); put("TOS", "TmaxOS"); put("UBT", "Ubuntu"); put("WAS", "watchOS"); put("WTV", "WebTV"); put("WHS", "Whale OS"); put("WIN", "Windows"); put("WCE", "Windows CE"); put("WIO", "Windows IoT"); put("WMO", "Windows Mobile"); put("WPH", "Windows Phone"); put("WRT", "Windows RT"); put("XBX", "Xbox"); put("XBT", "Xubuntu"); put("YNS", "YunOS"); put("ZEN", "Zenwalk"); put("ZOR", "ZorinOS"); put("IOS", "iOS"); put("POS", "palmOS"); put("WOS", "webOS"); } }; /** * 操作系统家族映射到相关操作系统的短代码 */ protected static Map> osFamilies = new HashMap<>() { { put("Android", Arrays.asList("AND", "CYN", "FIR", "REM", "RZD", "MLD", "MCD", "YNS", "GRI", "HAR", "ADR", "CLR", "BOS", "REV", "LEN", "SIR", "RRS")); put("AmigaOS", Arrays.asList("AMG", "MOR")); put("BlackBerry", Arrays.asList("BLB", "QNX")); put("Brew", Arrays.asList("BMP")); put("BeOS", Arrays.asList("BEO", "HAI")); put("Chrome OS", Arrays.asList("COS", "CRS", "FYD", "SEE")); put("Firefox OS", Arrays.asList("FOS", "KOS")); put("Gaming Console", Arrays.asList("WII", "PS3")); put("Google TV", Arrays.asList("GTV")); put("IBM", Arrays.asList("OS2")); put("iOS", Arrays.asList("IOS", "ATV", "WAS", "IPA")); put("RISC OS", Arrays.asList("ROS")); put("GNU/Linux", Arrays.asList( "LIN", "ARL", "DEB", "KNO", "MIN", "UBT", "KBT", "XBT", "LBT", "FED", "RHT", "VLN", "MDR", "GNT", "SAB", "SLW", "SSE", "CES", "BTR", "SAF", "ORD", "TOS", "RSO", "DEE", "FRE", "MAG", "FEN", "CAI", "PCL", "HAS", "LOS", "DVK", "ROK", "OWR", "OTV", "KTV", "PUR", "PLA", "FUC", "PAR", "FOR", "MON", "KAN", "ZEN", "LND", "LNS", "CHN", "AMZ", "TEN", "CST", "NOV", "ROU", "ZOR", "RED" ) ); put("Mac", Arrays.asList("MAC")); put("Mobile Gaming Console", Arrays.asList("PSP", "NDS", "XBX")); put("Real-time OS", Arrays.asList("MTK", "TDX", "MRE", "JME", "REX")); put("Other Mobile", Arrays.asList("WOS", "POS", "SBA", "TIZ", "SMG", "MAE")); put("Symbian", Arrays.asList("SYM", "SYS", "SY3", "S60", "S40")); put("Unix", Arrays.asList("SOS", "AIX", "HPX", "BSD", "NBS", "OBS", "DFB", "SYL", "IRI", "T64", "INF")); put("WebTV", Arrays.asList("WTV")); put("Windows", Arrays.asList("WIN")); put("Windows Mobile", Arrays.asList("WPH", "WMO", "WCE", "WRT", "WIO")); put("Other Smart TV", Arrays.asList("WHS")); } }; /** * 包含从我们使用的操作系统名称到已知 ClientHints 值的映射列表 */ protected static Map> clientHintMapping = new HashMap<>() { { put("GNU/Linux", Arrays.asList("Linux")); put("Mac", Arrays.asList("MacOS")); } }; /** * 已知仅适用于桌面的操作系统家族 */ protected static List desktopOsArray = Arrays.asList("AmigaOS", "IBM", "GNU/Linux", "Mac", "Unix", "Windows", "BeOS", "Chrome OS", "Chromium OS"); /** * 返回所有可用的操作系统 */ public static Map getAvailableOperatingSystems() { return operatingSystems; } /** * 返回所有可用的操作系统家族 */ public static Map> getAvailableOperatingSystemFamilies() { return osFamilies; } /** * 返回操作系统的名称和短代码 * * @param name 操作系统的名称 * @return {@code Map} */ public static Map getShortOsData(String name) { String shortName = "UNK"; for (Map.Entry os : operatingSystems.entrySet()) { if (!os.getValue().equalsIgnoreCase(name)) { continue; } name = os.getValue(); shortName = os.getKey(); break; } return Map.of("short", shortName, "name", name); } /** * {@inheritDoc} */ public Map parse() throws Exception { Map osFromClientHints = parseOsFromClientHints(); Map osFromUserAgent = parseOsFromUserAgent(); String name; String version; String shortName; if (!isNullOrEmpty(osFromClientHints.get("name"))) { name = osFromClientHints.get("name"); version = osFromClientHints.get("version"); // 如果 ClientHints 中未提供,但 UserAgent 中的操作系统家族匹配,则使用 UserAgent 中的 version if (isNullOrEmpty(version) && Objects.equals(getOsFamily(name), getOsFamily(osFromUserAgent.get("name")))) { version = osFromUserAgent.get("version"); } // 如果从 ClientHints 检测到的操作系统名称与 UserAgent 中的操作系统家族匹配 // 但操作系统名称不同,我们使用 UserAgent 中的一个,因为它可能更详细 if (Objects.equals(getOsFamily(osFromUserAgent.get("name")), name) && !(osFromUserAgent.get("name").equals(name))) { name = osFromUserAgent.get("name"); if ("HarmonyOS".equals(name)) { version = ""; } } shortName = osFromClientHints.get("short_name"); // Chrome OS 在某些情况下被报告为 Linux,只有当版本号匹配时我们才修复此问题 if ("GNU/Linux".equals(name) && "Chrome OS".equals(osFromUserAgent.get("name")) && osFromClientHints.get("version").equals(osFromUserAgent.get("version"))) { name = osFromUserAgent.get("name"); shortName = osFromUserAgent.get("short_name"); } } else if (!isNullOrEmpty(osFromUserAgent.get("name"))) { name = osFromUserAgent.get("name"); version = osFromUserAgent.get("version"); shortName = osFromUserAgent.get("short_name"); } else { return new HashMap<>(); } String platform = parsePlatform(); String family = getOsFamily(shortName); String[] androidApps = new String[]{"com.hisense.odinbrowser", "com.seraphic.openinet.pre", "com.appssppa.idesktoppcbrowser"}; if (clientHints != null) { if (Arrays.asList(androidApps).contains(clientHints.getApp()) && !"Android".equals(name)) { name = "Android"; family = "Android"; shortName = "ADR"; version = ""; } } Map osInfo = new HashMap<>(); osInfo.put("name", name); osInfo.put("short_name", shortName); osInfo.put("version", version); osInfo.put("platform", platform); osInfo.put("family", family); if (operatingSystems.containsValue(osInfo.get("name"))) { osInfo.put("short_name", getKeyByValue(operatingSystems, osInfo.get("name"))); } return osInfo; } @Override public String getName() { return parserName; } /** * 返回指定操作系统的操作系统家族 * * @param osLabel 名称或短代码 * @return String|null If null, "Unknown" */ public static String getOsFamily(String osLabel) { if (operatingSystems.containsValue(osLabel)) { osLabel = getKeyByValue(operatingSystems, osLabel); } for (Map.Entry> entry : osFamilies.entrySet()) { List list = entry.getValue(); if (list.contains(osLabel)) { return entry.getKey(); } } return null; } /** * 如果操作系统是桌面,则返回 true * * @param osName 操作系统短代码 * @return boolean */ public static boolean isDesktopOs(String osName) { String osFamily = getOsFamily(osName); return desktopOsArray.contains(osFamily); } /** * 返回指定简称的全名 * * @param os * @param ver * @return String | null */ public static String getNameFromId(String os, String ver) { if (operatingSystems.containsKey(os)) { String osFullName = operatingSystems.get(os); return (osFullName + " " + ver).trim(); } return null; } /** * 返回从 ClientHints 中安全检测到的操作系统 * * @return {@code Map} */ protected Map parseOsFromClientHints() { String name = ""; String version = ""; String shortName = ""; if (clientHints != null && !isNullOrEmpty(clientHints.getOperatingSystem())) { String hintName = applyClientHintMapping(clientHints.getOperatingSystem(), clientHintMapping); for (Map.Entry entry : operatingSystems.entrySet()) { if (fuzzyCompare(hintName, entry.getValue())) { name = entry.getValue(); shortName = entry.getKey(); break; } } version = clientHints.getOperatingSystemVersion(); if ("Windows".equals(name)) { int majorVersion = Integer.parseInt(version.split("\\.", 2).length > 0 ? version.split("\\.", 1)[0] : "0"); if (majorVersion > 0 && majorVersion < 11) { version = "10"; } else if (majorVersion > 10) { version = "11"; } } if (Integer.parseInt(version) == 0) { version = ""; } } Map osInfo = new HashMap<>(); osInfo.put("name", name); osInfo.put("short_name", shortName); osInfo.put("version", buildVersion(version, new ArrayList<>())); return osInfo; } /** * 返回从 UserAgent 检测到的操作系统 * * @return {@code Map} * @throws Exception */ protected Map parseOsFromUserAgent() throws Exception { OS osRegex = null; List matcher = null; String name = "", version = "", shortName = ""; List regexes = getRegexes(fixtureFile, OS.class); for (OS regex : regexes) { matcher = matchUserAgent(regex.getRegex()); osRegex = regex; if (!isNullOrEmpty(matcher)) { break; } } if (!isNullOrEmpty(matcher)) { name = buildByMatch(osRegex.getName(), matcher); Map shortOsData = getShortOsData(name); name = shortOsData.get("name"); shortName = shortOsData.get("short"); version = osRegex.getVersion() != null ? buildVersion(osRegex.getVersion(), matcher) : ""; List> versions = osRegex.getVersions() != null ? osRegex.getVersions() : new ArrayList<>(); for (Map regex : versions) { matcher = matchUserAgent(regex.get("regex")); if (isNullOrEmpty(matcher)) { continue; } if (regex.containsKey("name")) { name = buildByMatch(regex.get("name"), matcher); shortOsData = getShortOsData(name); name = shortOsData.get("name"); shortName = shortOsData.get("short"); } if (regex.containsKey("version")) { version = buildVersion(regex.get("version"), matcher); } break; } } Map osInfo = new HashMap<>(); osInfo.put("name", name); osInfo.put("short_name", shortName); osInfo.put("version", version); return osInfo; } /** * 解析当前 UserAgent 字符串的操作系统平台 * * @return String */ protected String parsePlatform() throws Exception { // 如果有客户端提示,使用其中的架构信息 if (clientHints != null && !isNullOrEmpty(clientHints.getArchitecture())) { String arch = clientHints.getArchitecture().toLowerCase(); if (arch.contains("arm")) { return "ARM"; } if (arch.contains("mips")) { return "MIPS"; } if (arch.contains("sh4")) { return "SuperH"; } if (arch.contains("x64") || (arch.contains("x86") && "64".equals(clientHints.getBitness()))) { return "x64"; } if (arch.contains("x86")) { return "x86"; } } if (!isNullOrEmpty(matchUserAgent("arm|aarch64|Apple ?TV|Watch ?OS|Watch1,[12]"))) { return "ARM"; } if (!isNullOrEmpty(matchUserAgent("mips"))) { return "MIPS"; } if (!isNullOrEmpty(matchUserAgent("sh4"))) { return "SuperH"; } if (!isNullOrEmpty(matchUserAgent("64-?bit|WOW64|(?:Intel)?x64|WINDOWS_64|win64|amd64|x86_?64"))) { return "x64"; } if (!isNullOrEmpty(matchUserAgent(".+32bit|.+win32|(?:i[0-9]|x)86|i86pc"))) { return "x86"; } return ""; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy