Como remover tudo o log de depuração de chamadas antes de construir a versão de um aplicativo para Android?

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

Pergunta

De acordo com o Google, eu preciso "desactivar todas as chamadas para Log métodos no código-fonte"antes de publicar meu aplicativo Android para o Google Play.Extrato da seção 3 do publicação de lista de verificação:

Certifique-se de desativar o log e desativar a opção de depuração antes de você criar o seu aplicativo para o lançamento.Você pode desativar o log de remoção de chamadas para Log métodos em seus arquivos de origem.

Meu projeto open-source é grande e é uma dor que fazer isso manualmente a cada vez que eu o lançamento.Além disso, a remoção de uma linha de Log é potencialmente complicado, por exemplo:

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

Se eu comentar a linha de Log e, em seguida, a condição aplica-se para a próxima linha, e as chances são de carga() não é chamado.São tais situações raras, o suficiente para que eu pode decidir que não deve existir?

Por isso, há uma melhor ao nível do código fonte, de forma simples?Ou talvez alguns inteligente ProGuard sintaxe de forma eficiente, mas com segurança remover todas as linhas de Log?

Foi útil?

Solução

Acho que uma solução muito mais fácil é esquecer todos os if cheques em todo o lugar e apenas use Proguard para tirar qualquer Log.d() ou Log.v() Método chama quando chamamos nossa formiga release alvo.

Dessa forma, sempre temos as informações de depuração sendo produzidas para construções regulares e não precisam fazer alterações de código para as compilações de liberação. O ProGuard também pode fazer vários passes sobre o bytecode para remover outras declarações indesejadas, blocos vazios e pode embrulhar automaticamente métodos curtos, quando apropriado.

Por exemplo, aqui está uma configuração de proguard muito básica para Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Então, você salvaria isso em um arquivo e depois ligar para o ProGuard da Ant, passando no seu frasco recém-compilado e no frasco da plataforma Android que você está usando.

Veja também os exemplos no manual de proguard.


Atualização (4,5 anos depois): Hoje em dia eu usei Madeira para o log do Android.

Não é apenas um pouco melhor do que o padrão Log Implementação - A tag de log é definida automaticamente e é fácil registrar seqüências de caracteres e exceções formatadas - mas você também pode especificar diferentes comportamentos de registro em tempo de execução.

Neste exemplo, as instruções de registro só serão gravadas no Logcat no Debug Builds do meu aplicativo:

Madeira está configurada no meu Application onCreate() método:

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

Então, em qualquer outro lugar do meu código, posso registrar facilmente:

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

Veja o App de amostra de madeira Para um exemplo mais avançado, onde todas as declarações de log são enviadas ao Logcat durante o desenvolvimento e, na produção, nenhuma declaração de depuração é registrada, mas os erros são relatados silenciosamente à Crashlytics.

Outras dicas

Todas as boas respostas, mas quando terminei meu desenvolvimento, não queria usar as instruções se em torno de todas as chamadas de log, nem eu queria usar ferramentas externas.

Portanto, a solução que estou usando é substituir a classe Android.util.log pela minha própria classe de 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);
    }
}

A única coisa que tive que fazer em todos os arquivos de origem foi substituir a importação do Android.util.log pela minha própria classe.

Eu sugiro ter um booleano estático em algum lugar indicando se deve ou não registrar:

class MyDebug {
  static final boolean LOG = true;
}

Então, onde quer que você queira fazer login no seu código, basta fazer isso:

if (MyDebug.LOG) {
  if (condition) Log.i(...);
}

Agora, quando você define o mydebug.log como false, o compilador retira todo o código dentro de tais verificações (como é uma final estática, sabe no momento da compilação que o código não é usado.)

Para projetos maiores, você pode começar a ter booleanos em arquivos individuais para poder ativar ou desativar facilmente o registro, conforme necessário. Por exemplo, essas são as várias constantes de madeira que temos no gerenciador de janelas:

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;

Com código correspondente como:

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

A solução de Proguard de Christopher é a melhor, mas se, por qualquer motivo, você não gosta de ProGuard, aqui está uma solução muito de baixa tecnologia:

Logs de comentários:

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

Toras de descomposição:

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

Uma restrição é que suas instruções de registro não devem abranger várias linhas.

(Execute essas linhas em um shell Unix na raiz do seu projeto. Se estiver usando o Windows, obtenha uma camada Unix ou use comandos equivalentes do Windows)

Gostaria de adicionar algumas precisões sobre o uso do ProGuard com o Android Studio e o Gradle, já que tive muitos problemas para remover as linhas de log do binário final.

