Android 앱의 릴리스 버전을 빌드하기 전에 모든 디버그 로깅 호출을 제거하는 방법은 무엇입니까?
Google에 따르면 Android 앱을 Google Play에 게시하기 전에 " 소스 코드에서 Log 메소드 호출을 비활성화 "해야합니다 . 발행 체크리스트 의 섹션 3에서 추출하십시오 .
릴리스 할 응용 프로그램을 빌드하기 전에 로깅을 비활성화하고 디버깅 옵션을 비활성화하십시오. 소스 파일에서 Log 메소드에 대한 호출을 제거하여 로깅을 비활성화 할 수 있습니다.
내 오픈 소스 프로젝트는 규모가 크며 릴리스 할 때마다 수동으로 수행하기가 어렵습니다. 또한 다음과 같이 로그 줄을 제거하는 것이 까다로울 수 있습니다.
if(condition)
Log.d(LOG_TAG, "Something");
data.load();
data.show();
Log 줄을 주석 처리하면 조건이 다음 줄에 적용되고 기회는 load ()가 호출되지 않습니다. 그런 상황이 존재하지 않아야한다고 결정할 수있을 정도로 드문 일입니까?
그렇다면 더 나은 소스 코드 수준의 방법이 있습니까? 또는 모든 Log 행을 효율적이지만 안전하게 제거하는 영리한 ProGuard 구문입니까?
나는 훨씬 쉽게 솔루션은 모든 잊지 찾을 if
여기 저기 검사를 그냥 사용 ProGuard에서을 어떤 밖으로 제거하기 위해서 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를 호출하여 방금 컴파일 한 JAR과 사용중인 Android 플랫폼 JAR을 전달합니다.
ProGuard 매뉴얼 의 예제 도 참조하십시오 .
업데이트 (4.5 년 후) : 요즘에는 Android 로깅에 Timber 를 사용했습니다 .
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에 자동으로보고되는 고급 예제 는 Timber 샘플 앱 을 참조하십시오 .
모든 좋은 대답이지만 개발이 끝나면 모든 Log 호출에 if 문을 사용하거나 외부 도구를 사용하고 싶지 않았습니다.
그래서 내가 사용하는 해결책은 android.util.Log 클래스를 내 자신의 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 가져 오기를 내 클래스로 바꾸는 것입니다.
로깅 여부를 나타내는 정적 부울을 사용하는 것이 좋습니다.
MyDebug 클래스 { 정적 최종 부울 LOG = true; }
그런 다음 코드에 로그인하려는 위치에 다음을 수행하십시오.
if (MyDebug.LOG) { if (조건) Log.i (...); }
이제 MyDebug.LOG를 false로 설정하면 컴파일러는 이러한 검사 내부의 모든 코드를 제거합니다 (정적 최종이므로 컴파일 타임에 코드가 사용되지 않음을 알고 있음).
대규모 프로젝트의 경우 필요에 따라 로깅을 쉽게 활성화 또는 비활성화 할 수 있도록 개별 파일에 부울을 갖기를 시작할 수 있습니다. 예를 들어, 창 관리자에있는 다양한 로깅 상수는 다음과 같습니다.
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의 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 작품 을 만들기 위해서는 전제 조건이 있습니다.
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 용 Logback을 사용하고 로그를 활성화하여 로그를 파일 또는 LogCat으로 경로 재 지정할 수 있습니다.
최종 라이브러리에서 로그를 제거해야하는 경우 파일을 활성화 한 후 Proguard 파일에 추가합니다 proguard-android-optimize.txt
.
-assumenosideeffects class * implements org.slf4j.Logger {
public *** trace(...);
public *** debug(...);
public *** info(...);
public *** warn(...);
public *** error(...);
}
Jake Wharton의 Timber를 사용하는 것이 좋습니다.
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");
인쇄
태그를 지정하지 않은 "귀하의 클래스 / msg"
Google IO 예제 응용 프로그램에서와 같이 LogUtils 클래스를 사용했습니다 . BuildConfig.DEBUG가 신뢰할 수 없기 때문에 BuildConfig.DEBUG 대신 응용 프로그램 특정 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.util.Log 대신 roboguice의 로깅 기능을 사용하는 것이 좋습니다.
이 기능은 릴리스 빌드에 대한 디버그 및 상세 로그를 자동으로 비활성화합니다. 또한 무료로 멋진 기능을 사용할 수 있습니다 (예 : 사용자 정의 가능한 로깅 동작, 모든 로그에 대한 추가 데이터 등)
proguard를 사용하는 것은 매우 번거로울 수 있으며 그 이유가 없으면 응용 프로그램에서 응용 프로그램 을 구성하고 작동 하는 데 어려움을 겪지 않을 것입니다.
Android Studio 사용자에게 특별히 적용되는이 솔루션을 게시하고 있습니다. 또한 최근에 Timber를 발견하고 다음을 수행하여 성공적으로 내 앱으로 가져 왔습니다.
최신 버전의 라이브러리를 build.gradle에 넣습니다.
compile 'com.jakewharton.timber:timber:4.1.1'
그런 다음 Android Studio에서 편집-> 찾기-> 경로에서 바꾸기 ...로 이동하십시오.
텍스트 상자에 Log.e(TAG,
로그 메시지를 입력 하거나 정의하십시오 "Text to find"
. 그런 다음Timber.e(
찾기를 클릭 한 다음 모두 바꿉니다.
Android Studios는 이제 프로젝트의 모든 파일을 살펴보고 모든 로그를 목재로 바꿉니다.
이 방법으로 내가 가진 유일한 문제는 gradle이 각 Java 파일의 가져 오기에서 "Timber"를 찾을 수 없기 때문에 나중에 백만 개의 오류 메시지를 표시한다는 것입니다. 오류를 클릭하면 Android Studio가 자동으로 "Timber"를 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는 태그에 대한 모든 로깅을 해제합니다. 'log.tag. ='에 local.prop 파일을 작성하여 /data/local.prop에 배치 할 수도 있습니다.
따라서 우리는 사용자 정의 로그 유틸리티를 사용할 수 있습니다 :
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는 최적화 된 릴리스 DEX에서 StringBuilder와 사용중인 모든 문자열 및 메소드를 제거 할 수 있습니다. 사용 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.DEBUG
매우 간단한 해결책이 있습니다. 개발에는 IntelliJ를 사용하므로 세부 사항은 다양하지만 아이디어는 모든 IDE에 적용되어야합니다.
소스 트리의 루트를 선택하고 마우스 오른쪽 단추를 클릭 한 후 "바꾸기"를 선택하십시오. 그런 다음 모든 "로그"를 바꾸도록 선택합니다. "// Log."와 함께. 모든 로그 문이 제거됩니다. 나중에 다시 넣으려면 동일한 바꾸기를 반복하지만 이번에는 모든 "// Log"를 바꾸십시오. "로그"와 함께.
나에게만 잘 작동합니다. "대화 상자"와 같은 사고를 피하기 위해 대소 문자를 구분하여 교체를 설정하십시오. 추가 보증을 위해 "로그"를 사용하여 첫 번째 단계를 수행 할 수도 있습니다. 검색 할 문자열로.
훌륭한.
으로 zserge의 의견은 제안,
목재는 매우 훌륭하지만 이미 기존 프로젝트가있는 경우 github.com/zserge/log를 사용해보십시오. android.util.Log의 드롭 인 대체품이며 Timber의 기능과 그 밖의 기능을 대부분 갖추고 있습니다.
그의 로그 라이브러리 는 아래와 같이 간단한 활성화 / 비활성화 로그 인쇄 스위치를 제공합니다.
또한, 단지 변경을 요구 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 Studio에서는 Ctrl + Shift + F를 사용하여 전체 프로젝트 (MacO의 경우 Command + Shift + F)와 Ctrl + Shift + R (대체 (MacO의 경우 Command + 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
The ProGuard tool shrinks, optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and methods with semantically obscure names. The result is a smaller sized .apk file that is more difficult to reverse engineer. Because ProGuard makes your application harder to reverse engineer, it is important that you use it when your application utilizes features that are sensitive to security like when you are Licensing Your Applications.
ProGuard is integrated into the Android build system, so you do not have to invoke it manually. ProGuard runs only when you build your application in release mode, so you do not have to deal with obfuscated code when you build your application in debug mode. Having ProGuard run is completely optional, but highly recommended.
This document describes how to enable and configure ProGuard as well as use the retrace tool to decode obfuscated stack traces
I like to use Log.d(TAG, some string, often a String.format ()).
TAG is always the class name
Transform Log.d(TAG, --> Logd( in the text of your class
private void Logd(String str){
if (MainClass.debug) Log.d(className, str);
}
In this way when you are ready to make a release version, set MainClass.debug to false!
Logs can be removed using bash in linux and sed:
find . -name "*\.java" | xargs sed -ri ':a; s%Log\.[ivdwe].*\);%;%; ta; /Log\.[ivdwe]/ !b; N; ba'
Works for multiline logs. In this solution you can be sure, that logs are not present in production code.
I know this is an old question, but why didn't you replace all your log calls with something like Boolean logCallWasHere=true; //---rest of your log here
This why you will know when you want to put them back, and they won't affect your if statement call :)
Why not just do
if(BuildConfig.DEBUG)
Log.d("tag","msg");
? 추가 라이브러리가 필요없고 프로젝트를 망치는 경향이있는 proguard 규칙이 없으며 Java 컴파일러는 릴리스 빌드를 할 때이 호출에 대한 바이트 코드를 남기지 않습니다.
가장 간단한 방법;
사용하다 DebugLog
앱이 출시되면 DebugLog에 의해 모든 로그가 비활성화됩니다.
https://github.com/MustafaFerhan/DebugLog
'Programing' 카테고리의 다른 글
Oracle에서 AUTO_INCREMENT로 ID를 만드는 방법은 무엇입니까? (0) | 2020.02.26 |
---|---|
Rails 3.1에서 자산 파이프 라인 (스프로킷) 메시지 로깅을 비활성화하는 방법은 무엇입니까? (0) | 2020.02.26 |
Git에서 어떤 커밋을 가리키는 지 어떻게 알 수 있습니까? (0) | 2020.02.26 |
비어 있거나 null JSTL c 태그 평가 (0) | 2020.02.26 |
내부 대 개인 액세스 수정 자 (0) | 2020.02.26 |