2010-09-02 6 views
28

Czy istnieje sposób na odzyskanie przeglądarki użytkownika przeglądarki bez wykonywania czynności w trybie WebView?Programowo pobierać program User-Agent

wiem, że to jest możliwe, aby uzyskać ją poprzez WebView:

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

Ale w moim przypadku nie mam/potrzebujemy obiektu Webview i nie chcę, aby go utworzyć tylko do pobierania przez użytkownika ciąg agenta.

Odpowiedz

41

Jeśli nie mieć można spróbować biorąc go jak ten

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

Edycja-

Doc dla getUserAgentString() mówi

zwróci Webview za agenta użytkownika łańcuch.

Więc nie sądzę, że możesz to dostać, chyba że je zadeklarujesz. Ktoś poprawi mnie, jeśli się mylę.

+1

Dzięki, to działa. Byłoby miło obejść go bez tworzenia obiektu, ale wygląda na to, że nie jest to możliwe ... – Laimoncijus

32

Użyłem użyć solution zaproponowanego przez DeRagan. Okazało się jednak, że utworzenie pojedynczej instancji WebView powoduje uruchomienie wątku "WebViewCoreThread", który pozostaje w tle do momentu zakończenia aplikacji przez system. Może nie zużywa zbyt wiele zasobów, ale i tak mi się to nie podoba. Więc używam nieco inną metodę teraz, który stara się uniknąć tworzenia 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); 
    } 
} 

tworzy WebSettings instancji bezpośrednio za pomocą konstruktora pakiet widoczne, a jeśli to nie jest dostępne dla jakiegoś powodu (np z powodu zmian API w przyszłości Androida wersje) - po cichu wraca do rozwiązania "podobnego do WebView".

UPDATE

Jak wskazano przez @Skywalker5446, począwszy od Androida 4.2/17 API, jest publiczna metoda statyczna, aby uzyskać wartość domyślna agenta użytkownika. Zaktualizowałem swój kod, aby korzystać z tej metody na obsługiwanych platformach.

+1

Ta metoda zakończy się niepowodzeniem na Androidzie 4.2, "WebSettings" jest teraz abstrakcyjne, chociaż istnieje 'WebSettingsClassic', nazywając prywatne API jest zawsze nie jest to elegancki sposób, po prostu zawiedzie w przyszłości i nie można go naprawić bez aktualizacji. – neevek

+1

W systemie Android 4.2/API 17 istnieje publiczna metoda statyczna pozwalająca uzyskać tę wartość: WebSettings.getDefaultUserAgent (Kontekst), więc można dodać do tego testu także sprawdzanie poziomu interfejsu API. –

+0

@ Skywalker5446 Dzięki za przydatne informacje, zaktualizuję odpowiednio odpowiedź. – Idolon

1

Dzięki odpowiedzi Idolona moja aplikacja może przetworzyć to w tle.

Ale jakoś na HTC Inspire 4G z AT & T, która działa 2.3.3, przechodzi do instrukcji catch i nie może być już uruchomiona na wątku tła. Moje rozwiązanie tego problemu jest następujące:

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; 
    } 
} 

(załóżmy, że masz mContext i mUserAgent w tej dziedzinie)

+0

Prawdopodobnie chcesz albo "zakończyć()' Looper i 'join()' wątek lub użyć 'wait()' i 'notify()'/'notifyAll()', aby zagwarantować, że mUserAgent będzie modyfikowany. Obecnie metoda może powrócić, zanim wątek potomny zaktualizuje mUserAgent. – yingted

+0

Hi. Zmieniłem część, którą wskazałeś. –

41

Jest znacznie prostszy sposób, jeśli jesteś na Androida 2.1 lub wyższej. To prawda, że ​​nie jest to dokładnie ten sam ciąg agenta użytkownika, który powróciłby, ale może Ci służyć wystarczająco dobrze dla twoich celów.

Dodatkową zaletą przeciągania z widoku sieciowego jest to, że można go użyć z dowolnego wątku (nie tylko z wątku interfejsu użytkownika).

Istnieje właściwość systemowa o nazwie http.agent, której można użyć do pobrania ciągu User-Agent.

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

Aby uzyskać więcej informacji, patrz Programmatically get User-Agent String.

+6

To nie jest agent użytkownika przeglądarki, o to właśnie pytano. Działa to jednak dobrze dla wielu celów. – lilbyrdie

+0

To jest ciąg ** użytkownika-agenta **, którego WebView użyje do samostanowienia ** do hosta ** bieżącej załadowanej strony w WebView. Na wypadek, gdybyś musiał połączyć się przez HTTP Transport do dowolnego zdalnego hosta, to jest najbardziej elegancka metoda identyfikacji siebie jako Android WebView. –

10

Od Androida 2.1 należy używać System.getProperty ("http.agent");

Nie musisz też najpierw tworzyć WebView ORAZ, to jest ta zaleta, możesz go używać w trybie nieodczytanym.

pozdrowienia steve

+3

To nie jest odpowiedź na pytanie. Daje to ganet użytkownika urządzenia, a nie widok sieciowy. – trante

1

Jest to zaktualizowana rozwiązanie oparte na wcześniejszych odpowiedzi, które działa po kompilacji dla KitKat. Teraz klasa WebSettings jest abstrakcyjna, a klasa WebSettingsClassic została usunięta.

@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(); 
     } 
    } 
}