Как удалить все вызовы журнала отладки перед публикацией приложения в Google Play?

Согласно Google, я должен "деактивировать любые вызовы методов Log в исходном коде" перед публикацией моего приложения для Android. Выдержка из раздела 5 контрольного списка публикации:

Убедитесь, что вы отключили ведение журнала и отключили параметр отладки, прежде чем создавать приложение для выпуска. Вы можете отключить ведение журнала, удалив вызовы методов журнала в исходных файлах.

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

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

Если я прокомментирую строку журнала, то условие применяется к следующей строке, и скорее всего, load() не вызывается. Достаточно ли редки такие ситуации, чтобы я мог решить, что их не должно быть?

Это в официальном контрольном списке, так что я думаю, что многие люди делают это на регулярной основе.
Итак, как эффективно, но безопасно удалить все строки журнала?

31 ответ

Решение

Я считаю, что гораздо более простое решение состоит в том, чтобы забыть все if проверяет повсюду и просто использовать ProGuard, чтобы раздеть Log.d() или же Log.v() вызовы метода, когда мы вызываем наш муравей release цель.

Таким образом, мы всегда выводим отладочную информацию для обычных сборок, и нам не нужно вносить какие-либо изменения в код для релизных сборок. 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 года спустя): в настоящее время я использовал Timber для Android-логов.

Это не только немного лучше, чем по умолчанию Log реализация - тег журнала устанавливается автоматически, и в него легко записывать отформатированные строки и исключения - но вы также можете указать различные способы ведения журнала во время выполнения.

В этом примере операторы регистрации будут записываться в logcat только в отладочных сборках моего приложения:

Древесина установлена ​​в моем ApplicationonCreate() метод:

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.

Все хорошие ответы, но когда я закончил свою разработку, я не хотел ни использовать операторы if во всех вызовах журнала, ни использовать внешние инструменты.

Поэтому решение, которое я использую, состоит в том, чтобы заменить класс android.util.Log своим собственным классом Log:

public class Log {
    static final boolean LOG = false;

    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 (условие) 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 + ")");

Решение Кристофера 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)

Я хотел бы добавить некоторые подробности об использовании 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(...);
}

Я настоятельно рекомендую использовать 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" без указания тега

Я использовал класс LogUtils, как в примере приложения Google IO. Я изменил это, чтобы использовать специфичную для приложения константу 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");
  }
}

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

Поместите последнюю версию библиотеки в ваш build.gradle:

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

Затем в Android Studios, перейдите в Edit -> Find -> Replace in Path...

Введите Log.e(TAG, или же вы определили свои сообщения журнала в "Text to find" текстовое окно. Тогда вы просто замените его Timber.e(

Нажмите "Найти", а затем заменить все.

Android Studios теперь будет просматривать все ваши файлы в вашем проекте и заменять все журналы тембрами.

Единственная проблема, с которой я столкнулся при использовании этого метода, заключается в том, что gradle впоследствии выдает миллион сообщений об ошибках, поскольку не может найти "Timber" в импорте для каждого из ваших java-файлов. Просто нажмите на ошибки, и Android Studios автоматически импортирует "Timber" в вашу Java. Как только вы сделали это для всех ваших файлов ошибок, gradle снова скомпилирует.

Вы также должны поместить этот кусок кода в свой onCreate метод вашего Application учебный класс:

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

Это приведет к регистрации приложения только тогда, когда вы находитесь в режиме разработки, а не в производстве. Вы также можете иметь BuildConfig.RELEASE для входа в режиме релиза.

Я хотел бы рассмотреть возможность использования средства регистрации roboguice вместо встроенного android.util.Log

Их средство автоматически отключает отладочные и подробные журналы для сборок релиза. Кроме того, вы получаете некоторые отличные функции бесплатно (например, настраиваемое поведение ведения журнала, дополнительные данные для каждого журнала и многое другое)

Использование proguard может быть довольно сложным делом, и я не буду испытывать трудности с настройкой и настройкой его работы с вашим приложением, если у вас нет веских причин для этого (отключение журналов не является хорошим)

Если вы можете запустить глобальную замену (один раз) и после этого сохранить некоторые правила кодирования, вы можете следовать шаблону, часто используемому в платформе 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'
    }
  }
}

С плагином Grade Android Studio, BuildConfig.DEBUG является достаточно надежным, поэтому вам не нужны дополнительные константы для управления зачисткой.

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

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

