Як видалити всі виклики в журналі налагодження перед створенням версії додатка для Android?


397

За словами Google, я повинен " деактивувати будь-які дзвінки до методів журналу у вихідному коді ", перш ніж публікувати свій додаток Android в Google Play. Витяг із розділу 3 контрольного списку публікацій :

Переконайтеся, що ви відключили ведення журналу та відключили параметр налагодження перед тим, як створити свою програму для випуску. Ви можете відключити ведення журналу, видаливши дзвінки до методів журналу у вихідних файлах.

Мій проект з відкритим кодом великий і болю робити це вручну щоразу, коли випускаю. Крім того, видалити рядок журналу потенційно складно, наприклад:

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

Якщо я коментую рядок Журналу, то умова застосовується до наступного рядка, і шанси, що load () не викликається. Чи такі ситуації досить рідкісні, що я можу вирішити, що вони не існують?

Отже, чи є кращий спосіб на рівні вихідного коду це зробити? А може, якийсь розумний синтаксис ProGuard для ефективного, але безпечного видалення всіх ліній журналу?


2
+1, тому що я не пам’ятав цього про перелік публікацій.
rds

51
Щоб коментувати незаблокований рядок, я використовую "; //" замість "//".
проголошено

Якщо вам потрібно буде скасувати це, ви, ймовірно, захочете скористатися sed 's_^\(\s*Log\.\)_;//'`date|tr -s \ -`'\1_g'натомість.
проголошено

2
Посилання, яке додав Димитър, більше не працює. Я знайшов це замість source.android.com/source/code-style.html#log-sparingly .
JosephL

1
@mboy: Напевно, для продуктивності в основному нині, але для старих версій Android це також має переваги безпеки.
Ніколя Рауль

Відповіді:


488

Я вважаю, що набагато простіше рішення - це забути всі ifперевірки всюди і просто використовувати ProGuard, щоб викреслити будь-які дзвінки Log.d()або Log.v()методи, коли ми зателефонуємо на нашу releaseціль Ant .

Таким чином, у нас завжди є інформація про налагодження, яка виводиться для регулярних збірок, і не потрібно вносити будь-які зміни коду для версій версій. ProGuard також може робити кілька проходів через байт-код для видалення інших небажаних операторів, порожніх блоків та може автоматично вбудовувати короткі методи, де це доречно.

Наприклад, ось дуже простий конфігурація ProGuard для Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Таким чином, ви збережете це у файл, а потім зателефонуйте ProGuard від Ant, перейшовши у ваш щойно складений JAR та платформу JAR Android, яку ви використовуєте.

Дивіться також приклади в посібнику 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!");
}

Докладніший приклад дивіться у прикладі програми Timber , де всі заяви журналу надсилаються в logcat під час розробки, а у виробництві не записуються заяви про налагодження, але про помилки повідомляється Crashlytics.


59
І чому це не в файлі proguard за замовчуванням?
rds

10
+ rds, оскільки це дозволить зробити номери рядків у виробництві стеками різними, ніж у вашому коді, оскільки рядки видаляються.
Хлопець

