Android 앱의 릴리스 버전을 구축하기 전에 모든 디버그 로깅 통화를 제거하는 방법은 무엇입니까?

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

문제

구글에 따르면, 나는 "소스 코드에서 메소드 로그로 통화를 비활성화합니다."내 Android 앱을 Google Play에 게시하기 전에. 게시 체크리스트:

릴리스 신청서를 작성하기 전에 로깅을 비활성화하고 디버깅 옵션을 비활성화해야합니다. 소스 파일의 로그 메소드로 호출을 제거하여 로깅을 비활성화 할 수 있습니다.

내 오픈 소스 프로젝트는 크며 출시 할 때마다 수동으로 수행하는 것은 고통입니다. 또한 로그 라인을 제거하는 것은 잠재적으로 까다 롭습니다.

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

로그 라인에 주석을 달면 조건이 다음 줄에 적용되며 롯지 ()가 호출되지 않을 가능성이 있습니다. 그러한 상황은 존재하지 않아야한다고 결정할 수있을 정도로 희귀합니까?

그렇다면 더 나은 소스 코드 레벨 방법이 있습니까? 아니면 모든 로그 라인을 효율적으로하지만 안전하게 제거하기 위해 영리한 Proguard 구문이 있을까요?

도움이 되었습니까?

해결책

훨씬 쉬운 해결책은 모든 것을 잊어 버리는 것입니다. if 모든 곳에서 확인하고 사용하십시오 대리자 어떤 것도 제거합니다 Log.d() 또는 Log.v() 방법 호출 우리가 개미를 호출 할 때 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를 호출하여 방금 컴파일 된 항아리와 사용중인 Android 플랫폼 용기를 통과합니다.

또한보십시오 Proguard 매뉴얼에서.


업데이트 (4.5 년 후) : 요즘 내가 사용했습니다 재목 안드로이드 로깅의 경우.

기본값보다 조금 더 좋은 것뿐만 아니라 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로 전송되고 생산시 디버그 문장이 기록되지 않지만 오류는 충돌로부터 조용히보고됩니다.

다른 팁

모든 좋은 답변이지만 개발이 끝났을 때 모든 로그 통화에 대한 문장을 사용하고 싶지도 않았거나 외부 도구를 사용하고 싶지 않았습니다.

따라서 내가 사용하는 솔루션은 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(...);
}

이제 mydebug.log를 False로 설정하면 컴파일러는 그러한 확인 내부의 모든 코드를 제거합니다 (정적 최종이므로 컴파일 시간에 코드가 사용되지 않는다는 것을 알고 있습니다.)

대규모 프로젝트의 경우, 필요에 따라 로깅을 쉽게 활성화하거나 비활성화 할 수 있도록 개별 파일에 부울을 시작할 수 있습니다. 예를 들어, 이들은 Window Manager에있는 다양한 로깅 상수입니다.

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 + ")");

Christopher 's 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 Studio 및 Gradle과 함께 Proguard를 사용하는 것에 대한 정밀도를 추가하고 싶습니다.

만들기 위해서 assumenosideeffects Proguard Works에는 전제 조건이 있습니다.

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 일할 수있다.

그런 다음 개인적으로 사용합니다 SLF4J, 다른 사람들에게 배포되는 일부 라이브러리를 개발할 때 더 많은 것입니다. 장점은 기본적으로 출력이 없다는 것입니다. 통합기가 일부 로그 출력을 원한다면 Android에 로그백을 사용하고 로그를 활성화 할 수 있으므로 로그를 파일 또는 로그 캣으로 리디렉션 할 수 있습니다.

최종 라이브러리에서 로그를 제거해야한다면 Proguard 파일에 추가합니다 (활성화 한 후 proguard-android-optimize.txt 물론 파일) :

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

Jake Wharton의 목재를 사용하는 것이 좋습니다

https://github.com/jakewharton/timber

활성화/비활성화로 문제를 해결하고 태그 클래스를 자동으로 추가합니다.

단지

public class MyApp extends Application {

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

로그는 디버그 ver에서만 사용 된 다음 사용합니다.

Timber.d("lol");

또는

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

인쇄

태그를 스펙 핑하지 않고 "당신의 클래스 / msg"

나는 사용했다 logutils Google IO 예제 응용 프로그램과 같은 클래스. BuildConfig.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");
  }
}

