【问题标题】:Retrieve User-Agent programmatically以编程方式检索用户代理
【发布时间】:2011-04-07 06:22:50
【问题描述】:

有没有办法在没有WebView 的活动中检索浏览器的用户代理?

我知道可以通过WebView获得它:

WebView view = (WebView) findViewById(R.id.someview);
String ua = view.getSettings().getUserAgentString() ;

但在我的情况下,我没有/不需要 webview 对象,我不想仅仅为了检索用户代理字符串而创建它。

【问题讨论】:

    标签: android webview android-webview user-agent


    【解决方案1】:

    如果你没有一个,你可以试试这样

    String ua=new WebView(this).getSettings().getUserAgentString();
    

    编辑-

    getUserAgentString() 的文档说

    返回 WebView 的用户代理字符串

    所以我不认为你可以得到它,除非你声明一个。如果我错了,有人纠正我

    【讨论】:

    • 谢谢,它有效。在不创建对象的情况下绕过它会很好,但似乎不太可能......
    • 注意Webview在某些设备上不可用,那么这个方法会抛出异常。
    【解决方案2】:

    我曾经使用 DeRagan 提出的solution。但事实证明,创建单个WebView 实例会启动一个线程“WebViewCoreThread”,该线程会一直保持在后台,直到应用程序被系统终止。也许它不会消耗太多资源,但我还是不喜欢它。所以我现在使用稍微不同的方法,它试图避免创建 WebViewCoreThread:

    // You may uncomment next line if using Android Annotations library, otherwise just be sure to run it in on the UI thread
    // @UiThread 
    public static String getDefaultUserAgentString(Context context) {
      if (Build.VERSION.SDK_INT >= 17) {
        return NewApiWrapper.getDefaultUserAgent(context);
      }
    
      try {
        Constructor<WebSettings> constructor = WebSettings.class.getDeclaredConstructor(Context.class, WebView.class);
        constructor.setAccessible(true);
        try {
          WebSettings settings = constructor.newInstance(context, null);
          return settings.getUserAgentString();
        } finally {
          constructor.setAccessible(false);
        }
      } catch (Exception e) {
        return new WebView(context).getSettings().getUserAgentString();
      }
    }
    
    @TargetApi(17)
    static class NewApiWrapper {
      static String getDefaultUserAgent(Context context) {
        return WebSettings.getDefaultUserAgent(context);
      }
    }
    

    它直接使用包可见的构造函数创建 WebSettings 实例,如果由于某种原因(例如由于未来 Android 版本中的 API 更改)不可用 - 默默地退回到“类似 WebView”的解决方案。

    更新

    正如@Skywalker5446 所指出的,从Android 4.2/API 17 开始,有一个公共静态方法来获取默认的用户代理值。我已更新我的代码以在受支持的平台上使用该方法。

    【讨论】:

    • 这个方法在 Android 4.2 上会失败,WebSettings 现在是抽象的,虽然有一个WebSettingsClassic,调用私有 API 总是不是一个优雅的方式,它只会在未来失败,你可以不升级就修复它。
    • 在 Android 4.2/API 17 中,有一个公共静态方法可以获取此值:WebSettings.getDefaultUserAgent(Context),因此您也可以在此技巧中添加对该 API 级别的检查。
    • @Skywalker5446 感谢您提供有用的信息,我会相应地更新我的答案。
    • WebSettings 即使在 4.1.1 上也是抽象的。
    • 使用 WebSettings.class.getDeclaredConstructor(Context.class, WebView.class) 我现在收到 lint 警告“Cannot resolve constructor with specified argument types
    【解决方案3】:

    感谢 Idolon 的回答,我的应用可以在后台处理此问题。

    但不知何故,在运行 2.3.3 的 AT&T 的 HTC Inspire 4G 上,它进入了 catch 语句,并且不能再在后台线程上运行。 我的解决方案如下:

    public static String getUserAgent(Context context) {
        try {
            Constructor<WebSettings> constructor = WebSettings.class.getDeclaredConstructor(Context.class, WebView.class);
            constructor.setAccessible(true);
            try {
                WebSettings settings = constructor.newInstance(context, null);
                return settings.getUserAgentString();
            } finally {
                constructor.setAccessible(false);
            }
        } catch (Exception e) {
            String ua;
            if(Thread.currentThread().getName().equalsIgnoreCase("main")){
                WebView m_webview = new WebView(context);
                ua = m_webview.getSettings().getUserAgentString();
            }else{
                mContext = context;
                ((Activity) mContext).runOnUiThread(new Runnable() {
    
                    @Override
                    public void run() {
                        WebView webview = new WebView(mContext);
                        mUserAgent = webview.getSettings().getUserAgentString();
                    }
    
                });
                return mUserAgent;
            }
            return ua;
        }
    }
    

    (假设字段中有 mContext 和 mUserAgent)

    【讨论】:

    • 您可能想要quit() Looper 和join() 线程,或者使用wait()notify()/notifyAll() 以便保证修改mUserAgent。目前,该方法可能在子线程更新 mUserAgent 之前返回。
    【解决方案4】:

    如果您使用的是 Android 2.1 或更高版本,则有一种更简单的方法。当然,这与 webview 将返回的用户代理字符串不完全相同,但可能会为您提供足够好的服务。

    作为从 Web 视图拉取的额外优势,您可以从任何线程(不仅仅是 UI 线程)使用它。

    有一个名为 http.agent 的系统属性,可用于检索 User-Agent 字符串。

    String userAgent = System.getProperty("http.agent");
    

    更多详情请见Programmatically get User-Agent String

    【讨论】:

    • 这不是浏览器的用户代理,这是要求的。不过,它适用于多种用途。
    • 这是 User-Agent 字符串,WebView 将使用它来标识自己到 WebView 中当前加载页面的主机。以防万一您需要通过 HTTP 传输连接到任何远程主机,这是将您自己标识为 Android WebView 的最优雅的方式。
    • 非常好的呼叫解决方案,即改造/okhttp。我刚刚在 Android 6 和 Android 9 上尝试过。你得到的是像 Dalvik/2.1.0(Linux;U;Android 9;SM-G398FN Build/PPR1.180610.011)这样的 UserAgent
    【解决方案5】:

    从 Android 2.1 开始,您应该使用 System.getProperty("http.agent");

    您也不需要先创建 WebView AND ,这就是优势, 您可以在非 uithread 中使用它。

    你好,史蒂夫

    【讨论】:

    • 这不是问题的答案。这给了设备的用户 ganet,而不是 webview 的。
    【解决方案6】:

    这是一个基于先前答案的更新解决方案,在您为 KitKat 编译时有效。现在WebSettings 类是抽象的,WebSettingsClassic 类已被删除。

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public static String getUserAgent(final Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return WebSettings.getDefaultUserAgent(context);
        }
        else {
            try {
                final Class<?> webSettingsClassicClass = Class.forName("android.webkit.WebSettingsClassic");
                final Constructor<?> constructor = webSettingsClassicClass.getDeclaredConstructor(Context.class, Class.forName("android.webkit.WebViewClassic"));
                constructor.setAccessible(true);
                final Method method = webSettingsClassicClass.getMethod("getUserAgentString");
                return (String) method.invoke(constructor.newInstance(context, null));
            }
            catch (final Exception e) {
                return new WebView(context).getSettings()
                        .getUserAgentString();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-04
      • 1970-01-01
      • 1970-01-01
      • 2010-10-25
      • 2012-01-30
      • 2014-02-07
      • 1970-01-01
      相关资源
      最近更新 更多