5
Я можу підтвердити, що відключення дзвінків з журналу змінює номери ліній в стек. Це не завжди буде синхронізовано (я зробив декілька швидких тестів, але не можу точно визначити причину, можливо, якщо ви об'єднаєте рядок у журнал виклику), але іноді це буде кілька рядків відключення. Варто неприємностей IMO за можливість легко видаляти журнали викликів.
Тоні Чан

5
@Fraggle From proguard-android.txt в інструментах ADT: "Зауважте, що якщо ви хочете включити оптимізацію, ви не можете просто включити прапори оптимізації у свій власний файл конфігурації проекту; натомість вам потрібно буде вказати на" proguard-android-optimize. txt "файл замість цього з вашого" # project.properties файлу.
Раана

3
Як сказано нижче у відповіді. "Єдина проблема такого підходу полягає в тому, що якщо ви робите Log.d (" тег "," Обробляється: "+ новий ItemCounter (blabla) +" елементи "), навіть якщо це повідомлення журналу не відображається у вашій версії, StringBuilder використовується для створення повідомлення, яке може бути дорогим для створення. "Це правда і у випадку з Timber?
Читранг

117

Усі хороші відповіді, але коли я закінчив свою розробку, я не хотів ні використовувати, якщо заяви навколо всіх журналів викликів, ні я не хотів використовувати зовнішні інструменти.

Таким чином, я використовую рішення - замінити клас 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 моїм власним класом.


143
Єдина проблема такого підходу полягає в тому, що якщо ви робите Log.d ("тег", "Обробляється:" + новий ItemCounter (blabla) + "елементи"), навіть якщо це повідомлення журналу не відображається у вашій випущеній версії, a StringBuilder використовується для створення повідомлення, яке може бути дорогим для створення.
espinchi

9
Це рішення має велику проблему. espinchi згадав лише верхівку айсберга. Проблема полягає в тому, що коли ви зателефонуєте, Log.d("tag", someValue.toString());що забути перевірити деякий Value на те, що він не є нульовим, це дуже просто, що означає, що це може призвести до NullPointerExceptionвиробництва. Це пропонує безпечне рішення, але це обмане вас. Ми нам private static boolean DEBUGа потімif(DEBUG)Log.d(TAG, msg);
Філіпп

2
@espinchi Ваше занепокоєння , здається, відноситься до всіх бібліотек лісозаготівельних , як обговорювалося в цій відповіді stackoverflow.com/a/15452492/433718 (SLF4J, що накопичилися, ...). Чи не пропонується їх використовувати?
OneWorld

1
Єдиний спосіб мінімізувати накладні витрати, згадані в 1-му коментарі від @espinchi, - це змінити способи ведення журналу, щоб замість них прийняти varargs String. Тут описано повне рішення . Це, мабуть, має ще один недолік: кожен виклик повинен бути відредагований (не лише одна лінія імпорту).
Стен

21
Просто FYI, якщо ви використовуєте Android Studio та систему збирання gradle, ви можете використовувати static final boolean LOG = BuildConfig.DEBUGта не потребувати змін цього файлу ніколи.
ашишдух

61

Я пропоную стати статичним булевим десь із зазначенням, чи потрібно входити чи ні:

клас MyDebug {
  статичний кінцевий булевий LOG = вірно;
}

Тоді, куди ви хочете увійти в свій код, просто зробіть це:

якщо (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 + ")");

1
Я б також проголосував за такий підхід. Він також використовується в офіційному зразку виставлення рахунків через додаток Google.
LA_

4
Чи не було б менш багатослівним передавати умову як перший параметр?
Snicolas

1
Це здається найкращим рішенням, хоча для кожного оператора журналу потрібен додатковий код: Номери рядків зберігаються (слабкість підходу ProGuard), не створюється код для створення журнального повідомлення ( слабкість підходу класу обгортки і, мабуть, також підхід до бібліотеки журналів) . Використання такого підходу в Googles у зразку виставлення рахунків за додатками згідно @LA_ також підтримує мої думки.
OneWorld

2
@Snicolas Як можна передати умову як перший параметр, не застосовуючи обгортку? Більше того, якщо ви додасте його як параметр, то перед тим, як ввести метод, необхідно оцінити всі параметри, тобто також рядок повідомлення. Стан потрібно перевірити, перш ніж будувати параметри. Запропоноване рішення, можливо, є найкращим, якщо немає зовнішніх інструментів.
type-a1pha

2
Бінарний код мудрий, це найкраще. Але таке кодування просто багато зусиль для простого виводу журналу налагодження. Читання коду значно падає. Виграй дещо, програй, я думаю ...
Річард Ле Месюр'є

30

Рішення 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)


1
потрібен "" після -і в Sed, якщо він працює на Mac (відповідно до цього ) Дякую
Вішал

Я відчуваю, що це може бути те, що я в кінцевому підсумку використовую для чогось, над чим працюю, тому що мені зовсім не пощастило робити це з Proguard
Джо Плант

А що робити, якщо у вас є журнал після відмітки, що не міститься у коді, як ви запропонували у своєму першому дописі?
type-a1pha

@ type-a1pha: Якщо ви приймаєте це рішення, вам доведеться вважати брекет-блоки обов'язковими.
Nicolas Raoul

