java 从用户代理字符串检测移动设备

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15346006/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 19:18:34  来源:igfitidea点击:

Detect mobile devices from user agent string

javauser-agent

提问by Aniket Schneider

I am looking for a way to analyze user agent strings to determine whether they were generated by mobile devices. This needs to be java-based and usable in large batch log file analysis on hadoop for generating statistics (i.e., a web service wouldn't be appropriate).

我正在寻找一种方法来分析用户代理字符串以确定它们是否由移动设备生成。这需要基于 Java 并且可用于 hadoop 上的大型批处理日志文件分析以生成统计信息(即,Web 服务不合适)。

I have seen WURFL, but given that I just need a binary mobile/not mobile response, the license fee seems prohibitive.

我见过WURFL,但鉴于我只需要一个二进制移动/非移动响应,许可费似乎令人望而却步。

So far I have been using UADetector, which is almost exactly what I need. However, I have encountered some limitations with it. In my testing, I have found many user agent strings that provide enough information to determine that the user agent is from a mobile device, but are reported as UNKNOWN by UADetector.

到目前为止,我一直在使用UADetector,这几乎正是我所需要的。但是,我遇到了一些限制。在我的测试中,我发现许多用户代理字符串提供了足够的信息来确定用户代理来自移动设备,但被 UADetector 报告为 UNKNOWN。

For example, poorly-standardized Android apps can send the UA string "Android". This is enough to know that it came from a mobile device, but UADetector reports this UserAgentType as UNKNOWN rather than MOBILE_BROWSER.

例如,标准化不佳的 Android 应用程序可能会发送 UA 字符串“Android”。这足以知道它来自移动设备,但 UADetector 将此 UserAgentType 报告为 UNKNOWN 而不是 MOBILE_BROWSER。

Apache Mobile Filter's Lite Device Detectiondoes the right thing, but I need something I can use from Java.

Apache Mobile FilterLite Device Detection做正确的事情,但我需要一些可以从 Java 中使用的东西。

Can anyone recommend a better solution?

谁能推荐一个更好的解决方案?

回答by Anthony Hand

I'm the founder and maintainer of the MobileESP project, a free open source cross-platform library for detecting mobile devices. It's still very much alive! :-)

我是 MobileESP 项目的创始人和维护者,这是一个用于检测移动设备的免费开源跨平台库。它仍然非常活跃!:-)

www.mobileesp.org

www.mobileesp.org

MobileESP onlygives binary "is mobile" responses. You can detect by platform like iOS, Android or Windows Phone, or by device category, like "iPhone Tier" smartphones vs. tablet. Be sure to take a quick review of the API page.

MobileESP给出二进制的“是移动的”响应。您可以按 iOS、Android 或 Windows Phone 等平台或设备类别(例如“iPhone Tier”智能手机与平板电脑)进行检测。请务必快速查看 API 页面。

As you may know, useragent strings vary widely. If the browser shipped on the device, the manufacturer may customize it. For example, HTC often customizes the native Android browser's useragent string.

您可能知道,用户代理字符串变化很大。如果浏览器随设备一起提供,制造商可能会对其进行自定义。例如,HTC 经常自定义原生 Android 浏览器的用户代理字符串。

Google provides recommendations on how the OEM should customize the useragent. If the device should be considered a phone, then Google recommends including the word "mobile" element in the string. But if the device should be considered a tablet, then the string should notcontain "mobile." Adherence to this recommendation varies widely, of course.

Google 提供了有关 OEM 应如何自定义用户代理的建议。如果该设备应被视为手机,则 Google 建议在字符串中包含单词“mobile”元素。但是,如果该设备应被认为是平板电脑,则该字符串应该包含“移动”。当然,对这项建议的遵守程度差异很大。

Third party browsers like Opera or Maxthon can put whatever they want to in the useragent string -- and do! Certain "new" browsers which shall remain nameless have been doing very poor jobs of putting the correct information in their useragent strings for each platform (e.g., Android vs. iOS versions). There's not much you can do unless you get a lot of traffic from these browsers and wish to invest in tracking their exact useragent values per platform and software rev.