나는 Roboguice를 사용하는 것을 고려할 것입니다 벌목 시설 내장 된 Android.util.log 대신

해당 시설은 릴리스 빌드에 대한 디버그 및 장방 로그를 자동으로 비활성화합니다. 또한 무료로 멋진 기능을 제공합니다 (예 : 사용자 정의 가능한 로깅 동작, 모든 로그에 대한 추가 데이터 등)

Proguard를 사용하는 것은 상당히 번거 로울 수 있으며 나는 그것을 구성하고 만드는 데 어려움을 겪지 않을 것입니다. 일하다 그 이유가없는 한 신청서를 사용하면 (로그를 비활성화하는 것이 좋지 않습니다)

Android Studio 사용자에게 특별히 적용되는이 솔루션을 게시하고 있습니다. 또한 최근에 목재를 발견하고 다음을 수행하여 내 앱으로 성공적으로 가져 왔습니다.

라이브러리의 최신 버전을 Build.gradle에 넣으십시오.

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

그런 다음 Android Studios에서 편집 -> 찾기 -> 경로에서 교체하십시오 ...

입력하십시오 Log.e(TAG, 또는 로그 메시지를 "Text to find" 텍스트 상자. 그런 다음 그냥 교체하십시오 Timber.e(

enter image description here

찾기를 클릭 한 다음 모두 교체하십시오.

Android Studios는 이제 프로젝트의 모든 파일을 거쳐 모든 로그를 목재로 교체합니다.

이 방법으로 내가 가진 유일한 문제는 Gradle이 각 Java 파일의 가져 오기에서 "목재"를 찾을 수 없기 때문에 나중에 백만 개의 오류 메시지를 제시한다는 것입니다. 오류를 클릭하면 Android Studios가 자동으로 "목재"를 Java로 가져옵니다. 모든 오류 파일에 대해 완료하면 Gradle이 다시 컴파일됩니다.

또한이 코드를 귀하의 onCreate 당신의 방법 Application 수업:

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

이로 인해 앱은 개발 모드가 생산되지 않은 경우에만 로깅됩니다. 당신은 또한 가질 수 있습니다 BuildConfig.RELEASE 릴리스 모드로 로그를 위해.

per android.util.log는 로그를 활성화/비활성화하는 방법을 제공합니다.

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

기본값 isloggable (...) 메소드가 거짓을 반환합니다.

adb shell setprop log.tag.MyAppTag DEBUG

이는 디버그 레벨 위의 모든 로그를 인쇄 할 수 있음을 의미합니다. 참조 안드로이드 문서 :

지정된 태그에 대한 로그가 지정된 레벨에서 로그가 가능한지 여부를 확인합니다. 모든 태그의 기본 레벨이 정보로 설정됩니다. 이는 위의 모든 레벨과 정보를 포함하여 모든 수준이 기록됩니다. 로깅 메소드에 호출하기 전에 태그를 기록 해야하는지 확인해야합니다. 시스템 속성을 설정하여 기본 레벨을 변경할 수 있습니다 : 'SetProp log.tag. '레벨이 장점, 디버그, 정보, 경고, 오류, 주장 또는 억제되는 경우. 억압은 태그의 모든 로깅을 끄게합니다. 다음과 같은 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에서 자주 사용되는 패턴을 따를 수 있습니다. 뼈대.

글쓰기 대신

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

그것을 가지고 있습니다

if (BuildConfig.DEBUG) Log.d(TAG, string1 + String.format("%.2f", arg2) + arg3.toString());

이제 Proguard는 StringBuilder와 최적화 된 릴리스 DEX에서 사용하는 모든 문자열과 방법을 제거 할 수 있습니다. 사용 proguard-android-optimize.txt 그리고 당신은 걱정할 필요가 없습니다 Android.util.log 당신의 proguard-rules.pro:

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

Android Studio Gradle 플러그인을 사용하여 BuildConfig.디버그 매우 신뢰할 수 있으므로 스트리핑을 제어하기 위해 여분의 상수가 필요하지 않습니다.

매우 간단한 솔루션이 있습니다. 나는 개발에 Intellij를 사용하므로 세부 사항은 다양하지만 아이디어는 모든 IDE에 적용되어야합니다.

소스 트리의 루트를 선택하고 마우스 오른쪽 버튼을 클릭하고 "교체"를 선택합니다. 그런 다음 모든 "로그"를 교체하도록 선택합니다. "// log." 이것은 모든 로그 문을 제거합니다. 나중에 다시 넣기 위해 나는 동일한 교체를 반복하지만 이번에는 모든 "// log"를 교체합니다. "로그"와 함께.

나에게 잘 작동합니다. "대화"와 같은 사고를 피하기 위해 교체를 대체 민감한 것으로 설정하는 것을 잊지 마십시오. 추가 보증을 위해 "로그"를 사용하여 첫 번째 단계를 수행 할 수도 있습니다. 검색의 문자열로.

훌륭한.

처럼 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(...);
}

enter image description here

이것이 제가 안드로이드 프로젝트에서했던 것입니다 ..

Android Studio에서는 CTRL+SHIFT+F의 유사한 작업을 수행하여 전체 프로젝트 (MACOS의 명령+SHIFT+F) 및 CTRL+SHIFT+R을 대체 할 수 있습니다 ((MACOS의 명령+SHIFT+R)

다른 로그 레벨에 대한 지원을 제공하고 코드가 라이브 장치 또는 에뮬레이터에서 실행되는지에 따라 로그 레벨을 자동으로 변경하여 위의 솔루션을 개선했습니다.

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 Tool은 사용하지 않은 코드를 제거하고 의미 적으로 모호한 이름을 가진 클래스, 필드 및 메소드를 이름을 바꾸어 코드를 축소, 최적화 및 난민합니다. 결과는 리버스 엔지니어가 더 어려운 작은 크기의 .apk 파일입니다. Proguard는 응용 프로그램을 역 엔지니어링하기가 더 어려워지기 때문에 응용 프로그램을 라이센스 할 때와 같이 보안에 민감한 기능을 사용하는 경우 응용 프로그램을 사용하는 것이 중요합니다.

Proguard는 Android 빌드 시스템에 통합되어 있으므로 수동으로 호출 할 필요가 없습니다. Proguard는 릴리스 모드에서 응용 프로그램을 구축 할 때만 실행되므로 디버그 모드에서 응용 프로그램을 빌드 할 때 난독 화 된 코드를 처리 할 필요가 없습니다. Proguard Run이있는 것은 완전히 선택 사항이지만 적극 권장됩니다.

이 문서는 Proguard를 활성화하고 구성하는 방법에 대해 설명하고 역전 도구를 사용하여 난독 화 된 스택 추적을 해독합니다.

log.d (태그, 일부 문자열, 종종 string.format ())를 사용하는 것을 좋아합니다.

태그는 항상 클래스 이름입니다

transform log.d (tag, -> logd (클래스 텍스트에서

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

릴리스 버전을 만들 준비가되면 MainClass.debug를 False로 설정하십시오!

Linux에서 Bash를 사용하여 로그를 제거하고 SED를 제거 할 수 있습니다.

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

다중 로그에 대해 작동합니다. 이 솔루션에서는 로그가 생산 코드에 존재하지 않는지 확인할 수 있습니다.

나는 이것이 오래된 질문이라는 것을 알고 있지만, 왜 모든 로그 통화를 부울 로그 콜 워시르 = 참으로 바꾸지 않았는지; // --- 여기에 나머지 로그

이것은 당신이 언제 당신이 그들을 다시 넣고 싶은지 알게 될 것입니다. 그리고 그들은 당신의 if 문장에 영향을 미치지 않을 것입니다 :)

그냥하지 않는 이유

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

? 추가 라이브러리가 필요하지 않으며 프로젝트를 망치는 경향이있는 Proguard 규칙은 없으며 Java 컴파일러는 릴리스 빌드를 할 때이 통화를 위해 바이트 코드를 남기지 않습니다.

가장 간단한 방법;

사용 DebugLog

앱이 해제되면 디버그 로그에 의해 모든 로그가 비활성화됩니다.

https://github.com/mustafaferhan/debuglog

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top