How to remove all debug logging calls before building the release version of an Android app?

前端 未结 27 1473
有刺的猬
有刺的猬 2020-11-22 07:39

According to Google, I must \"deactivate any calls to Log methods in the source code\" before publishing my Android app to Google Play. Extract from section 3 of th

相关标签:
27条回答
  • 2020-11-22 08:16

    I would like to add some precisions about using Proguard with Android Studio and gradle, since I had lots of problems to remove log lines from the final binary.

    In order to make assumenosideeffects in Proguard works, there is a prerequisite.

    In your gradle file, you have to specify the usage of the proguard-android-optimize.txt as default file.

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

    Actually, in the default proguard-android.txt file, optimization is disabled with the two flags:

    -dontoptimize
    -dontpreverify
    

    The proguard-android-optimize.txt file does not add those lines, so now assumenosideeffects can work.

    Then, personnally, I use SLF4J, all the more when I develop some libraries that are distributed to others. The advantage is that by default there is no output. And if the integrator wants some log outputs, he can uses Logback for Android and activate the logs, so logs can be redirected to a file or to LogCat.

    If I really need to strip the logs from the final library, I then add to my Proguard file (after having enabled the proguard-android-optimize.txt file of course):

    -assumenosideeffects class * implements org.slf4j.Logger {
        public *** trace(...);
        public *** debug(...);
        public *** info(...);
        public *** warn(...);
        public *** error(...);
    }
    
    0 讨论(0)
  • 2020-11-22 08:18

    This is how I solve it in my Kotlin Project before going to production:

    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(...);
    }
    
    0 讨论(0)
  • 2020-11-22 08:19

    If you can run a global replace (once), and after that preserve some coding convention, you can follow the pattern often used in Android framework.

    Instead of writing

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

    have it as

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

    Now proguard can remove the StringBuilder and all strings and methods it uses on the way, from optimized release DEX. Use proguard-android-optimize.txt and you don't need to worry about android.util.Log in your proguard-rules.pro:

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

    With Android Studio gradle plugin, BuildConfig.DEBUG is quite reliable, so you don't need extra constants to control the stripping.

    0 讨论(0)
  • 2020-11-22 08:19

    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!

    0 讨论(0)
  • 2020-11-22 08:20

    I have improved on the solution above by providing support for different log levels and by changing the log levels automatically depending on if the code is being run on a live device or on the emulator.

    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);
        }
    }
    
    
    }
    
    0 讨论(0)
  • 2020-11-22 08:21

    I'm posting this solution which applies specifically for Android Studio users. I also recently discovered Timber and have imported it successfully into my app by doing the following:

    Put the latest version of the library into your build.gradle:

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

    Then in Android Studios, go to Edit -> Find -> Replace in Path...

    Type in Log.e(TAG, or however you have defined your Log messages into the "Text to find" textbox. Then you just replace it with Timber.e(

    Click Find and then replace all.

    Android Studios will now go through all your files in your project and replace all the Logs with Timbers.

    The only problem I had with this method is that gradle does come up witha million error messages afterwards because it cannot find "Timber" in the imports for each of your java files. Just click on the errors and Android Studios will automatically import "Timber" into your java. Once you have done it for all your errors files, gradle will compile again.

    You also need to put this piece of code in your onCreate method of your Application class:

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

    This will result in the app logging only when you are in development mode not in production. You can also have BuildConfig.RELEASE for logging in release mode.

    0 讨论(0)
提交回复
热议问题