如何在Android Marshmallow上使用传统的Apache HTTP客户端?

76

背景

在 Android Marshmallow 上,Google 已彻底删除了对 Apache HTTP 客户端的支持 (链接 此处),因为相比替代方案,它性能不佳。

这也可能是许多应用程序在 Android Marshmallow 上崩溃的原因。

问题

Google 允许您仍然使用此 API,只是不作为内置的 API。只需将以下行添加到 gradle 文件中:

useLibrary 'org.apache.http.legacy'

所以,这就是我做的:

dependencies {
    classpath 'com.android.tools.build:gradle:1.3.0'
}

同时:

android {
    compileSdkVersion 'android-MNC'
    buildToolsVersion "23.0.0 rc3"
    useLibrary 'org.apache.http.legacy'

    defaultConfig {
        applicationId "com.example.user.androidmtest"
        minSdkVersion 'MNC'
        targetSdkVersion 'MNC'
        versionCode 1
        versionName "1.0"
    }
当我尝试它时,它编译得很好(没有显示任何错误,并且我可以运行概念验证应用程序,因为它没有任何特殊的代码),但是当我尝试使用我知道属于旧API的一些类(比如"HttpClient"类)时,我发现它不允许我这样做。 我知道不建议使用这个解决方案,但是我们必须让应用程序准备好工作,至少在Android Marshmallow的所有应该更改的事情都100%完成之前,我们不希望出现崩溃等意外情况。这里是截图:enter image description here 问题是什么?为什么会发生这种情况?我使用它正确吗?
编辑:在这里报告了这个问题:https://code.google.com/p/android/issues/detail?id=181474

你说的“compiled fine”是指Gradle同步正常,还是在运行时出现了ClassNotFoundException? - Blackbelt
你能发布一些Android Studio的截图吗? - DevUt
@Blackbelt 我的意思是,到目前为止,我编写的那些应该被支持的类可以编译和运行得很好(因为还没有使用它们)。不会出现任何ClassNotFoundException,因为我还没有使用它们。只有当我尝试使用应该存在的类时,我才不能这样做。它不允许我这样做,也不提供我所需的导入。 - android developer
@androiddeveloper coPLaS回答对我有用,因此应将其标记为正确答案。 - Sheraz Ahmad Khilji
为了澄清useLibrary的作用:Apache HttpClient在android-23中被隐藏,但实际上并未被删除。否则,许多针对早期平台的应用程序将在M上崩溃。添加useLibrary可以将这些遗留类添加到引导类路径中,在编译时(以及运行时)基本上取消隐藏这些类。下面WenChao的评论证明了这些类已添加到引导类路径中。 - Joe Bowbeer
显示剩余10条评论
12个回答

93

Android Studio 抱怨 org.apache.http 类无法使用。

org.apache.http.NameValuePair
org.apache.http.client.utils.URLEncodedUtils

部分文件丢失。

因此,我添加了org.apache.http.legacy.jar,该文件位于Android/Sdk/platforms/android-23/optional文件夹中,将其添加到了app/libs中。

我还在app.gradle文件中添加了这一行。

compile files('libs/org.apache.http.legacy.jar')

但是如果你使用更多的库,你可以使用这种方式

compile fileTree(dir: 'libs', include: ['*.jar'])

这解决了我所有错误,因为 Google 移除了对 Apache HTTP 客户端的支持。


2
对我有用。不过,我必须将该Jar文件作为库添加到我的应用程序模块中,以消除Android Studio关于HttpClient等错误的警告。 - Jürgen 'Kashban' Wahlmann
1
当我包含org.apache.http.legacy.jar时,我遇到了Proguard问题:IOExcpetion: Can't write [path to classes.jar] (Can't read [path to libs/org.apache.http.legacy.jar(;;;;;;!META-INF/MANIFEST.MF)] (Duplicate zip entry [org.apache.http.legacy.jar:org/apache/commons/codec/binary/Hex.class]))。还有其他人使用Proguard吗?有什么想法吗? - ashughes
1
很遗憾,Google选择使用一种需要人们将二进制文件添加到其项目中的hack,而不是将http-legacy发布到构件存储库。我以为我们在10年前就已经摆脱了这种反模式。 - William
1
您很厉害,先生。 - activity
1
即使这样,对我仍然没有用。请问 @CoPLaS 是否有可能诊断一下? - Lakshmi Narayanan
显示剩余11条评论

11

通过进行简单的文件路径检查,可以得到完美的解决方案。运行:

   android {
    compileSdkVersion 'android-MNC'
    buildToolsVersion "23.0.0 rc3"
    useLibrary 'org.apache.http.legacy'

    defaultConfig {
        applicationId "com.example.user.androidmtest"
        minSdkVersion 'MNC'
        targetSdkVersion 'MNC'
        versionCode 1
        versionName "1.0"

    }

        getBootClasspath().each{File file ->
           println file.absolutePath
        }
    }
}
你将得到类似以下的内容:

/Users/"你的用户名"/Development/android-sdk-macosx/platforms/android-MNC/android.jar /Users/"你的用户名"/Development/android-sdk-macosx/platforms/android-MNC/optional/org.apache.http.legacy.jar

所以,jar文件在那里。由于某些原因它没有被添加到项目中,但你可以手动添加。

