76

Background

On Android Marshmallow, Google has completely removed the support of Apache HTTP client (link here) because it doesn't have good performance compared to the alternatives.

This might also be the cause for so many apps crashing on Android Marshmallow.

The problem

Google allows you to still use this API, just not as a built in one, by adding this line to the gradle file:

useLibrary 'org.apache.http.legacy'

So, this is what I did:

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

And:

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

When I tried it, it compiled fine (no errors being shown, and I could run the proof-of-concept app, as it doesn't have any special code), but when I tried using some of the classes that I know that are part of the old API (like "HttpClient" class), I see that it doesn't allow me to do so.

I know it's not recommended to use this solution, but we must have the app ready to work there at least temporarily, till we work 100% on all of the things that should change for Android Marshmallow, and we don't want surprises in the form of crashes.

Here's a screenshot:

enter image description here

The question

Why does it occur? Did I use it correctly?


EDIT: reported about this issue here:

https://code.google.com/p/android/issues/detail?id=181474

android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • by *it compiled fine* you mean gradle synced fine or are you getting a ClassNotFoundException at runtime? – Blackbelt Jul 27 '15 at 12:24
  • Can you post some screenshot of android studioat – DevUt Jul 27 '15 at 12:25
  • @Blackbelt I mean that up to the time I've written classes that are supposed to be supported, it could be compiled&run fine (because there is nothing to use it). There can't be any ClassNotFoundException, because I don't use them yet. Only when I try to use classes that are supposed to be there, I can't. It doesn't allow me to do so and it doesn't offer me the needed imports. – android developer Jul 27 '15 at 12:47
  • @user4847410 Screenshot of what exactly ? Trying to put the import by force will result in it not being recognized. and using a class that exists there does it too. Anyway, I've updated the question to show the current situation, which is quite minimal... – android developer Jul 27 '15 at 12:50
  • Check if you're using the latest *beta* gradle. dependencies { classpath 'com.android.tools.build:gradle:1.3.0' } That seems like something is missing after the version (i.e. '-beta' or something). Using the latest beta solved it for me – milosmns Jul 27 '15 at 17:30
  • @milosmns Are you sure it's not final? The recent update says it's available: http://tools.android.com/recent/androidstudio13releasecandidate4available "Include Andoid Gradle 1.3.0 in the offline Gradle plugin repository" . Doesn't it mean it's final? – android developer Jul 27 '15 at 18:27
  • @androiddeveloper Hmm. It says Release candidate 4, so I'm guessing it's not a GA load yet. But what I used to get this to work was *com.android.tools.build:gradle:1.3.0-beta2*. Please post an update if you figure out what was wrong, we're resorting to lots of ugly hacks all the time – milosmns Jul 28 '15 at 09:53
  • @milosmns Tried the "1.3.0-beta2" . Still same results. – android developer Jul 28 '15 at 10:06
  • @androiddeveloper Oh. Bummer. Strange thing happened just now, when I changed the SDK to 'M' and build tools to the latest, Gradle version declaration reverted back to stable.. – milosmns Jul 28 '15 at 10:20
  • Ok, here's what I have (complete setup) - http://pastebin.com/Hx456HFh It's working now for me, hope it helps someone – milosmns Jul 28 '15 at 10:26
  • @milosmns using your code, it says the plugin is too old, so I changed it to 1.3.0 . Anyway, it doesn't work, because as soon as I write "HttpClient s;" in code, it doesn't allow me to import it. – android developer Jul 28 '15 at 12:33
  • @androiddeveloper **coPLaS** [answer](http://stackoverflow.com/a/32066606/1118886) worked for me so it should be marked as correct answer – Sheraz Ahmad Khilji Aug 20 '15 at 10:43
  • Sorry. I am new to mobile development. I am using HTTPClient in my app. Does it mean that even if I keep my targetsdkversion 22 and run the app on Android marshmallow, it will crash ? – MobileAppDeveloper Sep 17 '15 at 19:16
  • @MobileAppDeveloper You can try on the emulator... My guess is that it will crash. – android developer Sep 18 '15 at 07:01
  • To clarify what useLibrary is doing: Apache HttpClient is *hidden* in android-23 but is not actually removed. Otherwise lots of apps targeting earlier platforms would crash on M. Adding useLibrary serves to add these legacy classes to the boot classpath, essentially unhiding these classes at compile time (and at runtime). WenChao's comment below demonstrates that the classes are added to the boot classpath. – Joe Bowbeer Oct 19 '15 at 03:23

12 Answers12

93

Android Studio was complaining that org.apache.http classes like

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

were missing.

So I added org.apache.http.legacy.jar which is in Android/Sdk/platforms/android-23/optional folder to to app/libs

I also added this line to my app.gradle file

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

But if you're using more libraries, you can use this way

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

This resolved all my errors that were caused because google removed support of Apache HTTP client.

pedrofsn
  • 326
  • 2
  • 15
CoPLaS
  • 1,727
  • 12
  • 21
  • 2
    Worked for me. I had to add the Jar as a library to my app module though, to get rid of the Android Studio errors about HttpClient and so forth. – Jürgen 'Kashban' Wahlmann Aug 18 '15 at 12:41
  • 1
    I get Proguard issues when I include org.apache.http.legacy.jar: `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]))` Anyone else using Proguard? Any ideas? – ashughes Aug 19 '15 at 01:31
  • This should be marked as Right Answer. It worked for me. – Sheraz Ahmad Khilji Aug 20 '15 at 10:33
  • @ashughes probably you get proguard issues because other libs e.g. commons-codec in some of your modules. – sandrstar Aug 29 '15 at 12:30
  • what if I set android:targetSdkLevel to 22 or lower? Will my app crash on Android M? – suitianshi Sep 01 '15 at 09:15
  • I also use httpcore-4.3.1.jar and httpmime-4.3.2.jar , so adding the legacy jar file causes other issues (like: Error:(5, 43) error: package org.apache.http.entity.mime.content does not exist ) , and if I don't remove them, I get errors that say that the classes already exist (same package name and class name). BTW, I think this already use the jar file : compile fileTree(dir: 'libs', include: ['*.jar']) – android developer Sep 06 '15 at 07:06
  • @androiddeveloper I am also having same issue of multiple dex as i am using both jars you mentioned above. So did you find any solution for this? – Nak Android Dev Sep 08 '15 at 09:00
  • @NakAndroidDev Sadly no, and the team manager said we will move to okHttp to avoid those issues once and for all. I wonder how good it is. – android developer Sep 08 '15 at 09:46
  • @CoPLaS what about eclipse, where can I find this lib? – Ricardo Sep 13 '15 at 22:52
  • @NakAndroidDev Did you solve it ? I've now tried to do it again, and now I got: Error:Execution failed for task ':app:packageAllSyncmeappDebugClassesForMultiDex'. > java.util.zip.ZipException: duplicate entry: org/apache/http/ConnectionClosedException.class – android developer Sep 17 '15 at 14:11
  • yes; but it's not proper fix yet. I think its bug with Android Studio. What i did is added `useLibrary 'org.apache.http.legacy'` in my gradle file and then tried to build run the app. it worked as it should. But when I open my class file and write its code then it's showing me error that can not resolve all these packages and classes. but on compile time and execution its not showing any error, – Nak Android Dev Sep 18 '15 at 13:32
  • 1
    It is very sad that Google has chosen to use a hack requiring people to add a binary to their project rather than publishing http-legacy to an artefact repo. I thought we had left that anti-pattern behind 10 years ago. – William Sep 22 '15 at 05:00
  • Thanks Works ! I think that Google will need repair this problem. –  Dec 08 '15 at 22:54
  • Thanks. But When I'm using this now, all the basic classes and methods like HttpPost, HttpClient, NameValuePair, BasicNameValuePair are deprecated. Now What – Krishna Feb 08 '16 at 18:07
  • 1
    You are Genius, Sir. – activity Aug 12 '16 at 19:10
  • 1
    It still hasn't worked for me even after this. Any possible diagnosis please @CoPLaS – Lakshmi Narayanan Sep 28 '16 at 19:55
11

Perfect solution here by running a simple file path check. by running

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

You will get something like below

/Users/"yourname"/Development/android-sdk-macosx/platforms/android-MNC/android.jar /Users/"yourname"/Development/android-sdk-macosx/platforms/android-MNC/optional/org.apache.http.legacy.jar

So there you go, the jar is there.For some reason it didn't get added to the project. but you can always add it manually I guess.

Abhinav Singh Maurya
  • 3,313
  • 8
  • 33
  • 51
WenChao
  • 3,586
  • 6
  • 32
  • 46
  • 1
    I don't understand. What is this code you've written? You mean I should search for this jar, and add it to the project. Please explain. – android developer Aug 05 '15 at 06:18
  • Yeah, you are right. I wrote that code in build.gradle under android clause. Exactly what I'm saying, the jar didn't get picked up automatically . Perhaps you need to add it manually – WenChao Aug 05 '15 at 06:24
  • What does the code do? Is it really needed? Also, have you checked it? Does it work fine? – android developer Aug 05 '15 at 06:28
  • No,it just prints the file path. doesn't do anything fancy, you can remove it safely. That jar contains everything from the old apache jar(HttpClient,Log, etc.) I suppose it will work just fine. – WenChao Aug 05 '15 at 06:32
  • ok, thank you. hope that I won't need it when the time comes. Will check it again if/when needed. For now, You get +1 for the effort. – android developer Aug 05 '15 at 08:54
  • I've now got back to this issue. Now I get this error when trying to use the jar: Error:Execution failed for task ':app:packageAllSyncmeappDebugClassesForMultiDex'. > java.util.zip.ZipException: duplicate entry: org/apache/http/ConnectionClosedException.class .Did you also have this issue? – android developer Aug 19 '15 at 09:10
10

useLibrary 'org.apache.http.legacy' did not work for me until I upgraded the Gradle tools version in my main build.gradle file of my Android Studio project, as follows:

dependencies {
    classpath 'com.android.tools.build:gradle:1.3.0'
}
Jamie Hall
  • 101
  • 2
6

The answer above just helps the debug builds to run, and release builds that are utilizing gradle.

Insert this inside the application tag on the manifest file, on all project instances that uses the legacy apache classes:

<uses-library android:name="org.apache.http.legacy" android:required="false" />

This helps for those who are still using Eclipse and ant scripts during compile.

Pier Betos
  • 1,038
  • 9
  • 17
6

After many frustrating hours, the following worked:

1. Locate the apache jar. It should reside somewhere like:

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

2. Copy org.apache.http.legacy.jar to your libs folder.

Either right click on libs -> paste , or use your file explorer to navigate to the libs folder of your project and paste.

If you don't have a libs folder, as I did, make a new project and import all relevant files into their respective places.

3. Click ok see this

4. Most important step: Right click on the apache folder and select Add As Library. see this

Hope this helps someone get on with their life.

The AEB
  • 71
  • 1
  • 2
2

Legacy Apache library located in

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

So you can copy it inside you project libs or just use

compile files("${android.getSdkDirectory().getAbsolutePath()}" + File.separator + "platforms" + File.separator + "android-23" + File.separator + "optional" + File.separator + "org.apache.http.legacy.jar")

in your /app/build.gradle

AndreyICE
  • 3,574
  • 29
  • 27
2

I know this is silly reason but at list try it...

I experienced this problem recently, and it is caused by the path length restriction I think it´s 256 characters maximum.

Relocate your Project and the build will succeed.Hope this work for you.

Arpit Patel
  • 7,212
  • 5
  • 56
  • 67
2

First you have to check that in your libs folder

Make sure in Libs Folder Check that apache library

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

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Arpit Patel
  • 7,212
  • 5
  • 56
  • 67
1

Enable this in sdk/platforms/android-23/optional/optional.json

[
  {
    "name": "org.apache.http.legacy",
    "jar": "org.apache.http.legacy.jar",
    "manifest": false
  }
]
arun-r
  • 3,104
  • 2
  • 22
  • 20
1

Remove

useLibrary 'org.apache.http.legacy' 

from the build.gradle and I also added this line to my app.gradle file

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

But if you're using more libraries, you can use this way

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

CoPLaS answer fixed my problems.

Roger Belk
  • 309
  • 5
  • 17
0

A simple way to solve this issue is C:\Users\username\AppData\Local\Android\sdk\platforms. Here delete your android-23 and from SDK manager update your API 23 again. It will solve your issue.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
impathuri
  • 574
  • 6
  • 21
0

How to use the legacy Apache HTTP client on Android Marshmallow?

To continue using Apache HTTP classes for API 23+:

First of all, be sure to add the gradle dependencie into the build.gradle f

buildscript {

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

Then add the reference inside build.gradle of your project:

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.0"
    useLibrary 'org.apache.http.legacy'
    ...
}
Jorgesys
  • 124,308
  • 23
  • 334
  • 268