Para fazer assumenosideeffects Nos trabalhos de Proguard, há um pré -requisito.

No seu arquivo gradle, você deve especificar o uso do proguard-android-optimize.txt como arquivo padrão.

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'
    }
}

Na verdade, no padrão proguard-android.txt Arquivo, otimização é desativada com os dois sinalizadores:

-dontoptimize
-dontpreverify

o proguard-android-optimize.txt O arquivo não adiciona essas linhas, então agora assumenosideeffects pode trabalhar.

Então, pessoalmente, eu uso Slf4j, ainda mais quando desenvolvo algumas bibliotecas que são distribuídas a outras pessoas. A vantagem é que, por padrão, não há saída. E se o integrador quiser algumas saídas de log, ele poderá usar o logback para o Android e ativar os logs, para que os logs possam ser redirecionados para um arquivo ou para o logcat.

Se eu realmente precisar retirar os logs da biblioteca final, adicionei ao meu arquivo proguard (depois de permitir o proguard-android-optimize.txt arquivo, é claro):

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

Eu sugiro usar Madeira de Jake Wharton

https://github.com/JakeWharton/timber

ele resolve seu problema com o ativando/desativando o plus adiciona tag classe automagicamente

apenas

public class MyApp extends Application {

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

logs serão apenas utilizados na sua depuração ver e, em seguida, usar

Timber.d("lol");

ou

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

imprimir

"Sua classe / msg" sem specyfing a marca

Eu usei um Logutils Classe como no aplicativo de exemplo do Google IO. Eu modifiquei isso para usar uma constante de depuração específica do aplicativo em vez de BuildConfig.debug porque BuildConfig.debug não é confiável. Então, nas minhas aulas, tenho o seguinte.

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

Eu consideraria usar o de Roboguice instalação de log em vez do Android.util.log embutido

Suas instalações desabilitam automaticamente a depuração e os logs detalhados das compilações de lançamento. Além disso, você obtém alguns recursos bacanas gratuitamente (por exemplo, comportamento de log personalizável, dados adicionais para cada log e muito mais)

Usar proGuard pode ser um tanto aborrecimento e eu não me esforçaria pelo trabalho de configurar e fazê -lo trabalhar com seu aplicativo, a menos que você tenha um bom motivo para isso (os registros desativados não são bons)

Estou postando esta solução que se aplica especificamente para usuários de estúdio Android. Também descobri recentemente a madeira e a importei com sucesso para o meu aplicativo, fazendo o seguinte:

Coloque a versão mais recente da biblioteca em sua construção.gradle:

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

Então, nos estúdios do Android, vá para Editar -> Localizar -> Substituir no caminho ...

Digitar Log.e(TAG, ou no entanto, você definiu suas mensagens de log no "Text to find" caixa de texto. Então você apenas o substitui por Timber.e(

enter image description here

Clique em Localizar e substitua tudo.

O Android Studios agora passará por todos os seus arquivos em seu projeto e substituirá todos os logs por madeiras.

O único problema que tive com esse método é que o Gradle surge com um milhão de mensagens de erro depois, porque não pode encontrar "madeira" nas importações de cada um dos seus arquivos Java. Basta clicar nos erros e no Android Studios importará automaticamente a "madeira" para o seu Java. Depois de fazer isso para todos os seus arquivos de erros, a Gradle será compilada novamente.

Você também precisa colocar este pedaço de código em seu onCreate método do seu Application classe:

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

Isso resultará no log de aplicativos somente quando você estiver no modo de desenvolvimento não em produção. Você também pode ter BuildConfig.RELEASE Para fazer login no modo de liberação.

Per Android.util.log fornece uma maneira de ativar/desativar log:

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

Padrão O método isLoggable (...) retorna false, somente depois que você define o dispositivo gosta disso:

adb shell setprop log.tag.MyAppTag DEBUG

Isso significa que qualquer log acima do nível de depuração pode ser impresso. Referência Android Doc:

Verifica para ver se um log para a tag especificado é ou não loggable no nível especificado. O nível padrão de qualquer tag está definido como informações. Isso significa que qualquer nível acima e incluindo informações serão registradas. Antes de fazer chamadas para um método de log, você deve verificar se sua tag deve ser registrada. Você pode alterar o nível padrão definindo uma propriedade do sistema: 'SetProp log.tag. 'Onde o nível é detalhado, depuração, informação, aviso, erro, afirma ou suprime. O suprimido desativará todo o log para sua tag. Você também pode criar um arquivo local.prop que com o seguinte: 'log.tag. =' E colocar que em /data/local.prop.

Para que pudéssemos usar o Util de log personalizado:

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

Se você pode executar uma substituição global (uma vez) e, depois disso, preservar uma convenção de codificação, poderá seguir o padrão frequentemente usado no Android estrutura.

Em vez de escrever

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

tem como

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

Agora, o ProGuard pode remover o StringBuilder e todas as cordas e métodos que ele usa no caminho, a partir de dex de liberação otimizada. Usar proguard-android-optimize.txt E você não precisa se preocupar com Android.util.log na tua proguard-rules.pro:

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

Com o plug -in Android Studio Gradle, BuildConfig.DEPURAR é bastante confiável, então você não precisa de constantes extras para controlar a remoção.

Eu tenho uma solução muito simples. Eu uso o Intellij para o desenvolvimento, para que os detalhes variem, mas a idéia deve ser aplicada em todos os IDEs.

Escolho para fazer a raiz da minha árvore de origem, clique com o botão direito do mouse e selecione fazer "Substituir". Eu então escolho substituir todos os "log". com "// log". Isso remove todas as instruções de log. Para colocá -los de volta mais tarde, repito a mesma substituição, mas desta vez substitua todo "// log". com "log".

Funciona muito bem para mim. Lembre -se de definir a substituição como sensível à caixa para evitar acidentes como "diálogo". Para uma garantia adicional, você também pode dar o primeiro passo com "log". como a string para pesquisar.

Brilhante.

Como Comentário de Zserge sugerido,

A madeira é muito boa, mas se você já possui um projeto existente - pode experimentar github.com/zserge/log. É um substituto para Android.util.log e possui a maioria dos recursos que a Timber possui e ainda mais.

sua biblioteca de log Fornece o interruptor de impressão de log de ativação/desabilitação simples como abaixo.

Além disso, isso requer mudar import linhas e nada precisa mudar para Log.d(...); declaração.

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

Adicione o seguinte ao seu proGuard-rules.txt Arquivo

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

enter image description here

Isso é o que eu costumava fazer nos meus projetos do Android.

No Android Studio, podemos fazer uma operação semelhante por, Ctrl+Shift+F para encontrar de todo o projeto (comando+shift+f em macOS) e ctrl+shift+r para substituir ((comando+shift+r no macOS))

Melhorei a solução acima, fornecendo suporte para diferentes níveis de log e alterando os níveis de log automaticamente, dependendo se o código estiver sendo executado em um dispositivo ativo ou no emulador.

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 fará isso por você na sua versão de lançamento e agora as boas notícias do Android.com:

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

A ferramenta ProGuard encolhe, otimiza e ofusca seu código removendo código não utilizado e renomeando classes, campos e métodos com nomes semanticamente obscuros. O resultado é um arquivo .apk de tamanho menor que é mais difícil de reverter o engenheiro. Como o ProGuard dificulta o engenheiro reverso do seu aplicativo, é importante que você o use quando o aplicativo utiliza recursos sensíveis à segurança, como quando você está licenciando seus aplicativos.

O ProGuard é integrado ao sistema de construção do Android, para que você não precise invocá -lo manualmente. O ProGuard é executado apenas quando você constrói seu aplicativo no modo de liberação, para que você não precise lidar com o código ofuscado ao criar seu aplicativo no modo de depuração. Ter o ProGuard Run é completamente opcional, mas altamente recomendado.

Este documento descreve como habilitar e configurar o ProGuard, bem como usar a ferramenta Retrace para decodificar rastreios de pilha ofuscada

Eu gosto de usar log.d (tag, alguma string, geralmente um string.format ()).

A tag é sempre o nome da classe

Transform Log.d (tag, -> logd (no texto da sua classe

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

Dessa forma, quando você estiver pronto para fazer uma versão de lançamento, defina mainClass.debug como false!

Os logs podem ser removidos usando o Bash no Linux e sed:

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

Funciona para logs multilinas. Nesta solução, você pode ter certeza de que os logs não estão presentes no código de produção.

Eu sei que essa é uma pergunta antiga, mas por que você não substituiu todas as suas chamadas de log por algo como boolean logCallwashere = true; // --- Resto do seu log aqui

É por isso que você saberá quando quiser colocá -los de volta, e eles não afetarão sua declaração se a declaração :)

Por que não apenas fazer

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

? Nenhuma biblioteca adicional é necessária, nenhuma regra de proguard que tende a estragar o projeto e o Java Compiler deixará de fora o ByteCode para esta chamada quando você fizer a versão de liberação.

a maneira mais simples;

usar DebugLog

Todos os logs são desativados pelo DebugLog quando o aplicativo é lançado.

https://github.com/mustafaferhan/debuglog

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top