連載
» 2014年03月24日 18時00分 公開

Androidで動く携帯Javaアプリ作成入門(50):あなたの知らないAndroid SDKの便利tools、14選まとめ (2/3)

[緒方聡,株式会社イーフロー]

【3】プロファイラーのフォーマットをAndroid SDKからJDK用に変換「hprof-conv」

 HPROF ConverterはAndroidの.hprofファイルのフォーマットをJavaの.hprofファイルのフォーマットに変換するツールです。hprofはJDK付属のプロファイラーで、Android SDKにも用意されています。

 前述のDDMSで任意のプロセスのプロファイルを取るには、DDMSの[Dump HPROF file]ボタンをクリックします。

図4 Dump HPROF file

 任意の場所に保存したファイルを「hprof-conv」コマンドでフォーマット変換します。

hprof-conv com.example.traceviewdemo.hprof converted.hprof

 最初が入力ファイル、次が出力ファイルです。ファイル指定を省略すると、標準入出力が使用されます。

 JDK付属の「jhat」コマンドで変換後のファイルを指定することで、ブラウザー経由で解析結果を参照できます。

jhat converted.hprof

 ポート7000でhttpdが起動するので、任意のブラウザーで「http://localhost:7000」にアクセスします。

図5 ブラウザーでプロファイル情報を参照

【4】アプリがどのように経時実行しているかを引き出す「procstats」

 Android SDK 4.4から追加された「procstats」という新しいツールを使用すると、システム上で実行されている全てのアプリとサービスが使用しているリソースを分析できます。

 詳細は、前回記事を参照してください。

【5】メモリ使用量の詳細を表示するツール「meminfo」

 「meminfo」はメモリ使用量の詳細を表示するツールで、Android 4.4で機能強化され、メモリ使用量のオーバーヘッドを発見しやすくなりました。

 詳細は、前回記事を参照してください。

【6】プロセスの統計情報をGUIで見られる「Process Stats」

 Android 4.4では、メモリプロファイルの解析が簡単に行える開発者オプションが追加されました。Android 4.4搭載端末で[設定]→[開発者向けオプション]→[プロセスの統計情報]で、端末上で開発者のアプリやサービスがどれぐらいメモリを使用しているかの確認が簡単に行えます。

 詳細は、前回記事の「Process Stats」を参照してください。

ソースコード解析/難読化

【7】ソースコードを静的解析してバグを見つける「lint」

 Androidのlintツールは正確性、セキュリティ、パフォーマンス、ユーザビリティ、アクセシビリティ、および国際化のための潜在的なバグや最適化の改善のためにAndroidプロジェクトのソースコードを静的解析するツールです。

 使い方は以下の通りです。

cd <ProjectDir>
lint src

 これで「src」以下のソースコードの静的解析の結果が表示されます。

 lintはEclipse上からプロジェクトに対して実行することで、ソースコード上にマークが付くようになるので、コマンドラインツールよりは、そちらの方が便利です。

図6 Androidプロジェクトに対するEclipse上からのlint

コラム「lint.batの修正とProject Lombok」

 筆者の環境(Windows、Android SDK Tools 22.6)では、lint.batを以下のように修正しなければ起動しませんでした。

- set jarpath=%frameworkdir%\%jarfile%
+ set jarpath=%frameworkdir%\%jarfile%;%frameworkdir%\lombok-ast-0.2.2.jar

 追加クラスパスに設定しているLombokは、Javaの冗長なコード省略可能にするためのライブラリです。例えば以下のようなクラスがあったとします。

