Androidに統合されたProGuardに関する改善点(ADT17)


はじめに

前回の記事では、ADT8で標準搭載されたProGuardの適用方法について解説しました。今回、ADT17でProGuardのいくつかの改善が行われたため、これら改善点について解説します。尚、本記事はProGuard Improvementsを元に翻訳したものです。

ProGuardとは

詳細は前々回の記事を参照頂きたいのですが、ProGuardが初めての方の為に簡単に説明します。
ProGuardはソースコードをコンパイルする際に処理を最適化したり、プログラム中の変数やメソッドを意味のない文字列に置き換え、逆コンパイルされた際に処理の中身をわかりにくくする、いわゆる「難読化」を行うツールです。ビルドツールであるAntやEclipse上から簡単にProGuardが使えるようになりました。

ProGuardの改良点

バンドルするバージョンを4.4から4.7にアップデート

バンドルされているバージョンが4.4から4.7になったことで、数多くの不具合修正及び拡張がなされました。いくつかのユーザーが直面していた、”error 1でDalvikフォーマットへのコンバージョンに失敗する" 不具合も修正されています。また、多くの "パス中のスペース" 問題に対応すべく、ProGuardの起動に関するコードの更新も行いました。

設定ファイルの取り扱い方法を変更

前回のリリースまでは、ADTで "new Android project" が作成されると、プロジェクト内にデフォルトの "proguard.cfg" がコピーされていました。このファイルはAndroidのProGuardで使用するために必要な数々のルール(「Androidと互換性を持たない最適化を行わないようにする」ことや「XMLから参照されたメソッドのみ圧縮されないように"keep"ルールを追加する」ことなど)が含まれています。

しかし時間と共に、デフォルトの設定とAndroid APIの追加によって発展してきた必要なルールの双方にバグが見つかりました。問題は、今、プロジェクト中にユーザが昔のproguard.cfgファイルのコピーを持っているということです。いくつかの既知の悪いパターンを検知するlintルールが新たに加えましたが -- しかし、ユーザが自身のproguardの設定ファイルを編集したり再編成する場合に、そのファイルが現在の推奨を満たす「最新かどうか」を判断することは非常に困難になります。

さらに、多くのユーザーはProGuardのドキュメントを読んだり、設定をいじったりすることを望みません -- 彼らはマーケットにアップロードする前にアプリを圧縮したり難読化がしたいだけなのです。

したがって、ADT17では設定ファイルを二つに分割しました:

  • Androidのための"デフォルト"設定
  • Project特有のフラグ

重要なポイントは、「ルールのデフォルトセットは、もうプロジェクト内にコピーする必要はない」ということです。デフォルトのルールセットはツールの中にインストールされ(特に tools/proguard/proguard-android.txt)、それらはツールと共にアップデートされます。

自身のソースコード中に特定の-keepフラグを追加したいような場合、プロジェクトの特定フラグをProGuardの設定のためローカルに追加することが可能です。デフォルトでは、プロジェクトのルートに"proguard-project.txt"という名前で保存されています。ファイルの拡張子を.cfgから.txtに変更した理由は、単純にこれらがテキストファイルであること、Eclipseやファイルエディタからダブルクリックするだけで変更できるからです。

注意:上記の変更は必須ではありません。これまでのように、自身のプロジェクト中に完全なProGuardの設定を規定しておくことも依然として可能です。

これら全ての作業を行うために、project.propertiesファイルのproguard.configプロパティの意味を変更しました。古いバージョンでは、ProGuardの圧縮と難読化を有効化するために、proguard.config=<設定ファイルまでのパス、大抵は単純にproguard.cfg> と定義していました。

ADT 17では、proguard.configプロパティは<設定ファイルまでのパス>の代わりに、<設定ファイルが存在するディレクトリのパス>を指定します。したがって、設定ファイルを複数指定することができます。これらの設定ファイルはProGuardによって全て結合されます。デフォルトではProGuardはオフになっていますが、"new projects" で作成されたproject.propertiesファイルには、以下のようなコメントのブロックが含まれています:

# To enable ProGuard to shrink and obfuscate your code, uncomment this
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

(プロジェクトファイル中の絶対パスを避けるために、${sdk.dir}や${user.home}をこれらパス中に含めることができます。project.propertiesファイルは、バージョン管理の中で特にチェックされるため、重要です。)

そのため、通常の方法でProGuardを有効にするためには、上記の行のコメントを解除するだけです。toolsディレクトリから全てのデフォルトのAndroid ProGuard設定フラグをピックアップされます。また、ツールのバグフィックスやAndroidの変更に伴う設定の不具合の更新は自動的に行われます。

ProGuardの設定を完全にコントロールしたい場合、代わりにファイルに自身の設定を単純に定義するだけで良いです。ProGuardは一般的にフラグを減じないため、デフォルトのフラグの一つを無効にしたい場合は、自身のファイル中にグローバルな設定をコピーし、無効にしたい行を取り除く必要があることに注意してください。
そのようなフラグの一つとして考慮した方が良いフラグは、-dontoptimizeフラグです。主な理由として、開発者が圧縮と難読化の面でProGuardを使用するからです(ダウンロードと実行時間のサイズを小さくし、コードのいくつかをプライベートにし、シンボルにパフォーマンスのメリットがある)。Dalvikは自身の最適化に多くの処理を行い、いくつかはProGuardによる最適化と互換性がありません。そのため、再現が難しいバグ(と、パフォーマンス効果が大抵は小さくなってしまうこと)を避けるために、デフォルトの設定では最適化をOFFにしています。
あえて最適化を実施したい場合は、デフォルトのファイルでコメントアウトされた最適化フラグをローカル設定ファイルにコピーして、注意してテストを行うようにして下さい。また、ローカルの設定は定期的に最新かどうかをチェックすることを忘れないようにして下さい。

ADT17中のデフォルト設定ファイルが更新されたため、直接それらを使用していない場合、自身のコピーと新しいコピーとの間で、自身のコピーに何かミスがないかどうかを比較したいと思うかもしれません。そこで、いくつかのフラグを説明するためにコメントを追加しました。

既にあるプロジェクトへの影響は?

上記の説明は、全て新しくプロジェクトを作成した場合についてのものでした。既存のプロジェクトに影響はあるのでしょうか?

心配には及びません。既存のプロジェクトには一切手をつけていません。全ては今日も作動しつづけます。自動的にあなたのフラグを変更したりはしていません。しかし、多くの開発者は熟考して設定を使用していないと思います。プロジェクトを作成した時に得たものをそのまま使用しており、それらは最新の設定では無いことに気づいていないかもしれません。この全体的な問題にユーザーが気づくように、このシナリオを検知する新しいlintのルールを追加しました:

おそらくこれは、デフォルトのAndroid設定ファイルとローカルのいくつかのフラグへリンクするためのprojetct.propertiesファイルの編集方法を分かりやすくする十分な情報を含むでしょう。このlintルールは能動的にProGuardを有効化している時だけキックされるため、プロジェクト中に作られはしたが、使用されていないデフォルトのproguard.cfgファイルを有する開発者を悩ませることはないでしょう。

最後に、proguard.configプロパティは「パス」であることに注意して下さい。このプロパティには2つ以上のファイルを定義することができます。ホームディレクトリを参照するために${user.home}フラグを使用することもできます。したがって、上に示されるような${sdk.dir}には"グローバルな" Androidのデフォルト、${user.home}中には"ユーザごと"のフラグ(プロジェクト間で共有されるもの)といったように、プロジェクト内で定義された全てのフラグを持つことが可能です。

文責:技術部 瀬戸 直喜