Android アプリのリリース バージョンをビルドする前に、すべてのデバッグ ログ呼び出しを削除するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/2446248

質問

Google によると、「ソース コード内の Log メソッドへの呼び出しを無効にするAndroid アプリを Google Play に公開する前に。のセクション 3 からの抜粋 出版チェックリスト:

リリース用のアプリケーションをビルドする前に、ログ記録を非アクティブ化し、デバッグ オプションを無効にしてください。ソース ファイル内の Log メソッドの呼び出しを削除することで、ロギングを非アクティブ化できます。

私のオープンソース プロジェクトは大規模なので、リリースするたびに手動で行うのは面倒です。さらに、ログ行の削除は、次のような場合に注意が必要になる可能性があります。

if(condition)
  Log.d(LOG_TAG, "Something");
data.load();
data.show();

ログ行をコメントすると、条件が次の行に適用され、load() が呼び出されない可能性があります。このような状況は存在すべきではないと判断できるほど稀な状況なのでしょうか?

では、ソースコードレベルでそれを行うより良い方法はあるのでしょうか?それとも、すべてのログ行を効率的かつ安全に削除するための賢い ProGuard 構文でしょうか?

役に立ちましたか?

解決

はるかに簡単な解決策は、すべてを忘れることだと思います if あちこちをチェックして、ただ使用してください プロガード 何かを取り除く Log.d() または Log.v() Ant を呼び出すときにメソッドが呼び出されます release 目標。

こうすることで、通常のビルドでは常にデバッグ情報が出力され、リリース ビルドではコードを変更する必要がなくなります。ProGuard は、バイトコード上で複数のパスを実行して、他の不要なステートメントや空のブロックを削除したり、必要に応じて短いメソッドを自動的にインライン化したりすることもできます。

たとえば、Android の非常に基本的な ProGuard 構成は次のとおりです。

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

-keep class * extends android.app.Activity
-assumenosideeffects class android.util.Log {
    public static *** d(...);
    public static *** v(...);
}

したがって、それをファイルに保存し、Ant から ProGuard を呼び出して、コンパイルしたばかりの JAR と使用している Android プラットフォーム JAR を渡します。

こちらも参照 ProGuard マニュアルに記載されています。


アップデート (4.5 年後): 最近私が使っていたのは 木材 Android のログ記録用。

デフォルトよりも少し優れているだけではありません Log 実装 — ログ タグは自動的に設定され、書式設定された文字列と例外を簡単にログに記録できます。ただし、実行時に異なるログ動作を指定することもできます。

この例では、ログ ステートメントはアプリのデバッグ ビルドでのみ logcat に書き込まれます。

木材は私の中に設置されています Application onCreate() 方法:

if (BuildConfig.DEBUG) {
  Timber.plant(new Timber.DebugTree());
}

その後、コード内の他の場所で簡単にログを記録できます。

Timber.d("Downloading URL: %s", url);
try {
  // ...
} catch (IOException ioe) {
  Timber.e(ioe, "Bad things happened!");
}

を参照してください。 木材サンプルアプリ より高度な例では、開発中にすべてのログ ステートメントが logcat に送信され、運用環境ではデバッグ ステートメントはログに記録されませんが、エラーは Crashlytics にサイレントに報告されます。

他のヒント

すべての良い答えが、私は、私はすべてのログ周りの文を呼び出して、また私は、外部ツールを使用したい場合はなかった。

のいずれかを使用したいdidn't私の開発を終了したとき

