【问题标题】:Android | Get OkHTTP Library version at runtime安卓 |在运行时获取 OkHTTP 库版本
【发布时间】:2016-03-24 08:41:22
【问题描述】:

最近我分析了我的应用程序的崩溃报告,发现了几个指向okhttp的堆栈跟踪

我的应用不明确依赖okhttp

AFAIK 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") -> 成功

谁能解释为什么?我错过了什么?

更新

我已经从我的设备adb pull /system/framework/okhttp.jar 中提取了 okhttp.jar,但它只包含MANIFEST.MF

【问题讨论】:

  • 我的应用不明确依赖okhttp

标签: java android okhttp


【解决方案1】:

从 4.xx 开始,google 正在使用 squareup 的 okhttp 部分

/**
* 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 编译

【讨论】:

  • okhttp 2.x 的解决方案怎么样?为什么我不能直接访问okhttp3.internal.Version
  • 感谢您的更新,但我需要版本,而不是 User-Agent。根据代码我知道Version.userAgent 包含实际的库版本,HttpURLConnectionImpl.defaultUserAgent 没有
  • @CAMOBAP - 所以通过反射版本字段获取
  • @CAMOBAP - 是的,如果您不知道如何使用反射,请查看编辑,然后了解有关反射的更多信息
  • 感谢回复,没有帮助,因为 jar 不包含 dex 文件 odex 单独放置
猜你喜欢
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
  • 2012-02-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多