2
@NicolasRaoul Напівколона виправляє це питання ( //проти ;//)
Alex Gittemeier

18

Я хотів би додати деякі вказівки щодо використання Proguard з Android Studio та gradle, оскільки у мене було чимало проблем із видаленням рядків журналів із остаточного бінарного файлу.

Для того, щоб зробити 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 , тим більше, коли розробляю одні бібліотеки, які поширюються на інші. Перевага полягає в тому, що за замовчуванням виходу немає. І якщо інтегратор бажає певних результатів журналу, він може використовувати Logback для Android та активувати журнали, тому журнали можна перенаправляти на файл або на LogCat.

Якщо мені дійсно потрібно зняти журнали з кінцевої бібліотеки, я додаю до свого файлу Proguard (після того, як увімкнув proguard-android-optimize.txtфайл звичайно):

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

Це не працює з новим компілятором Jack-- stackoverflow.com/questions/37932114/…
fattire

Це мені допомогло; і те й іншеproguard-android-optimize.txt файл Proguard за замовчуванням, так і -assumenosideeffectsв користувацькому файлі Proguard були потрібні! Я використовую shinker R8 (за замовчуванням сьогодні) та журнал Android за замовчуванням.
Джонік

10

Я настійно пропоную використовувати пиломатеріали від Джейка Уортона

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" без специфікації тегу


2
Пиломатеріали дуже приємні, але якщо у вас вже є проект - ви можете спробувати github.com/zserge/log . Це замінна версія для android.util.Log і має більшість функцій, які має Timber і навіть більше.
zserge

zserge, ваше журнальне рішення виглядає добре. Багато функцій. Чи обмірковували Ви додавати такі правила, як у Timber?
jk7

8

Я використав клас LogUtils, як у прикладі програми IO Google. Я змінив це, щоб використовувати константну програму DEBUG замість 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");
  }
}

+1 для звіту про помилку, Build.DEBUGякий я використовував. Я також відмовився від різних «правильних» способів вирішення проблем і застосував для вас подібне стильове рішення.
Річард Ле Месюр'є

7

Я б розглядав можливість використання засобу ведення журналу roboguice замість вбудованого android.util.Log

Їх об'єкт автоматично вимикає журнали налагодження та багатослівні журнали для версій версій. Крім того, ви отримуєте кілька чудових функцій безкоштовно (наприклад, налаштована поведінка ведення журналу, додаткові дані для кожного журналу та багато іншого)

Використання proguard може бути досить складно, і я не зазнав би проблем з налаштуванням і змушенням його працювати з вашим додатком, якщо у вас немає вагомих причин для цього (відключення журналів не є гарним)


Дуже приємний підхід, коли ти не можеш використовувати Obfuscation .... особливо через розбиття робогукісу через proguard LOL
Snicolas

1
Оновлене посилання для засобу ведення журналу robojuice
RenniePet

7

Я публікую це рішення, яке стосується спеціально для користувачів Android Studio. Нещодавно я відкрив Timber і успішно імпортував його у свій додаток, зробивши наступне:

Помістіть останню версію бібліотеки у свій build.gradle:

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

Потім в Android Studios перейдіть до меню Правка -> Знайти -> Замінити на шляху ...

