iOS
iOSDay 2

iOS9 ATSを本番・開発環境用ごとに対応する方法

More than 3 years have passed since last update.


概要

iOS9からApp Transport Security(ATS)が追加されました。

ATSとは安全なネットワーク接続を実現するための機能であり、Appleの要件を満たしていない場合は接続失敗という扱いになります。


対応方法

対象となるのは、自社内サーバ、WebView経由、サードパーティライブラリ(SNS、広告、分析など)だと思います。 ATS自体を無効にするのはあまり良いやり方ではないので、これらのドメインをATSの例外に設定するのが一般的なやり方だと思います。


設定方法

設定方法はInfo.plistに指定の情報をセットするだけです。 しかし、プロジェクトのTargetが多かったりConfigurationによって設定を分けたい場合には、Info.plistを個別に用意して管理する必要がありますが、無駄にInfo.plistファイルが増えるので良い方法ではないと思います。


スクリプトでATS設定

そこで、スクリプトを実行してATSに必要な情報をInfo.plistにセットしてみました。

PlistBuddyコマンドを使えばplistを編集できます。 Build Phaseでスクリプトを毎回実行して、Info.plistにATS対応の情報を追加しています。

HTTP通信のfoo.comドメインをATSの例外にするコマンドは以下のようになります。

/usr/libexec/PlistBuddy -c Add NSAppTransportSecurity:NSExceptionDomains:foo.com:NSExceptionAllowsInsecureHTTPLoads bool true

上記のコマンドを実行すると、Info.plistに以下のように登録されます。

<key>NSAppTransportSecurity</key>

<dict>
<key>NSExceptionDomains</key>
<dict>
<key>foo.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>

あとは、TargetConfigurationごとにそれぞれ例外を設定するだけです。

スクリプト内では${PRODUCT_NAME}Target${CONFIGURATION}Configurationを取得出来るので、処理を分岐させて適切なドメインにATSの例外設定を実行すれば完了です。

今回対応したアプリはTargetで本番・開発環境を切り分けれたので、以下のようになりました。

case ${PRODUCT_NAME} in

"JP DEV")
`/usr/libexec/PlistBuddy -c Add NSAppTransportSecurity:NSExceptionDomains:dev.foo.co.jp:NSExceptionAllowsInsecureHTTPLoads bool true`;;
"JP Production")
`/usr/libexec/PlistBuddy -c Add NSAppTransportSecurity:NSExceptionDomains:foo.co.jp:NSExceptionAllowsInsecureHTTPLoads bool true`;;
"US DEV")
`/usr/libexec/PlistBuddy -c Add NSAppTransportSecurity:NSExceptionDomains:dev.foo.com:NSExceptionAllowsInsecureHTTPLoads bool true`;;
"US Production")
`/usr/libexec/PlistBuddy -c Add NSAppTransportSecurity:NSExceptionDomains:foo.com:NSExceptionAllowsInsecureHTTPLoads bool true`;;
esac

余談ですがPlistBuddyコマンドのAddについて、既に存在しているエントリをAddしようとするとエラーになるので、一度DeleteしてからAddするようにしています。 PlistBuddyコマンドを正しく理解出来ていないだけかもしれません...


Preprocessed-Info.plistを活用する

これで、実行プロジェクトの状態から適切な情報がInfo.plistにセットされますが、別の問題が出てきました。 Configurationなどを変えるとビルド後にInfo.plist自体が編集されるので、ファイルに差分が出てしまいます。

上記のように設定を変えるたびに毎回差分が出るのは邪魔なので、Preprocessed-Info.plistの方を編集することでInfo.plistの差分を出さないようにします。

Preprocessed-Info.plistとは、Build Phaseの1番最初に生成されて、その後に編集された内容もアプリに反映されるplistのことです。 Build SettingsPreprocess Info.plist FileYESにすると生成されます。 このファイルは${TEMP_DIR}以下に生成されるので、編集しても差分が出ることはありません(プロジェクト直下では無いので)。

先ほどのPlistBuddyコマンドは編集するplistを指定することが出来ます。 最終的なコマンドは以下のようになります。

/usr/libexec/PlistBuddy -c Add NSAppTransportSecurity:NSExceptionDomains:foo.com:NSExceptionAllowsInsecureHTTPLoads bool true ${TEMP_DIR}/Preprocessed-Info.plist


まとめ

スクリプトが出来るまで多少時間はかかりましたが、設定しているATSの例外を一元管理出来るので、良い方法ではないかと思います。 特に大規模なプロジェクトだと細かい違いがあるので、スクリプトで処理を判別出来るのは良かったです。

唯一の後悔は、素直にシェルスクリプトで書いてしまったことです。 なぜSwiftで書かなかったのか...

まだATSの対応をされていない方もいらっしゃると思うので、参考になれば幸いです。