По умолчанию метод isLoggable(...) возвращает false, только после того, как вы установили proprop в устройстве, вот так:

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);
    }
}
  1. Перейти к Application->app->proguard-rules.pro

  2. Введите ниже код в proguard-rules.pro`

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

# Вы можете удалить конкретный класс отладки, если хотите, чтобы эта ошибка типа отладки в журнале

  1. В build.gradle(app) ->buildTypes сделай это

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

Добавьте следующее в ваш файл proguard-rules.txt

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

Это то, что я делал на своих проектах Android.

В Android Studio мы можем выполнить аналогичную операцию, нажав Ctrl+Shift+F для поиска по всему проекту (Command+Shift+F в MacOs) и Ctrl+Shift+R для замены ((Command+Shift+R в MacO))

Вот как я решаю это в моем проекте Kotlin перед запуском в производство:

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

-assumenosideeffects class android.util.Log {
    public static boolean isLoggable(java.lang.String, int);
    public static int d(...);
    public static int w(...);
    public static int v(...);
    public static int i(...);
    public static int e(...);
}

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

Я выбираю в корне моего исходного дерева, щелкаю правой кнопкой мыши и выбираю "заменить". Затем я решаю заменить все "Журнал". с "//Log." Это удаляет все записи журнала. Чтобы вернуть их позже, я повторяю ту же самую замену, но на этот раз, чтобы заменить все "// Журнал". с "Журнал."

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

Brilliant.

Как и предполагал комментарий Зсерге,

Timber очень хорош, но если у вас уже есть существующий проект - вы можете попробовать 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, то, создав свой собственный класс с двумя экземплярами, один для отладки, а другой для выпуска, вы можете выбрать, что для входа в систему в любом случае.

Итак, если вы не хотите ничего регистрировать в выпуске, просто реализуйте Logger, который ничего не делает, как в примере ниже:

      import android.util.Log

sealed class Logger(defaultTag: String? = null) {
    protected val defaultTag: String = defaultTag ?: "[APP-DEBUG]"

    abstract fun log(string: String, tag: String = defaultTag)

    object LoggerDebug : Logger() {
        override fun log(string: String, tag: String) {
            Log.d(tag, string)
        }
    }

    object LoggerRelease : Logger() {
        override fun log(string: String, tag: String) {}
    }

    companion object {
        private val isDebugConfig = BuildConfig.DEBUG

        val instance: Logger by lazy {
            if(isDebugConfig)
            LoggerDebug
            else
                LoggerRelease
        }

    }
}

Затем, чтобы использовать свой класс регистратора:

      class MainActivity : AppCompatActivity() {

private val logger = Logger.instance

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    logger.log("Activity launched...")
    ...
    myView.setOnClickListener {
        ...

        logger.log("My View clicked!", "View-click")
    }
}

== ОБНОВЛЕНИЕ ==

Если мы хотим избежать конкатенации строк для повышения производительности, мы можем добавить встроенную функцию с лямбдой, которая будет вызываться только в конфигурации отладки:

      // Add this function to the Logger class.
inline fun commit(block: Logger.() -> Unit) {
    if(this is LoggerDebug)
        block.invoke(this)
}

А потом:

       logger.commit {
     log("Logging without $myVar waste of resources"+ "My fancy concat")
 }

Поскольку мы используем встроенную функцию, нет дополнительных выделений объектов и дополнительных вызовов виртуальных методов.

ProGuard сделает это за вас при сборке релиза, и теперь хорошие новости от android.com:

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

Инструмент ProGuard сокращает, оптимизирует и запутывает ваш код, удаляя неиспользуемый код и переименовывая классы, поля и методы с семантически скрытыми именами. В результате получается файл.apk меньшего размера, который сложнее проанализировать. Поскольку ProGuard затрудняет обратное проектирование вашего приложения, важно использовать его, когда ваше приложение использует функции, чувствительные к безопасности, например, когда вы лицензируете свои приложения.

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

Этот документ описывает, как включить и настроить ProGuard, а также как использовать инструмент восстановления, чтобы декодировать запутанные следы стека.

Я улучшил вышеупомянутое решение, предоставляя поддержку различных уровней журнала и автоматически меняя уровни журнала в зависимости от того, выполняется ли код на работающем устройстве или на эмуляторе.

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


}

Я использовал подход ниже в своем проекте

Создан пользовательский класс регистратора:

      public class LoggerData 
{
   
    public static void showLog(String type, Object object) {
        try {
            Log.d("loggerData:" + type + "-", "showLog: " + new Gson().toJson(object));
        } catch (Exception e) {
            Log.d("TAG", "showLog: " + e.getLocalizedMessage());
            Log.d("loggerData:" + type + "-", "showLog: " + object);
        }

    }

    public static void showLog(Object object) {
        
            try {
                Log.d("loggerData:" + "-", "showLog: +" + new Gson().toJson(object));
            } catch (Exception e) {
                Log.d("TAG", "showLog: " + e.getLocalizedMessage());
                Log.d("loggerData:" + "-", "showLog: " + object);
            }
        
    }
}

Затем всякий раз, когда требуется использовать код входа в систему таким образом

        LoggerData.showLog("Refreshed token: ", token);

перед сборкой выпуска APK отключите журналы только в одном месте в классе LoggerData

пример

      public class LoggerData {
    

    public static void showLog(String type, Object object) {
        try {
            //Log.d("loggerData:" + type + "-", "showLog: " + new Gson().toJson(object));
        } catch (Exception e) {
            //Log.d("TAG", "showLog: " + e.getLocalizedMessage());
            //Log.d("loggerData:" + type + "-", "showLog: " + object);
        }

    }

    public static void showLog(Object object) {
       
            try {
              //  Log.d("loggerData:" + "-", "showLog: +" + new Gson().toJson(object));
            } catch (Exception e) {
                //Log.d("TAG", "showLog: " + e.getLocalizedMessage());
                //Log.d("loggerData:" + "-", "showLog: " + object);
            }
        }
    }

Надеюсь, это поможет и вам.

Я знаю, что это старый вопрос, но почему вы не заменили все вызовы журнала чем-то вроде Boolean logCallWasHere=true; //--- остальная часть вашего журнала здесь

Вот почему вы будете знать, когда вы хотите вернуть их обратно, и они не повлияют на ваш вызов оператора if:)

Вот простое решение Kotlin, которое не относится к Android или API ведения журнала:

Настройте вспомогательный объектLoggingUtils:

      object LoggingUtils {
  const val DEBUG_LOGGING_ENABLED = false

  /** Wraps log lines that should be removed from the prod binary. */
  inline fun debugLog(logBlock: () -> Unit) {
    if (DEBUG_LOGGING_ENABLED) logBlock()
  }
}

затем оберните строки в этом методе:

      fun handleRequest(req: Request) {
  debugLog { logger.atFinest().log("This is a high-volume debug log! %s", request) }

  // ...

  try {
    // ...
  } catch (e: Exception) {
    logger.atSevere().withCause(e).log("I want this to appear in prod logs!")
  }
}

ПосколькуdebugLogметод отмечен какinlineи переменнаяDEBUG_LOGGING_ENABLEDявляется константой, строка журнала просто включается или оптимизируется во время компиляции. Никакие лямбда-выражения не выделяются, никаких вызовов методов.

Это немного чище и проще для рефакторинга, чем обертывание каждой строки журналаif() {}операторы по отдельности, а заманчивый вариант создания оболочек для ваших регистраторов может иметь существенные недостатки с точки зрения оптимизации компилятора и сервера регистрации, защиты от ненадлежащей регистрации пользовательских данных и т. д.

Мне нравится использовать Log.d(TAG, некоторая строка, часто String.format ()).

TAG всегда имя класса

Transform Log.d(TAG, -> Logd(в тексте вашего класса

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

Таким образом, когда вы будете готовы сделать релиз-версию, установите MainClass.debug в false!

Логи можно удалить с помощью bash в linux и sed:

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

Работает для многострочных журналов. В этом решении вы можете быть уверены, что журналы отсутствуют в рабочем коде.

С 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) включить режим выбора столбца (alt + shift + insert)

2) выделить по одному Log.d(ТЕГ, "текст"); часть "Журнал".

3) затем нажмите shift + ctrl + alt + j

4) щелкните стрелку влево

5) делать shift + end

6) нажмите удалить.

это удаляет сразу все вызовы LOG в файле java.

Почему бы просто не сделать

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

? Никаких дополнительных библиотек не требуется, никаких правил proguard, которые имеют тенденцию портить проект, а компилятор java просто оставит байт-код для этого вызова, когда вы делаете сборку релиза.

Вот мое решение, если вы не хотите возиться с дополнительными библиотеками или редактировать код вручную. Я создал эту записную книжку Jupyter, чтобы просмотреть все java-файлы и закомментировать все сообщения журнала. Не идеально, но он сделал свою работу за меня.

Вы можете попробовать воспользоваться этим простым обычным методом:

Ctrl+Shift+R

заменить

Log.e(

С участием

// Log.e(
Другие вопросы по тегам