像 Opera 或 Maxthon 这样的第三方浏览器可以在用户代理字符串中放入他们想要的任何内容——并且这样做!某些将保持匿名的“新”浏览器在为每个平台(例如,Android 与 iOS 版本)将正确信息放入其用户代理字符串方面做得非常差。除非您从这些浏览器获得大量流量并希望投资跟踪每个平台和软件版本的确切用户代理值,否则您无能为力。

Anyway, MobileESP was created with the vision of doing the detection on a page-by-page basis when the page is served. I purposefully wrote the code to be very easy to read and customize, too.

无论如何,创建 MobileESP 的愿景是在提供页面时逐页进行检测。我也特意编写了易于阅读和自定义的代码。

To do the batch processing, you might do something like this:

要进行批处理,您可能会执行以下操作:

1.) In the constructor, comment out the initDeviceScan() method. You won't need this for bulk processing.

1.) 在构造函数中,注释掉 initDeviceScan() 方法。批量处理不需要这个。

2.) Pass the UserAgent and an empty string in to the constructor (UAgentInfo()).

2.) 将 UserAgent 和一个空字符串传递给构造函数 (UAgentInfo())。

3.) Then run whatever detect methods you're interested in. Be thoughtful about the order in which you do them to save time, based on a scan of your users.

3.) 然后运行您感兴趣的任何检测方法。根据对用户的扫描,考虑执行它们的顺序以节省时间。

For example, if most of your users are on iPhone and that's one of the detection criteria you're interested in, then run that check first. If this example, you certainly wouldn't run the BlackBerry method first!

例如,如果您的大多数用户都使用 iPhone,并且这是您感兴趣的检测标准之一,那么请先运行该检查。如果是这个例子,你肯定不会先运行黑莓方法!

My contact info is in the source code and on the web site. Send me a note if you have any questions or run into any bugs. Definitely look around the MobileESP.org web site for some tips.

我的联系信息在源代码和网站上。如果您有任何问题或遇到任何错误,请给我留言。请务必浏览 MobileESP.org 网站以获取一些提示。

Best wishes on your project, Aniket!

Aniket,祝您项目顺利!

  • Anthony
  • 安东尼

回答by Mladen Adamovic

Another thread suggests using the following library:

另一个线程建议使用以下库:

https://github.com/ahand/mobileesp/blob/master/Java/UAgentInfo.java

https://github.com/ahand/mobileesp/blob/master/Java/UAgentInfo.java

which seems OK.

这似乎没问题。

回答by Zarwalski

51Degrees has a free open source Java API that allows you to run offline processing. You can access it from the GitHub Repository here. https://github.com/51Degrees/Java-Device-Detection.

51Degrees 有一个免费的开源 Java API,允许您运行离线处理。您可以从此处的 GitHub 存储库访问它。https://github.com/51Degrees/Java-Device-Detection

As part of the API there is an offline processing example (code also shown below) this takes a CSV file of User-Agents and returns the required properties into an Output file. The following example just uses 3 of the properties within the data set, for a full list you can look at the dictionary here https://51degrees.com/resources/property-dictionary

作为 API 的一部分,有一个离线处理示例(代码也在下面显示),它采用用户代理的 CSV 文件并将所需的属性返回到输出文件中。以下示例仅使用数据集中的 3 个属性,有关完整列表,您可以在此处查看字典https://51degrees.com/resources/property-dictionary

// output file in current working directory
public String outputFilePath = "batch-processing-example-results.csv";
// pattern detection matching provider
private final Provider provider;

/**
 * Initialises the device detection Provider with the included Lite data
 * file. For more data see: 
 * <a href="https://51degrees.com/compare-data-options">compare data options
 * </a>
 * 
 * @throws IOException if there was a problem reading from the data file.
 */
public OfflineProcessingExample() throws IOException {
    provider = new Provider(StreamFactory.create(
            Shared.getLitePatternV32(), false));
 }

/**
 * Reads a CSV file containing User-Agents and adds the IsMobile, 
 * PlatformName and PlatformVersion information for the first 20 lines.
 * For a full list of properties and the files they are available in please 
 * see: <a href="https://51degrees.com/resources/property-dictionary">
 * Property Dictionary</a>
 * 
 * @param inputFileName the CSV file to read from.
 * @param outputFilename where to save the file with extra entries.
 * @throws IOException if there was a problem reading from the data file.
 */
