Android | 在运行时获取OkHTTP库的版本

7
最近我分析了我的应用程序的崩溃报告,并发现几个堆栈跟踪指向okhttp
我的应用程序没有明确依赖于okhttp
据我所知,okhttp版本取决于Android操作系统版本,并且okhttp库本身放置在设备上。
为了帮助故障排除,我决定记录okhttp库版本,并找到了一些有用的类。
  1. com.squareup.okhttp.internal.Version
  2. okhttp3.internal.Version
只是为了确保我没有犯错,我从堆栈跟踪中获取了com.android.okhttp.internal.http.HttpURLConnectionImpl类并尝试了Class.forName - 成功。
我还注意到,在构建时,com.squareup.okhttp被转换为com.android.okhttp,因此我尝试了这些变体。
  1. Class.forName("com.android.okhttp.internal.Version") -> java.lang.ClassNotFoundException
  2. Class.forName("com.squareup.okhttp.internal.Version") -> java.lang.ClassNotFoundException
  3. Class.forName("okhttp3.internal.Version") -> java.lang.ClassNotFoundException
  4. Class.forName("com.android.okhttp.internal.http.HttpURLConnectionImpl") -> 成功
有人能解释一下为什么吗?我错过了什么?
更新
我从我的设备中提取了okhttp.jar adb pull /system/framework/okhttp.jar,但它只包含MANIFEST.MF

在崩溃报告中,您可以了解到您的应用程序版本,并且假设您至少有一些简单的版本控制措施,您应该知道该应用程序版本所附带的okhttp版本。 - laalto
我的应用程序并不明确依赖于 okhttp - CAMOBAP
1个回答

2

从4.xx版本开始,谷歌使用了okhttp,它是squareup的一部分。

/**
* This implementation uses HttpEngine to send requests and receive responses. This class may use
* multiple HttpEngines to follow redirects, authentication retries, etc. to retrieve the final
* response body.
*
* <h3>What does 'connected' mean?</h3> This class inherits a {@code connected} field from the
* superclass. That field is <strong>not</strong> used to indicate whether this URLConnection is
* currently connected. Instead, it indicates whether a connection has ever been attempted. Once a
* connection has been attempted, certain properties (request header fields, request method, etc.)
* are immutable.
*/
public class HttpURLConnectionImpl extends HttpURLConnection {


  private String defaultUserAgent() {
    String agent = System.getProperty("http.agent");
    return agent != null ? Util.toHumanReadableAscii(agent) : Version.userAgent();
  }

https://github.com/square/okhttp/blob/master/okhttp-urlconnection/src/main/java/okhttp3/internal/huc/HttpURLConnectionImpl.java

http://square.github.io/okhttp/

一切都取决于设备-您使用的操作系统版本因为API正在不断发展,您可以使用反射,但需要知道特定API上的字段。请参阅https://github.com/square/okhttp/blob/master/CHANGELOG.md以获得更多信息。要比较不同的API版本,请使用https://android.googlesource.com/platform/external/okhttp/。您可以在开始时尝试。

System.getProperty("http.agent");

编辑:

通过反思

 HttpURLConnection  connection = (HttpURLConnection) new URL("http://google.com")
         .openConnection();
 Method method = connection.getClass().getDeclaredMethod("defaultUserAgent");
 method.setAccessible(true);
 String okEngineVersion = (String) method.invoke(connection, new Object[]{});

相同于

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

如果您想烦扰:

  • 每个类都被同等对待 - > 作为相等的(没有版本控制 - 您只能从类中检查魔术小大数 - Java编译器版本)
  • /system/framework/okhttp.jar的清单不包含版本属性

如果您需要okhttp.internal.Version类,则:

 File file = new File("/system/framework/okhttp.jar");

 // using javaxt-core lib        
 Jar jar = new Jar(file);
 jar.getVersion();

// load dex 
DexFile dexfile = DexFile.loadDex(file.getAbsolutePath(),
                   File.createTempFile("opt", "dex", _context.getCacheDir()).getPath(), 0);

Enumeration<String> dexEntries = dexfile.entries();
ClassLoader systemClassLoader = DexClassLoader.getSystemClassLoader();

while (dexEntries.hasMoreElements()) {
  String className = dexEntries.nextElement();
  Class<?> aClass = systemClassLoader.loadClass(className);
}

结论:如果你想避免应用程序因库更改而崩溃,可以提供自己的库版本,并动态加载类或与apk一起编译。

okhttp2.x 的解决方案怎么样?为什么我不能直接访问 okhttp3.internal.Version - CAMOBAP
谢谢您的更新,但我需要版本号,而不是“User-Agent”。根据代码,我知道“Version.userAgent”包含实际库版本,“HttpURLConnectionImpl.defaultUserAgent”则没有。 - CAMOBAP
@CAMOBAP - 通过反射获取版本字段。 - ceph3us
@CAMOBAP - 如果您不知道如何使用反射,请查看编辑并了解更多关于反射的知识。 - ceph3us
谢谢回复,但没有帮助,因为JAR文件中没有包含dex文件,而是放置在单独的odex文件中。 - CAMOBAP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接