だから、I`mを使用したソリューションは、私自身のLogクラスでandroid.util.Logクラスを置き換えることです。

public class Log {
    static final boolean LOG = BuildConfig.DEBUG;

    public static void i(String tag, String string) {
        if (LOG) android.util.Log.i(tag, string);
    }
    public static void e(String tag, String string) {
        if (LOG) android.util.Log.e(tag, string);
    }
    public static void d(String tag, String string) {
        if (LOG) android.util.Log.d(tag, string);
    }
    public static void v(String tag, String string) {
        if (LOG) android.util.Log.v(tag, string);
    }
    public static void w(String tag, String string) {
        if (LOG) android.util.Log.w(tag, string);
    }
}

私はすべてのソースファイルにしなければならなかった唯一のことは、私自身のクラスにandroid.util.Logの輸入を置き換えることでした。

私は、ログに記録するかどうかを示すブール静的どこかを持つことをお勧め

class MyDebug {
  static final boolean LOG = true;
}

あなたのコードでログインしたい場所に続いて、ちょうどこの操作を行います。

if (MyDebug.LOG) {
  if (condition) Log.i(...);
}
あなたがfalseにMyDebug.LOGを設定すると、

さて、コンパイラは(それが静的な最終的なものであるため、それはコンパイル時にそのコードが使用されていない知っている。)このようなチェック内のすべてのコードを取り除きます。

大規模プロジェクトでは、個々のファイルでブールは、必要に応じて簡単にそこにログを有効または無効にすることができるようになる開始することをお勧めします。例えば、これらは、我々はウィンドウマネージャを持っている様々なログの定数です。

static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG_LAYERS = false;
static final boolean DEBUG_INPUT = false;
static final boolean DEBUG_INPUT_METHOD = false;
static final boolean DEBUG_VISIBILITY = false;
static final boolean DEBUG_WINDOW_MOVEMENT = false;
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;

のようなコードを対応する

    if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
        TAG, "Adding window " + window + " at "
        + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");

クリストファーさんProGuardのソリューションが最適ですが、何らかの理由であなたがProGuardのが気に入らない場合は、ここでは非常にローテクなソリューションです。

コメントログます:

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/Log\./;\/\/ Log\./g'

のコメントを外しログます:

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/;\/\/ Log\./Log\./g'

制約は、あなたのログ命令は複数行にまたがってはならないということです。

(プロジェクトのルートにUNIXシェルでこれらの行を実行します。Windowsを使用している場合、UNIX層を取得したり、Windowsのコマンドと同等を使用)

私は、最終的なバイナリからのログの行を削除する問題の多くを持っていたことから、AndroidのメーカーとのGradleでProGuardのを使用する方法についていくつかの精度を追加したいと思います。

ProGuardの作品でassumenosideeffectsを作るためには、前提条件があります。

あなたのGradleファイルでは、デフォルトのファイルとしてproguard-android-optimize.txtの使用を指定する必要があります。

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

        // With the file below, it does not work!
        //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

実際には、デフォルトのproguard-android.txtファイルで、最適化は、二つのフラグで無効になっています:

-dontoptimize
-dontpreverify

proguard-android-optimize.txtファイルには、これらの行を追加していないので、今assumenosideeffects作業することができます。

次に、personnally、私が使用して SLF4J に、すべてのより多くの時に私は他の人に配布されているいくつかのライブラリを開発。利点は、デフォルトでは出力がないということです。積分器は、いくつかのログ出力を望んでいる場合は、ログファイルにまたはLogCatにリダイレクトすることができますように、彼は、AndroidのためLogbackを使用してログを有効にすることができます。

私は本当に最後のライブラリーからログを除去する必要がある場合は(当然のproguard-android-optimize.txtファイルを有効にした後)

、私はその後、私のProGuardのファイルに追加します:

-assumenosideeffects class * implements org.slf4j.Logger {
    public *** trace(...);
    public *** debug(...);
    public *** info(...);
    public *** warn(...);
    public *** error(...);
}

私は非常にジェイクウォートンから木材を使用することをお勧めします。

https://github.com/JakeWharton/timber

これは、有効/無効にして問題を解決し、プラス自動的にタグクラスを追加します。

だけ

public class MyApp extends Application {

  public void onCreate() {
    super.onCreate();
    //Timber
    if (BuildConfig.DEBUG) {
      Timber.plant(new DebugTree());
    }
    ...

ログは、あなたのデバッグ版で使用され、その後、使用されます。

Timber.d("lol");

または

Timber.i("lol says %s","lol");

印刷する

タグをspecyfingせずに "あなたのクラス/ MSG"

私は<のhref = "https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/util/LogUtilsを使用していました。 Javaの」のrel = "nofollowを"> GoogleのIOサンプルアプリケーションのようにLogUtils のクラス。私は、これが代わりBuildConfig.DEBUGのアプリケーション特定DEBUG定数を使用するように改変ため BuildConfig .DEBUGは信頼できないのです。その後、私のクラスでは、私は次のことを持っています。

import static my.app.util.LogUtils.makeLogTag;
import static my.app.util.LogUtils.LOGV;

public class MyActivity extends FragmentActivity {
  private static final String TAG = makeLogTag(MyActivity.class);

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LOGV(TAG, "my message");
  }
}

私は、Android Studioユーザのために特別に適用されるこのソリューションを投稿しています。私も最近木材を発見し、次のようにして、私のアプリに成功し、それをインポートします:

あなたのbuild.gradleに、ライブラリの最新バージョンを入れます:

compile 'com.jakewharton.timber:timber:4.1.1'

次にAndroidのスタジオで、編集するために行く - >検索 - >

...パスに置き換えます

Log.e(TAG,に入力するか、あなたは"Text to find"テキストボックスにあなたのログメッセージを定義しているが。次に、あなただけのTimber.e(

と交換します

 loading=

"ここに画像の説明を入力します。

[検索]をクリックして、すべてを交換してください。

Androidのメーカーは現在、プロジェクト内のすべてのファイルを通過し、ティンバーですべてのログを置き換えます。

私はこの方法で持っていた唯一の問題は、それはあなたのjavaファイルのそれぞれについて、輸入では「木材」を見つけることができないためのGradleはその後witha万人のエラーメッセージが出てくるんです。ただ、エラーをクリックして、Androidのスタジオが自動的にあなたのjavaに「木材」をインポートします。すべてのあなたのエラーファイルのためにそれをやったら、Gradleでは、再度コンパイルされます。

あなたはまた、あなたのonCreateクラスのごApplication方法でコードのこの部分を配置する必要があります:

    if (BuildConfig.DEBUG) {
        Timber.plant(new Timber.DebugTree());
    }

これは、あなたが開発モードでない生産している場合にのみ、アプリケーションログになります。あなたはまた、リリースモードでログインするためのBuildConfig.RELEASEを持つことができます。

パーandroid.util.Log /無効のログを有効にする方法を提供します:

public static native boolean isLoggable(String tag, int level);

方法isLoggable(...)を使用すると、デバイスにのみに、SetProp後にこれを気に入って、falseを返すデフォルト

adb shell setprop log.tag.MyAppTag DEBUG

これはDEBUGレベル以上の任意のログをプリントアウトすることができることを意味します。アンドロイドドキュメントを参照します:

  

指定されたタグのログは、指定されたレベルでログ可能であるかどうかが調べられます。任意のタグのデフォルトのレベルが設定されています   INFOへ。これは、INFO以上とを含む任意のレベルになることを意味します   ログに記録。あなたがチェックすべきログメソッドへの呼び出しを行う前に、   あなたのタグをログに記録する必要があるかどうかを確認します。デフォルトのレベルを変更することができます   「に、SetProp log.tag:システムプロパティを設定することもできます。 "   レベルがVERBOSE、DEBUG、INFO、WARN、ERROR、ASSERT、またはどちらかである場合には   SUPPRESS。 SUPPRESSは、あなたのタグのすべてのログをオフにします。あなたはできる   また、その中で次のようにlocal.propファイルを作成します。   'log.tag。=' と/data/local.propでそれを置きます。

だから我々は、カスタムのutilをログを使用することができます

public final class Dlog 
{
    public static void v(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.VERBOSE))
            Log.v(tag, msg);
    }

    public static void d(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.DEBUG))
            Log.d(tag, msg);
    }

    public static void i(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.INFO))
            Log.i(tag, msg);
    }

    public static void w(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.WARN))
            Log.w(tag, msg);
    }

    public static void e(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.ERROR))
            Log.e(tag, msg);
    }
}

あなたは(一度)交換し、その後、いくつかのコーディング規約を守る、あなたは多くの場合、Androidのに使用されるパターンに従うことができます<のhref = "https://android.googlesource.com/platform/frameworks/グローバルを実行できる場合ベース/ + / 86628d4f122de740170388bc66e06b7825d6d461 /サービス/コア/ javaの/ COM /アンドロイド/サーバー/通知/ ZenModeConditions.java#66" のrel = "noreferrer">フレームワークでます。

の代わりに書いている。

Log.d(TAG, string1 + string2 + arg3.toString());

タグとしてそれを持っています
if (BuildConfig.DEBUG) Log.d(TAG, string1 + String.format("%.2f", arg2) + arg3.toString());

今ProGuardのは、最適化されたリリースDEXから、StringBuilderを、それが途中で使用するすべての文字列とメソッドを削除することができます。 proguard-android-optimize.txtを使用すると、あなたのproguard-rules.proのandroid.util.Log のを心配する必要はありません。

android {
  …
  buildTypes {
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
  }
}

AndroidのメーカーのGradleプラグインを使用すると、BuildConfig.DEBUGは非常に信頼性があるので、あなたは、ストリッピングを制御するために、余分な定数は必要ありません。

私は非常にシンプルなソリューションを持っています。私は開発のためのIntelliJを使用するので、詳細は異なりますが、アイデアは、すべてのIDEの間で適用されるべきである。

私は右クリックして「置換」を行うように選択し、自分のソースツリーのルートに選びます。私は、すべて置き換えることを選択し、「ログイン」を"//ログインします。" と。これは、すべてのログステートメントを削除します。後で、私は交換してください同じことを繰り返しますが、すべての置き換えとして、この時にそれらを元に戻すには、「//ログインします。」 "ログインします。" と。

私のためだけで素晴らしい作品。ちょうどのような事故を避けるために大文字と小文字を区別として置き換える設定することを忘れないでください「ダイアログを。」。追加保証のために、あなたはまた、との最初のステップ実行できる「ログを。」検索する文字列として。

ブリリアントます。

として、 zsergeさんのコメントには、

、提案しました
  

木材は非常にいいですが、あなたはすでに既存のプロジェクトを持っている場合 - あなたはgithub.com/zserge/logをしようとします。それはandroid.util.Logのドロップイン置換だと木材をさらに持ち、機能のほとんどを持っています。

以下のような簡単な有効/無効ログの印刷スイッチを提供する

彼のログライブラリます。

また、ののみimportラインを変更する必要があり、の何もないのはLog.d(...);文に変更する必要があります。

if (!BuildConfig.DEBUG)
    Log.usePrinter(Log.ANDROID, false); // from now on Log.d etc do nothing and is likely to be optimized with JIT

あなたの ProGuardの-rules.txt

ファイルに以下を追加します。
-assumenosideeffects class android.util.Log {
  public static *** d(...);
  public static *** w(...);
  public static *** v(...);
  public static *** i(...);
}

" ここに画像の説明を入力する

これは私が私のアンドロイドプロジェクトで行うために使用するものです..

Androidのメーカーでは、プロジェクト全体からMacOSの中に(コマンド+ Shiftキー+ F MacOSの中)とCtrl + + Rを交換するためにシフト((コマンド+ Shiftキー+ R)を見つけるために、同様の操作を、Ctrlキー+ Shiftキー+ Fで行うことができます)

Iは、異なるログ・レベルのサポートを提供することによって、コードは、ライブデバイスまたはエミュレータ上で実行されている場合に応じて自動的にログレベルを変更することにより、上記溶液に改善している。

public class Log {

final static int WARN = 1;
final static int INFO = 2;
final static int DEBUG = 3;
final static int VERB = 4;

static int LOG_LEVEL;

static
{
    if ("google_sdk".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT)) {
        LOG_LEVEL = VERB;
    } else {
        LOG_LEVEL = INFO;
    }

}


/**
 *Error
 */
public static void e(String tag, String string)
{
        android.util.Log.e(tag, string);
}

/**
 * Warn
 */
public static void w(String tag, String string)
{
        android.util.Log.w(tag, string);
}

/**
 * Info
 */
public static void i(String tag, String string)
{
    if(LOG_LEVEL >= INFO)
    {
        android.util.Log.i(tag, string);
    }
}

/**
 * Debug
 */
public static void d(String tag, String string)
{
    if(LOG_LEVEL >= DEBUG)
    {
        android.util.Log.d(tag, string);
    }
}

/**
 * Verbose
 */
public static void v(String tag, String string)
{
    if(LOG_LEVEL >= VERB)
    {
        android.util.Log.v(tag, string);
    }
}


}

ProGuardのは、あなたのリリースビルドとなりましandroid.comから良いニュースをあなたのためにそれを行います

http://developer.android.com/tools/help/proguard.html

ProGuardのツールは、縮小最適化し、未使用のコードを削除し、意味的にあいまいな名前のクラス、フィールド、メソッドの名前を変更することで、あなたのコードを難読化。結果は、リバースエンジニアリングすることはより困難である小さいサイズの.apkファイルです。 ProGuardのはエンジニアを逆にするアプリケーション難しくなりますので、それはあなたのアプリケーションは、あなたがあなたのアプリケーションのライセンスしているときのように、セキュリティに敏感な機能を利用するとき、あなたがそれを使用することが重要です。

ProGuardのは、Androidのビルドシステムに統合されているので、あなたはそれを手動で起動する必要はありません。 ProGuardのは、あなたがデバッグモードでアプリケーションをビルドする際に難読化されたコードに対処する必要はありませんので、あなたは、リリースモードでアプリケーションをビルドするときにのみ実行されます。 ProGuardの実行を持つことは完全に任意ですが、強くお勧めします。

この文書では、難読化されたスタックトレースをデコードすることを可能とProGuardの設定だけでなく、帰ツールを使用する方法について説明します。

私はLog.d(TAG、いくつかの文字列、しばしばString.Formatの())を使用するようにしたい。

タグは常にクラス名です。

Log.d(TAGを変換し、 - >のlogD(あなたのクラスのテキストで

private void Logd(String str){
    if (MainClass.debug) Log.d(className, str);
}

あなたはリリースバージョンを作成する準備ができているこの方法では、falseにMainClass.debugを設定!

ログは、Linuxではbashを使用して除去し、sedをすることができます:

find . -name "*\.java" | xargs sed -ri ':a; s%Log\.[ivdwe].*\);%;%; ta; /Log\.[ivdwe]/ !b; N; ba'

複数行のログのための作品集。このソリューションでは、ログは製品コードに存在しないことを、確認することができます。

私は、これは古い質問ですけど、なぜあなたのようなもので、すべてのログ呼び出しを置き換えるものではありませんでした ブールlogCallWasHere =はtrue。 // ---ここにあなたのログの残りの部分

この理由を、あなたが戻ってそれらを配置するときに知っているだろう、と彼らはあなたのif文の呼び出しには影響しません。)

だけでないのはなぜ

if(BuildConfig.DEBUG)
  Log.d("tag","msg");

?あなたはリリースビルドを行うときに必要な追加のライブラリは、プロジェクトおよびJavaコンパイラを台無しにする傾向がある何ProGuardのルールは、ちょうどこのコールのためのバイトコードを除外しません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top