Android 9でHTTP通信を有効にする方法

2018/12/27

Android8以下で問題なく通信できていたアプリがAndroid9になった途端に通信NGに失敗する、という問題に直面。Android 9.0 (Pie) の仕様変更が原因でした。

何が変わった?

Android 9.0では暗号化されていない接続はデフォルトで無効になります。iOSの ATS (App Transport Security) と同じような考え方ですね。

ちなみに、暗号化されていない接続を「クリアテキスト接続」と呼ぶようです。「平文」と同義ととらえればよさそう。

望ましい対応

全ての通信をTransport Layer Security (TLS) に対応するのがベストプラクティス。一般的なアプリだとHTTPを使わずHTTPSにすればOK。Socketとかを使っている場合はそちらもケアしましょう。

(好ましくはないが手軽な)代替案

AndroidManifest.xmlのapplicationタグにあるandroid:usesCleartextTrafficを使うと暗号化されていない接続を許可できます。Android 9.0ではandroid:usesCleartextTrafficの既定値がfalseになっているので、これを明示的にtrueにしてあげましょう。

usesCleartextTrafficはAPI level 23で導入された属性ですが、23未満だと無視されるだけなので気にせず指定してOKです。

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:usesCleartextTraffic="true"
                    ... >
        ...
    </application>
</manifest>

とりあえずHTTP通信を全部OKにしたい!というときはこれでOK。推奨されないでしょうけど、諸般の事情でこのパターンを採用するケースは多いと思います...

(手間はかかるが好ましい)次善策

ゼロイチじゃなくて細かく制御したいんだ!というときはアプリに対してネットワークセキュリティ構成に関する設定を追加してあげます。設定はXMLファイルに書き、マニフェストファイルのapplicationタグにあるandroid:networkSecurityConfig属性で設定ファイルのありかを示します。

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>

具体的な設定は res/xml/network_security_config.xml というファイルに記述します。

cleartextTrafficPermitted がキモで、これを使ってクリアテキスト接続を許可するかどうかを制御します。

パターン1:特定のドメインのみクリアテキスト接続を許可

<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">site1.example.com</domain>
        <domain includeSubdomains="true">site2.example.com</domain>
    </domain-config>
</network-security-config>

site1.example.comsite2.example.com 並びにそれらのサブドメインのみクリアテキスト接続を許可し、それ以外は禁止する、という設定になります。

特定の接続先がどうしてもHTTPSに対応できない!みたいなときはこの設定ですね。

パターン2:特定のドメインのみ暗号化を必須に

<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">site1.example.com</domain>
        <domain includeSubdomains="true">site2.example.com</domain>
    </domain-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

逆に、特定のドメインへの通信は保護したい、というパターン。

他にもいろいろ設定できるようですが、この2パターンで大半のケースに対応できると思います。


世の中的にはHTTPS化は不可避の流れなので、できるところから対応していきましょう。

ちなみに自分の場合は、URLを限定できないタイプのアプリだったのでHTTP通信を全部OKにしました。しょうがないよね...

参考URL




関連(するかもしれない)記事


おススメ