Введіть Log.e(TAG,або, тим не менш, ви визначили свої Повідомлення журналу в "Text to find"текстове поле. Тоді ви просто замініть йогоTimber.e(

введіть тут опис зображення

Клацніть Знайти та замініть всі.

Тепер Android Studios перегляне всі ваші файли у вашому проекті та замінить усі журнали на Timbers.

Єдиною проблемою, яка була у мене з цим методом, є те, що gradle після цього з'являється з мільйонами повідомлень про помилки, оскільки він не може знайти "Timber" в імпорті для кожного з ваших файлів Java. Просто натисніть на помилки, і Android Studios автоматично імпортує "Timber" у вашу Java. Після того, як ви зробите це для всіх ваших файлів помилок, gradle знову складе.

Вам також потрібно ввести цей фрагмент коду у ваш onCreateметод вашого Applicationкласу:

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

Це призведе до реєстрації додатків лише тоді, коли ви перебуваєте в режимі розробки, а не у виробництві. Ви також можете BuildConfig.RELEASEувійти в режим випуску.


3
Спробуйте зробити те ж саме для вашого імпорту та переконайтесь, що прапорець "Регулярний вираз" встановлений. Текст, щоб знайти: import android\.util\.Log\;Замінити на:import android\.util\.Log\;\nimport timber\.log\.Timber\;
Кларк Вілсон,

або ви можете скористатися структурним пошуком і замінити, як показує Chike Mgbemena у своєму дописі
Максим Тураєв

@MaksimTuraev Ваше посилання більше не стосується. Зараз це блог про зачіски.
Вадим Котов

Схоже, публікація видалена = (не можна її знайти ніде.
Максим Тураєв

@MaksimTuraev ось копія з машини Wayback, але зображення порушені - web.archive.org/web/20161004161318/http://chikemgbemena.com/…
Вадим Котов

6

За android.util.Log надається спосіб увімкнути / вимкнути журнал:

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

За замовчуванням метод isLoggable (...) повертає помилку, лише після того, як ви встановите програму на пристрої, як це:

adb shell setprop log.tag.MyAppTag DEBUG

Це означає, що будь-який журнал вище рівня DEBUG може бути роздрукований. Довідковий документ для android:

Перевіряє, чи можна реєструвати журнал для вказаного тегу на вказаному рівні. Для стандартного рівня будь-якого тегу встановлено значення INFO. Це означає, що будь-який рівень вище, включаючи INFO, буде реєструватися. Перш ніж здійснювати будь-які дзвінки до методу реєстрації, слід перевірити, чи слід увімкнути тег. Ви можете змінити рівень за замовчуванням, встановивши системне властивість: 'setprop log.tag. "Там, де рівень є або VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT або SUPPRESS. SUPPRESS вимкне весь журнал для вашого тегу. Ви також можете створити файл local.prop, який має в ньому таке: "log.tag. =" Та розмістити його в /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);
    }
}

6

Якщо ви можете запустити глобальну заміну (один раз) і після цього зберегти деяку умову кодування, ви можете слідувати шаблону, який часто використовується в рамках 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.DEBUG


4

введіть тут опис зображення

Це те, що я робив у своїх проектах для Android.

В Android Studio ми можемо виконати подібні операції, Ctrl + Shift + F, щоб знайти з цілого проекту (Command + Shift + F в MacOs) і Ctrl + Shift + R для заміни ((Command + Shift + R в MacOs))


Це, здається, відкриває роботу з проектами затемнення. Опція пошуку недоступна навіть на андроїд-студіях.
Саймон

2
в Android Studio ви можете здійснити подібний пошук за допомогою комбінації клавіш Ctrl + Shift + F
Lins Louis

Приклад коду у запитанні пояснює, чому це не є надійним.
Ніколя Рауль

Це може спричинити проблеми з видаленням будь-якої команди, що міститься в Журналі. Наприклад chocolateLog.recipie ();
Andrew S

Неможливо знайти цю опцію для Android Studio 2.1. Також я можу використовувати цей трюк на 1 файл одночасно за допомогою звичайного пошуку / заміни.
VVB

3

У мене дуже просте рішення. Я використовую IntelliJ для розробки, тому деталі змінюються, але ідея повинна застосовуватися для всіх IDE.

Я вибираю корінь свого вихідного дерева, клацніть правою кнопкою миші та виберіть пункт "Замінити". Потім я вибираю замінити всі "Журнал". з "// Журналом." Це видаляє всі оператори журналу. Щоб повернути їх пізніше, я повторюю ту саму заміну, але на цей раз, як замінити всі "// Журнал". з "Журналом".

Працює просто чудово для мене. Просто не забудьте встановити заміну як регістр, щоб уникнути нещасних випадків, таких як "Діалог". Для додаткової впевненості ви також можете зробити перший крок за допомогою "Журналу". як рядок для пошуку.

Блискуча.


2
Будь ласка, прочитайте пункт "Якщо я коментую рядок журналу" у своєму запитанні.
Ніколя Рауль

Гаразд, так, мені слід перечитувати частіше після перегляду відповідей :). Якщо у вас є такі випадки, вам може знадобитися інше рішення, таке, як пропонувалося раніше, як розміщення всіх ваших журналів за іншим інтерфейсом. Моя пропозиція, можливо, краще працює для менших команд та проектів, де люди хочуть уникнути накладних витрат зайвих лісоматеріалів, ви добре знаєте людей та код тощо.
kg_sYy

1
Заміна Log.d на; // Log.d також піклується про той сценарій "Якщо".
Джаспер

3

Як зазначає коментар 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

Чи потрібно ставити цей рядок коду в кожній діяльності / фрагменті чи просто в одному місці?
Ной Тернулло

@NoahTernullo // у похідному файлі програми. DefaultApplication.java
Youngjae

3

Додайте наступне до файлу proguard-rules.txt

-assumenosideeffects class android.util.Log {
  public static *** d(...);
  public static *** w(...);
  public static *** v(...);
  public static *** i(...);
}

1

Я вдосконалив рішення вище, надаючи підтримку різних рівнів журналу та автоматично змінюючи рівні журналу залежно від того, чи виконується код на реальному пристрої чи на емуляторі.

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);
    }
}


}

1
Та ж проблема, що і попереднє рішення. Якщо параметр рядка будується за допомогою дорогих викликів, він все одно витрачає ресурси. Перевірку виклику потрібно зробити перед тим, як побудувати передані параметри.
type-a1pha

1

ProGuard зробить це для вас під час створення релізу і тепер хороші новини від android.com:

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

Інструмент ProGuard скорочує, оптимізує та обмацує ваш код, видаляючи невикористаний код та перейменуючи класи, поля та методи із семантично неясними іменами. Результат - менший розмір .apk-файлу, який важче повернути інженеру. Оскільки ProGuard робить ваш додаток складнішим для зворотного інженера, важливо використовувати його, коли ваша програма використовує функції, чутливі до безпеки, наприклад, коли ви ліцензуєте ваші програми.