public Class Member {
    private int id;
    private String name;
    public void setId(int id) {
        this.id = id;
    }
    public int getId() {
        return id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

 フィールドを2つ持つだけのクラスなのに、コードはとても冗長です。Lombokを使用することで以下のようにスッキリ記述できます。

@Data
public Class Member {
    private int id;
    private String name;
}

 Lombokの「@Data」というアノテーションが、冗長なSetter/Getterを自動生成してくれるようになります。Lombokは、これ一つとっても便利なわけですが、今回のlintツールでは、Lombokを用いて抽象構文木を生成し、その構文木に基づいて警告などを出すようにしているのだと思います。

 興味のある方は、「Project Lombok」で最新のJARやドキュメントを参照してみてください。


【8】コードの難読化、最適化、未使用コードの削除を行う「ProGuard」

 ProGuardはコードの難読化、最適化、未使用コードの削除を行うツールです。

 ProGuardはAndroidのビルドシステムに統合されているため、任意に実行する必要はありません。また、リリースモードでアプリをビルドするときにのみ実行されるため、デバッグモードでは通常通りにデバッグを行えます。

 リリースモード時にProGuardを実行するかどうかは任意ですが、行うことを強く推奨します。

 EclipseのAndroidビルドシステムでProGuardを実行するには、「project.properties」に以下のエントリを追加します。

proguard.config=proguard-project.txt

 デフォルトのproguard-project.txtは何も設定されていません。デフォルトでは以下のようなケースで「ClassNotFoundException」「NoSuchMethodError」などの例外/エラーが発生する可能性があります。

  • AndroidManifest.xmlからのみ参照されているクラス
  • JNIから参照されているクラス
  • メソッドやフィールドへの動的アクセス

 コードの難読化・最適化をProGuardから保護するためには、設定ファイルに以下のように記述します。

-keep public class <MyClass>

 全ての設定をここで説明するのは困難なので、筆者が実際に使用している設定ファイルからピックアップして紹介します。ProGuardの設定の詳細は「ProGuard Usage」を参照してください。

# 特定のクラスのサブクラスを保護
-keep public class * extends android.app.Activity
# 他のサービスとのインターフェイスを保護
-keep public class com.android.vending.licensing.ILicensingService
# ネイティブメソッドを持つクラスを保護
-keepclasseswithmembernames class * {
    native <methods>;
}
# enumを保護
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
# Parcelableを実装するクラスのCREATORフィールドを保護
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator CREATOR;
}
# リソースの参照を保護
-keepclassmembers class **.R$* {
    public static <fields>;
}
# ログ呼び出し処理をストリップ
-assumenosideeffects class android.util.Log {
    <methods>;
}
-assumenosideeffects class com.example.myapp.Log {
    <methods>;
}

 これだけでは設定として不十分なので、くれぐれもコピー&ペーストで自身のプロジェクトに導入しないでください。Androidの設定例はProGuardの「Examples」に載っていますが、これもサンプルなので自身のプロジェクトに合った設定を、仕様を理解した上で設定してください。

最後の「ログ呼び出し処理のストリップ」は、「戻り値が利用されていないメソッド呼び出しは呼び出しコードを除去する」という設定です。不要なログがエンドユーザー環境で表示されないようになり、セキュリティやパフォーマンス向上に一役買います。AndroidにはわざわざLogクラスがあるのに、あえて独自のログクラスを用意しているのは、コード除去をより完全にするためです。

    android.util.Log.d(TAG, "time:" + time);
    com.example.myapp.Log.d(TAG, "time:", time);

 上記のようなコードがあった場合、「Log.d(……)」のメソッド呼び出し処理は除去されますが、Android標準のログクラスの場合、引数に渡す文字列連結のコードは除去されません。一方で独自のログクラスでは、メソッド内部で文字列連結を行った後、Androidのログクラスのメソッドを呼び出すため、不要な文字列連結がコードとして残りません。

コラム「proguard.batの修正」

 筆者の環境(Windows、Android SDK Tools 22.6.1)だと、Andorid SDKに付属するProGuard実行用バッチファイル「proguard.bat」を修正する必要がありました。この修正を行わなければ、プロジェクトのエクスポート時に以下のようなエラーが発生します。

[2014-03-23 20:41:18 - Test] Proguard returned with error code 1. See console
[2014-03-23 20:41:18 - Test] Error: Unable to access jarfile ..\lib\proguard.jar

 修正は「<android-sdk>\tools\proguard\bin\proguard.bat」を以下のように修正します。

REM デフォルトをコメントアウトして、フルパスに書き換え
REM SET PROGUARD_HOME=..
SET PROGUARD_HOME=<android-sdk>\tools\proguard

 同様の問題が発生する場合は、参考にしてみてください。


Copyright © ITmedia, Inc. All Rights Reserved.

編集部からのお知らせ

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。