一、报错描述

迁移 Java Sample 到 Android 项目中,使用 org.apache.http 库运行时报错如下:

FATAL EXCEPTION: pool-2-thread-1 (Ask Gemini)
Process: com.xxx.devicemanager, PID: 18821
java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; in class Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; or its superclasses (declaration of 'org.apache.http.conn.ssl.AllowAllHostnameVerifier' appears in /system/framework/framework.jar!classes5.dex)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.<clinit>(SSLConnectionSocketFactory.java:151)
at org.apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.java:981)
at org.apache.http.impl.client.HttpClients.createDefault(HttpClients.java:56)
at com.xxx.devicemanager.utils.HttpClientUtils.doPostJson(HttpClientUtils.java:200)
at com.xxx.devicemanager.CloudLinkManager$1.lambda$onSuccess$0$com-xxx-devicemanager-CloudLinkManager$1(CloudLinkManager.java:195)
at com.xxx.devicemanager.CloudLinkManager$1$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012) 

使用 org.apache.httpcomponents:httpclient 4.5.14,当Android Studio 编译时候也会报错,添加如下编译通过

android {
    ...
    packaging {
        exclude 'META-INF/DEPENDENCIES'
    }
    ...
}

二、报错分析

这个问题是一个典型的在 Android 开发中遇到的库冲突问题。错误日志 java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; 表明,您的代码在运行时加载的 AllowAllHostnameVerifier 类版本中,并不存在一个名为 INSTANCE 的静态字段。

这个问题的根本原因在于 库版本冲突。具体来说:

  1. Android 系统自带了 Apache HttpClient 库:为了历史兼容性,Android 系统本身在 framework.jar 中内置了一个版本的 Apache HttpClient 库。然而,这个系统内置的版本通常比较旧。
  2. 您的应用或其依赖的库引入了新版本的 HttpClient:您的应用(com.xxx.devicemanager)或者它所依赖的某个库(例如某个网络请求库)也引入了一个较新版本的 Apache HttpClient。
  3. 冲突发生:在运行时,Java 虚拟机(JVM)加载了 Android 系统提供的旧版本 AllowAllHostnameVerifier 类。从错误信息中的路径 /system/framework/framework.jar!classes5.dex 可以确认这一点。然而,您的代码(具体是在 org.apache.http.conn.ssl.SSLConnectionSocketFactory.<clinit>)是基于新版 HttpClient 编译的,它期望 AllowAllHostnameVerifier 类中有一个 INSTANCE 静态字段。由于加载的是没有这个字段的旧版本类,因此抛出了 NoSuchFieldError 异常。

这个问题在 Android 6.0 (API 23) 及以上版本尤为常见,因为从这个版本开始,Google 不再推荐使用 Apache HTTP 客户端,并对其支持做了变更。

三、解决方案

使用专门为 Android 优化的 HttpClient 库(推荐)

最直接且推荐的解决方法是,使用一个已经处理了这类冲突的第三方库,这个库会将 Apache HttpClient 的类重新打包到一个新的命名空间下,从而避免和系统自带的库冲突。

1.在您项目的 build.gradle (Module: app) 文件中,添加以下依赖:

dependencies {
    // ... 其他依赖
    implementation 'cz.msebera.android:httpclient:4.5.8' // 或者更新的版本
}

2.修改您的代码,将所有 org.apache.http 的 import 语句修改为 cz.msebera.android.httpclient。例如:

  • import org.apache.http.HttpResponse; -> import cz.msebera.android.httpclient.HttpResponse;
  • import org.apache.http.client.HttpClient; -> import cz.msebera.android.httpclient.client.HttpClient;

这种方法的优点是能够彻底解决命名空间冲突的问题。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