ProGuard інтегрований у систему збірки Android, тому не потрібно взивати його вручну. ProGuard запускається лише тоді, коли ви будуєте свою програму у режимі випуску, тому вам не доведеться мати справу із затуманеним кодом під час створення програми у режимі налагодження. Запуск програми ProGuard абсолютно необов’язковий, але настійно рекомендується.

У цьому документі описано, як увімкнути та налаштувати ProGuard, а також використовувати інструмент повторного відстеження для декодування затуманених слідів стека


2
Однак, схоже, не видаляти журнал налагодження за замовчуванням. Тож відповідь Крістофера звучить краще.
Nicolas Raoul

0

Мені подобається використовувати Log.d (TAG, деяка рядок, часто String.format ()).

TAG - це завжди назва класу

Перетворити Log.d (TAG, -> Logd (у тексті вашого класу)

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

Таким чином, коли ви готові зробити версію версії, встановіть для MainClass.debug значення false!


1
Проблема з цим та іншими рішеннями, крім форми захисту або коментування їх, полягає в тому, що ви залишаєте код, викликаючи, можливо, велику кількість нарощування рядків. у середньому додатку не проблема, але якщо ви намагаєтесь оптимізувати, це стає проблемою.
Лассі Кіннунен

0

Журнали можна видалити за допомогою bash в linux та sed:

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

Працює для багаторядкових журналів. У цьому рішенні ви можете бути впевнені, що журнали відсутні у виробничому коді.


0

Я знаю, що це старе питання, але чому ви не замінили всі свої дзвінки з журналу чимось на зразок булевого logCallWasHere = true; // --- решта вашого журналу тут

Ось чому ви дізнаєтесь, коли ви хочете повернути їх назад, і вони не вплинуть на ваш виклик, якщо виклик :)


Цікаво, сподіваємося, такі компілятори ігноруються компілятором / оптимізатором. Однак ім'я змінної повинно бути унікальним, оскільки деякі методи мають кілька викликів журналу, і ви не можете оголосити одну і ту ж змінну двічі.
Ніколя Рауль

Ви можете оголосити змінну вгорі про активність і видалити булеву декларацію з цього рядка;)
masood elsad

0

Чому б просто не зробити

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

? Ніякі додаткові бібліотеки не потрібні, ніякі правила прогард, які, як правило, накручують проект, і компілятор java просто не залишить байт-код для цього виклику, коли ви збираєтеся створити реліз.


Незручним є те, що він більш багатослівний, ніж просто писати Log.d("tag","msg");, а також легко забути написати if(BuildConfig.DEBUG)частину.
Ніколя Рауль

1
Ще одна проблема в цьому полягає в тому, що рядки залишаються в упакованому випуску.
страя

0

Ось моє рішення, якщо ви не хочете возитися з додатковими бібліотеками або редагувати свій код вручну. Я створив цей ноутбук Юпітера, щоб переглядати всі файли Java та коментувати всі повідомлення журналу. Не ідеально, але це зробило роботу для мене.


0

мій шлях:

1) включити режим вибору стовпця (alt + shift + вставка)

2) виберіть на одному Log.d (TAG, "текст"); частина "Журнал".

3) потім зробіть shift + ctrl + alt + j

4) натисніть стрілку вліво

5) зробити зсув + кінець

6) натисніть видалити.

це видаляє всі виклики LOG відразу у файлі java.


0

Ви можете спробувати використовувати цей простий звичайний метод:

Ctrl+Shift +R

замінити

Log.e(

З

// Log.e(

Це не буде добре працювати з прикладом коду, наведеним у питанні.
Ніколя Рауль

0

Легко з kotlin, просто оголосіть кілька функцій верхнього рівня

val isDebug: Boolean
    get() = BuildConfig.DEBUG

fun logE(tag: String, message: String) {
    if (isDebug) Log.e(tag, message)
}

fun logD(tag: String, message: String) {
    if (isDebug) Log.d(tag, message)
}

-1

найпростіший спосіб;

використання DebugLog

DebugLog відключив усі журнали після виходу програми.

https://github.com/MustafaFerhan/DebugLog


Це абсолютно неправильно. Це призводить до того, що журнали не реєструються, вони не видаляють їх з коду, тому вони все ще знаходяться, щоб допомогти людям переробити інженер ваш код, і у нього ще є вартість форматування рядків усіх цих журналів.
Гленн Мейнард
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.