public void processCsv(String inputFileName, String outputFilename) 
        throws IOException {
    BufferedReader bufferedReader = 
            new BufferedReader(new FileReader(inputFileName));
    try {
        FileWriter fileWriter = new FileWriter(outputFilename);
        try {
            // it's more efficient over the long haul to create a match 
            // once and reuse it in multiple matches
            Match match = provider.createMatch();
            // there are 20k lines in supplied file, we'll just do a couple 
            // of them!
            for (int i = 0; i < 20; i++) {

                // read next line
                String userAgentString = bufferedReader.readLine();

                // ask the provider to match the UA using match we created
                provider.match(userAgentString, match);

                // get some property values from the match
                Values isMobile = match.getValues("IsMobile");
                Values platformName = match.getValues("PlatformName");
                Values platformVersion = match.getValues("PlatformVersion");

                // write result to file
                fileWriter.append("\"")
                        .append(userAgentString)
                        .append("\", ")
                        .append(getValueForDisplay(isMobile))
                        .append(", ")
                        .append(getValueForDisplay(platformName))
                        .append(", ")
                        .append(getValueForDisplay(platformVersion))
                        .append('\n')
                        .flush();
            }
        } finally {
            fileWriter.close();
        }
    } finally {
        bufferedReader.close();
    }
}

/**
 * Match values may be null. A helper method to get something displayable
 * @param values a Values to render
 * @return a non-null String
 */
protected String getValueForDisplay(Values values) {
    return values == null ? "N/A": values.toString();
} 

/**
 * Closes the {@link fiftyone.mobile.detection.Dataset} by releasing data 
 * file readers and freeing the data file from locks. This method should 
 * only be used when the {@code Dataset} is no longer required, i.e. when 
 * device detection functionality is no longer required, or the data file 
 * needs to be freed.
 * 
 * @throws IOException if there was a problem accessing the data file.
 */
@Override
public void close() throws IOException {
    provider.dataSet.close();
}

/**
 * Instantiates this class and starts 
 * {@link #processCsv(java.lang.String, java.lang.String)} with default 
 * parameters.
 * 
 * @param args command line arguments.
 * @throws IOException if there was a problem accessing the data file.
 */
public static void main(String[] args) throws IOException {
    System.out.println("Starting Offline Processing Example");
    OfflineProcessingExample offlineProcessingExample = 
            new OfflineProcessingExample();
    try {
        offlineProcessingExample.processCsv(Shared.getGoodUserAgentsFile(), 
                offlineProcessingExample.outputFilePath);
        System.out.println("Output written to " + 
                offlineProcessingExample.outputFilePath);
    } finally {
        offlineProcessingExample.close();
    }
}

Hope this helps.

希望这可以帮助。

Disclosure: I work at 51Degrees.

披露:我在 51Degrees 工作。

回答by user2163103

How to read the Apache Mobile Filter value in JSP (for Tomcat)?

如何读取 JSP 中的 Apache Mobile Filter 值(对于 Tomcat)?

Before in the httpd.conf file where you have to configure mod_jk you muse add this:

在必须配置 mod_jk 的 httpd.conf 文件之前,您必须添加以下内容:

JkEnvVar AMF_IS_MOBILE undefined

The Java code is:

Java代码是:

request.getAttribute("AMF_IS_MOBILE")

from: http://wiki.apachemobilefilter.org

来自:http: //wiki.apachemobilefilter.org

回答by Abdullah Khan

To detect iPhone, Android and other mobile devices in Javauser-agentcan be used. If you are using Spring you can customize the below code as per your need.

Javauser-agent可用于检测 iPhone、Android 和其他移动设备。如果您使用的是 Spring,您可以根据需要自定义以下代码。

@Override
public ModelAndView redirectToAppstore(HttpServletRequest request) {
    String userAgent = request.getHeader("user-agent").toLowerCase();
    String iphoneStoreUrl = "IPONE_STORE_URL";
    String androidStoreUrl = "ANDROID_STORE_URL";
    if (userAgent.contains("iphone"))
        return new ModelAndView("redirect:" + iphoneStoreUrl);
    else if (userAgent.contains("android"))
        return new ModelAndView("redirect:" + androidStoreUrl);

    return new ModelAndView("redirect:/");
}