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

Java 从用户代理字符串检测移动设备,java,user-agent,Java,User Agent,我正在寻找一种方法来分析用户代理字符串,以确定它们是否由移动设备生成。这需要基于java,并可用于hadoop上的大批量日志文件分析,以生成统计数据(即,web服务不合适) 我看到了,但考虑到我只需要一个二进制移动/非移动响应,许可费似乎太高了 到目前为止,我一直在使用,这几乎正是我所需要的。然而,我遇到了一些限制。在我的测试中,我发现了许多用户代理字符串,这些字符串提供了足够的信息来确定用户代理来自移动设备,但被UADetector报告为未知 例如,标准化较差的Android应用程序可以发送U

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

我看到了,但考虑到我只需要一个二进制移动/非移动响应,许可费似乎太高了

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

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

's做了正确的事情,但我需要一些可以从Java中使用的东西


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

如何读取JSP中的Apache Mobile筛选器值(对于Tomcat)

在必须配置mod_jk的httpd.conf文件中添加以下内容:

JkEnvVar AMF_IS_MOBILE undefined
Java代码是:

request.getAttribute("AMF_IS_MOBILE")

from:

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


这似乎没问题。

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

MobileESP只提供二进制“是移动的”响应。您可以通过iOS、Android或Windows Phone等平台进行检测,也可以通过“iPhone层”智能手机和平板电脑等设备类别进行检测。确保快速查看API页面

您可能知道,useragent字符串变化很大。如果设备上附带了浏览器,制造商可以对其进行自定义。例如,HTC经常定制本机Android浏览器的useragent字符串

谷歌提供了OEM如何定制useragent的建议。如果该设备应被视为手机,那么谷歌建议在字符串中包含单词“mobile”元素。但如果该设备应被视为平板电脑,则字符串不应包含“移动”。当然,遵守这一建议的情况差异很大

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

不管怎样,MobileESP的创建是为了在服务页面时逐页进行检测。我特意编写的代码也很容易阅读和定制

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

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

2.)将UserAgent和空字符串传入构造函数(UAgentInfo())

3.)然后运行您感兴趣的任何检测方法。根据对用户的扫描,仔细考虑您为节省时间而执行这些操作的顺序

例如,如果您的大多数用户都在iPhone上,并且这是您感兴趣的检测标准之一,那么首先运行该检查。如果是这个示例,您肯定不会首先运行BlackBerry方法

我的联系信息在源代码和网站上。如果您有任何问题或遇到任何bug,请给我发一张便条。一定要在MobileESP.org网站上查找一些提示

祝你的项目顺利,安妮特

  • 安东尼

可以使用
Java
用户代理检测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:/");
}

51Degrees有一个免费的开源Java API,允许您运行脱机处理。您可以从GitHub存储库访问它

作为API的一部分,有一个脱机处理示例(代码如下所示),它获取用户代理的CSV文件,并将所需属性返回到输出文件中。下面的示例仅使用数据集中的3个属性,有关完整列表,您可以在此处查看字典

//当前工作目录中的输出文件
公共字符串outputFilePath=“批处理示例结果.csv”;
//模式检测匹配提供程序
私人最终提供者;
/**
*使用包含的Lite数据初始化设备检测提供程序
*文件。有关更多数据,请参阅:
* 
* 
*@如果读取数据文件时出现问题,则引发IOException。
*/
public OfflineProcessingExample()引发IOException{
提供程序=新提供程序(StreamFactory.create(
getLitePatternV32(),false));
}
/**
*读取包含用户代理的CSV文件并添加IsMobile,
*前20行的PlatformName和PlatformVersion信息。
*有关属性及其可用文件的完整列表,请
*见:
* 
*@param inputFileName要从中读取的CSV文件。
*@param outputFilename保存带有额外条目的文件的位置。
*@如果读取数据文件时出现问题,则引发IOException。
*/
public void processCsv(字符串输入文件名、字符串输出文件名)
抛出IOException{
BufferedReader BufferedReader=
新的BufferedReader(新的文件读取器(inputFileName));
试一试{
FileWriter FileWriter=新的FileWriter(outputFilename);
试一试{
//从长远来看,创建匹配更有效
//一次并多次重复使用
// 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();
    }
}