1
我不明白。这段代码是什么意思?你的意思是我需要搜索这个JAR文件,并将其添加到项目中吗?请解释一下。 - android developer
是的,你说得对。我把那段代码写在 build.gradle 文件的 android 部分下面。就是我说的,这个 jar 包没有被自动识别到。也许你需要手动添加它。 - WenChao
这段代码做了什么?它真的需要吗?此外,你检查过它了吗?它工作正常吗? - android developer
不,它只是打印文件路径,没有任何花哨的操作,你可以安全地将其删除。那个jar包含了旧的apache jar(HttpClient,Log等)中的所有内容。我想它应该能正常工作。 - WenChao
好的,谢谢。希望到时候我不需要它。如果需要的话,我会再次检查的。目前为止,你因为努力得到了+1。 - android developer
我现在回到了这个问题。现在当我尝试使用jar时,我遇到了这个错误:Error:Execution failed for task ':app:packageAllSyncmeappDebugClassesForMultiDex'。
java.util.zip.ZipException: duplicate entry: org/apache/http/ConnectionClosedException.class。你也遇到了这个问题吗?
- android developer

10

在我的Android Studio项目的主build.gradle文件中,我升级了Gradle工具版本,如下所示:

useLibrary 'org.apache.http.legacy'并没有起到作用。

dependencies {
    classpath 'com.android.tools.build:gradle:1.3.0'
}

非常感谢!任何想法为什么只有这个更改解决了问题? - Shirane85
显然,useLibrary指令是最近才添加到Gradle中的,因此需要使用我上面提到的更新版本。 - Jamie Hall
我在主gradle文件中有这个:classpath 'com.android.tools.build:gradle:1.0.0-rc2' 所以我应该删除这个并添加你的那行代码,还是保留两行代码,它们都能正常工作而不会出现任何问题? - Sagar Devanga
删除那个并添加上面的。 - Jamie Hall

6
上面的答案只是帮助调试构建运行和使用gradle的发布构建。
将此插入应用程序标签中,在使用旧版apache类的所有项目实例的清单文件中:
<uses-library android:name="org.apache.http.legacy" android:required="false" />

这对于那些在编译过程中仍在使用Eclipse和ant脚本的人很有帮助。

6

经过很多令人沮丧的小时,以下方法可行:

1. 找到Apache jar包。 它应该存放在类似这样的地方:

C:\Users\<yourname>\AppData\Local\Android\sdk\platforms\android-23\optional

2.复制 org.apache.http.legacy.jar 到你的libs文件夹中。

右键单击libs->粘贴,或使用文件浏览器导航到项目的libs文件夹并粘贴。

如果你没有libs文件夹,就像我一样,创建一个新项目并将所有相关文件导入到它们各自的位置。

3.点击ok 查看此处

4.最重要的步骤:右键单击apache文件夹并选择Add As Library 查看此处

希望这能帮助某人继续他们的生活。


2

首先,您需要检查libs文件夹中的内容。

确保在Libs文件夹中检查Apache库

Then add into your gradle file like this 

    android {
        compileSdkVersion 23
        buildToolsVersion '23.0.2'

        defaultConfig {
            applicationId "info.tranetech.laundry"
            minSdkVersion 15
            targetSdkVersion 23
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    android {
        useLibrary 'org.apache.http.legacy'
    }
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:appcompat-v7:23.0.1
        compile 'com.android.support:design:23.0.1
        testCompile 'junit:junit:4.12'
        compile files('libs/android-async-http-1.4.4.jar')
        compile 'com.google.android.gms:play-services:8.4.0'
    }

This Is my gradle file

Also check external library


2

我知道这个理由听起来很愚蠢,但至少试一下...

我最近遇到了这个问题,我认为它是由路径长度限制引起的,最大长度可能为256个字符。

重新安置你的项目,构建将会成功。希望这对你有用。


1
这并不傻...这是在我的情况下起作用的答案...过去36个小时我尝试了地球上的所有方法,除了这个..一开始听起来很傻,所以我没有认真对待它。 - KawaiKx
大家也试试这个... 对我来说真的很有效,其他所有方法都失败了。 - KawaiKx
很高兴为您服务。@KawaiKx - Arpit Patel

2

位于的传统Apache库

[ANDROID_SDK]\platforms\android-23\optional\org.apache.http.legacy.jar 

所以你可以将它复制到你的项目libs中,或者直接使用。
compile files("${android.getSdkDirectory().getAbsolutePath()}" + File.separator + "platforms" + File.separator + "android-23" + File.separator + "optional" + File.separator + "org.apache.http.legacy.jar")

在你的/app/build.gradle文件中。

1

请在sdk/platforms/android-23/optional/optional.json中启用此功能。

[
  {
    "name": "org.apache.http.legacy",
    "jar": "org.apache.http.legacy.jar",
    "manifest": false
  }
]

1
移除
useLibrary 'org.apache.http.legacy' 

我从build.gradle文件中复制了代码,并且还在我的app.gradle文件中添加了这一行。

compile files('libs/org.apache.http.legacy.jar')

但如果你使用了更多的库,你可以使用这种方式

compile fileTree(dir: 'libs', include: ['*.jar'])

CoPLaS的回答解决了我的问题。

2
那么,只需点赞CoPLaS的答案,而不是在这里复制它! - Leo supports Monica Cellio

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