HttpClientをtargetSdkVersion=28でも使う

# 今さら HttpClient を使ってる人なんていないよねー

2018年にもなって平成だって終わろうとしてるのに、未だに ```HttpClient```(```Apache HttpClient```, ```DefaultHttpClient```, ```AndroidHttpClient```) を使ってる人なんていないと思います。

が、私が 2011 年から開発している [とあるアプリ](https://play.google.com/store/apps/details?id=jp.takke.android.tkmixiviewer&hl=ja) ではまだまだ ```HttpClient``` を使っていて、クッキーの処理などでかなりごにょごにょした部分もあり、すぐには移行できない状況でした。

とはいえ、[ご存じの通り](https://developers-jp.googleblog.com/2017/12/improving-app-security-and-performance.html) Playストアの仕様が変わり、2018年8月から新規アプリ、同11月からは既存アプリの更新時にも、```targetSdkVersion```を API Level 26（Android 8.0）以上にする必要がでてきました。で、サクッと ```targetSdkVersion=28``` (Android 9) にしてみると ```ClassNotFoundException``` が出て起動すら出来なくなってマジで詰み気味だったので色々試してみました。

結論から言えば ```AndroidManifest.xml``` に少し記述すると起動できました。


以下、少し詳しく書いておきます。


# Apache HTTP Client は Android 6.0 で削除されました

[Android 6\.0 の変更点  \|  Android Developers](https://developer.android.com/about/versions/marshmallow/android-6.0-changes?hl=ja#behavior-apache-http-client) によると
>Android 6.0 リリースでは、Apache HTTP クライアントのサポートが削除されました。アプリでこのクライアントを使用していて、Android 2.3（API レベル 9）以上を対象としている場合は、代わりに HttpURLConnection クラスを使用してください。この API は透過的データ圧縮と応答のキャッシュによってネットワーク使用を軽減し、電源の消費を最小化するため、効率性が向上します。Apache HTTP API を引き続き使用するには、まず ```build.gradle``` ファイルで次のコンパイル時の依存関係を宣言する必要があります。

```groovy:build.gradle
android {
    useLibrary 'org.apache.http.legacy'
}
```

ということで、Android 6.0(API Level 23) 以降でも ```build.gradle``` に ```useLibrary 'org.apache.http.legacy'``` を記述することで利用できていました。


# ```targetSdkVersion=28``` + Android 9 で動作しなくなった

```useLibrary 'org.apache.http.legacy'``` を記述していても、```targetSdkVersion=28``` にすると下記の例外が出て Android 9 でアプリが起動すらしなくなりました(Android 8.1 で動くかは試していませんが動いたところで)。

```
java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/conn/scheme/SchemeRegistry;
```

少し試してみたところ、

```
  Android 9 + HttpClient + targetSdkVersion=16 => OK(起動する)
  Android 9 + HttpClient + targetSdkVersion=23 => OK(起動する)
  Android 9 + HttpClient + targetSdkVersion=24 => OK(起動する)
  Android 9 + HttpClient + targetSdkVersion=25 => OK(起動する)
  Android 9 + HttpClient + targetSdkVersion=26 => OK(起動する)
  Android 9 + HttpClient + targetSdkVersion=27 => OK(起動する)
  Android 9 + HttpClient + targetSdkVersion=28 => NG(起動しない)
```

でした。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">targetSdkVersion を上げると Android 9 で DefaultHttpClient で通信ができなくなる(useLibrary &#39;org.apache.http.legacy&#39; を書いていても) のを確認するために targetSdkVersion を少しずつ上げて試している</p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/1042966160260526080?ref_src=twsrc%5Etfw">2018年9月21日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">targetSdkVersion = 23, 24, 25, 26, 27 は OK、28 にすると Didn&#39;t find class &quot;org.apache.http.conn.scheme.SchemeRegistry&quot; で落ちる</p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/1042967753739526144?ref_src=twsrc%5Etfw">2018年9月21日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# AndroidManifest.xml に uses-library を追記する

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">AndroidManifest.xmlに &lt;uses-library android:name=&quot;org.apache.http.legacy&quot; android:required=&quot;false”/&gt; を追加でいけたはずです</p>&mdash; burton999@アプリ開発 (@ComicCafeApp) <a href="https://twitter.com/ComicCafeApp/status/1036530145761214464?ref_src=twsrc%5Etfw">2018年9月3日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

burton999 さんのアドバイスを受けて

```xml:AndroidManifest.xml
    <application>

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

のように記述してみたところ、```HttpClient``` + ```targetSdkVersion=28``` + ```Android 9``` の組み合わせでも一応問題なく起動しました。

本当はさっさと ```OkHttp3``` で全面的に書き直すべきなんでしょうけど、既存のコードが多すぎて作業できずにいるのでもう少しだけこの方法で延命したいと思います。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">targetSdkVersion=28 にしても Manifest に &lt;uses-library android:name=&quot;org.apache.http.legacy&quot; android:required=&quot;false&quot; /&gt; を書くと動作した。もう少しだけ延命できそう。。</p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/1042968962424692736?ref_src=twsrc%5Etfw">2018年9月21日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# ついでに

Android 9 からは平文の通信がデフォルトで禁止になるので

```
java.io.IOException: Cleartext traffic not permitted: http://mixi.jp
```
のような例外を見かけたりしますがその際は [Android 8: Cleartext HTTP traffic not permitted \- Stack Overflow](https://stackoverflow.com/questions/45940861/android-8-cleartext-http-traffic-not-permitted) あたりを参考にしてください。


# リンク

 * [AndroidでHTTP通信したいときの手段まとめ \- Qiita](https://qiita.com/riversun/items/5f78d47a3d95f857d34f)
 * [2018年8月からtargetSdkVersionをAPIレベル26（Android 8\.0）以上にする必要がある \- Qiita](https://qiita.com/oya-t/items/d52e97aea20b2f20ad44)
 * [Google Developers Japan: 今後の Google Play でのアプリのセキュリティおよびパフォーマンスの改善について](https://developers-jp.googleblog.com/2017/12/improving-app-security-and-performance.html)
 * [Android 8: Cleartext HTTP traffic not permitted \- Stack Overflow](https://stackoverflow.com/questions/45940861/android-8-cleartext-http-traffic-not-permitted)