Android what's the best way to hide logs? [duplicate] - android

This question already has answers here:
How to remove all debug logging calls before building the release version of an Android app?
(31 answers)
Closed 7 years ago.
so.. I'm using Log.d("", ""); in many places in my app for debuging.
but I don't want those logs in the store.
right now in order to hide them in the store version, I created a Constant.class and put a boolean there called debugMode, and wrapped every log i have in an if statement like this :
if (Constant.debugMode) {
Log.d(TAG, "check123");
}
and then when I build a google store apk I change that boolean to true instead of false.
that's kind of clumsy in my opinion, is there any more efficient way to do that?

Make a simple logger class that has public static methods and a swich to enable logs only for debug versions of your app. Here is a sample code.
public class Logger {
public static final boolean D = BuildConfig.DEBUG;
public static void LogInfo(String TAG, String msg) {
if (D) {
Log.i(TAG, msg);
}
}
public static void LogWarrning(String TAG, String msg) {
if (D) {
Log.w(TAG, msg);
}
}
public static void LogDebug(String TAG, String msg) {
if (D) {
Log.d(TAG, msg);
}
}
public static void LogError(String TAG, String msg) {
if (D) {
Log.e(TAG, msg);
}
}
}
Usage
Logger.LogDebug("Test", "Example");
This way you can keep the if clauses in one place and don't have to worry about them. Also I don't think it clumsy this way.

I find a far easier solution is to forget all the if checks all over
the place and just use ProGuard to strip out any Log.d() or Log.v()
method calls when we call our Ant release target.
That way, we always have the debug info being output for regular
builds and don't have to make any code changes for release builds.
ProGuard can also do multiple passes over the bytecode to remove other
undesired statements, empty blocks and can automatically inline short
methods where appropriate.
For example, here's a very basic ProGuard config for Android:
-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5
-keep class * extends android.app.Activity
-assumenosideeffects class android.util.Log {
public static * d(...);
public static * v(...); } So you would save that to a file, then call ProGuard from Ant, passing in your just-compiled JAR and the
Android platform JAR you're using.
#REF:Remove all debug logging calls before publishing: are there tools to do this?

Related

How to have logs that get removed when doing release build [duplicate]

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 the publication checklist:
Make sure you deactivate logging and disable the debugging option before you build your application for release. You can deactivate logging by removing calls to Log methods in your source files.
My open-source project is large and it is a pain to do it manually every time I release. Additionally, removing a Log line is potentially tricky, for instance:
if(condition)
Log.d(LOG_TAG, "Something");
data.load();
data.show();
If I comment the Log line, then the condition applies to the next line, and chances are load() is not called. Are such situations rare enough that I can decide it should not exist?
So, is there a better source code-level way to do that? Or maybe some clever ProGuard syntax to efficiently but safely remove all Log lines?
I find a far easier solution is to forget all the if checks all over the place and just use ProGuard to strip out any Log.d() or Log.v() method calls when we call our Ant release target.
That way, we always have the debug info being output for regular builds and don't have to make any code changes for release builds. ProGuard can also do multiple passes over the bytecode to remove other undesired statements, empty blocks and can automatically inline short methods where appropriate.
For example, here's a very basic ProGuard config for Android:
-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5
-keep class * extends android.app.Activity
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
So you would save that to a file, then call ProGuard from Ant, passing in your just-compiled JAR and the Android platform JAR you're using.
See also the examples in the ProGuard manual.
Update (4.5 years later): Nowadays I used Timber for Android logging.
Not only is it a bit nicer than the default Log implementation — the log tag is set automatically, and it's easy to log formatted strings and exceptions — but you can also specify different logging behaviours at runtime.
In this example, logging statements will only be written to logcat in debug builds of my app:
Timber is set up in my Application onCreate() method:
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
Then anywhere else in my code I can log easily:
Timber.d("Downloading URL: %s", url);
try {
// ...
} catch (IOException ioe) {
Timber.e(ioe, "Bad things happened!");
}
See the Timber sample app for a more advanced example, where all log statements are sent to logcat during development and, in production, no debug statements are logged, but errors are silently reported to Crashlytics.
All good answers, but when I was finished with my development I didn´t want to either use if statements around all the Log calls, nor did I want to use external tools.
So the solution I`m using is to replace the android.util.Log class with my own Log class:
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);
}
}
The only thing I had to do in all the source files was to replace the import of android.util.Log with my own class.
I suggest having a static boolean somewhere indicating whether or not to log:
class MyDebug {
static final boolean LOG = true;
}
Then wherever you want to log in your code, just do this:
if (MyDebug.LOG) {
if (condition) Log.i(...);
}
Now when you set MyDebug.LOG to false, the compiler will strip out all code inside such checks (since it is a static final, it knows at compile time that code is not used.)
For larger projects, you may want to start having booleans in individual files to be able to easily enable or disable logging there as needed. For example, these are the various logging constants we have in the window manager:
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;
With corresponding code like:
if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
TAG, "Adding window " + window + " at "
+ (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
Christopher's Proguard solution is the best, but if for any reason you don't like Proguard, here is a very low-tech solution:
Comment logs:
find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/Log\./;\/\/ Log\./g'
Uncomment logs:
find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/;\/\/ Log\./Log\./g'
A constraint is that your logging instructions must not span over multiple lines.
(Execute these lines in a UNIX shell at the root of your project. If using Windows, get a UNIX layer or use equivalent Windows commands)
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(...);
}
I highly suggest using Timber from Jake Wharton
https://github.com/JakeWharton/timber
it solves your issue with enabling/disabling plus adds tag class automagically
just
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
//Timber
if (BuildConfig.DEBUG) {
Timber.plant(new DebugTree());
}
...
logs will only be used in your debug ver, and then use
Timber.d("lol");
or
Timber.i("lol says %s","lol");
to print
"Your class / msg" without specyfing the tag
I have used a LogUtils class like in the Google IO example application. I modified this to use an application specific DEBUG constant instead of BuildConfig.DEBUG because BuildConfig.DEBUG is unreliable. Then in my Classes I have the following.
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");
}
}
I would consider using roboguice's logging facility instead of the built-in android.util.Log
Their facility automatically disables debug and verbose logs for release builds.
Plus, you get some nifty features for free (e.g. customizable logging behavior, additional data for every log and more)
Using proguard could be quite a hassle and I wouldn't go through the trouble of configuring and making it work with your application unless you have a good reason for that (disabling logs isn't a good one)
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.
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.
Per android.util.Log provides a way to enable/disable log:
public static native boolean isLoggable(String tag, int level);
Default the method isLoggable(...) returns false, only after you setprop in device likes this:
adb shell setprop log.tag.MyAppTag DEBUG
It means any log above DEBUG level can be printed out. Reference android doc:
Checks to see whether or not a log for the specified tag is loggable at the specified level. The default level of any tag is set
to INFO. This means that any level above and including INFO will be
logged. Before you make any calls to a logging method you should check
to see if your tag should be logged. You can change the default level
by setting a system property: 'setprop log.tag. '
Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or
SUPPRESS. SUPPRESS will turn off all logging for your tag. You can
also create a local.prop file that with the following in it:
'log.tag.=' and place that in /data/local.prop.
So we could use custom log util:
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);
}
}
Go to Application->app->proguard-rules.pro
Enter below code inside proguard-rules.pro`
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
public static *** w(...);
public static *** i(...);
public static *** e(...);
}
# You can remove the particular debug class if you want that debug type bug in log
In build.gradle(app) ->android do this thing
buildTypes {
debug{
debuggable false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-
optimize.txt'), 'proguard-rules.pro'
}
release {
debuggable false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-
optimize.txt'), 'proguard-rules.pro'
}
}
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
Add following to your proguard-rules.txt file
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** w(...);
public static *** v(...);
public static *** i(...);
}
I have a very simple solution. I use IntelliJ for development, so the details vary but the idea should apply across all IDE's.
I pick to root of my source tree, right-click and select to do "replace". I then choose to replace all "Log." with "//Log.". This removes all log statements. To put them back later I repeat the same replace but this time as replace all "//Log." with "Log.".
Works just great for me. Just remember to set the replace as case sensitive to avoid accidents such as "Dialog.". For added assurance you can also do the first step with " Log." as the string to search.
Brilliant.
As zserge's comment suggested,
Timber is very nice, but if you already have an existing project - you may try github.com/zserge/log . It's a drop-in replacement for android.util.Log and has most of the the features that Timber has and even more.
his log library provides simple enable/disable log printing switch as below.
In addition, it only requires to change import lines, and nothing needs to change for Log.d(...); statement.
if (!BuildConfig.DEBUG)
Log.usePrinter(Log.ANDROID, false); // from now on Log.d etc do nothing and is likely to be optimized with JIT
This is what i used to do on my android projects..
In Android Studio we can do similar operation by, Ctrl+Shift+F to find from whole project (Command+Shift+F in MacOs) and Ctrl+Shift+R to Replace ((Command+Shift+R in MacOs))
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(...);
}
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);
}
}
}
ProGuard will do it for you on your release build and now the good news from 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
If you want to use a programmatic approach instead of using ProGuard, then by creating your own class with two instances, one for debug and one for release, you can choose what to log in either circumstances.
So, if you don't want to log anything when in release, simply implement a Logger that does nothing, like the example below:
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
}
}
}
Then to use your logger class:
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")
}
}
== UPDATE ==
If we want to avoid string concatenations for better performances, we can add an inline function with a lambda that will be called only in debug config:
// Add this function to the Logger class.
inline fun commit(block: Logger.() -> Unit) {
if(this is LoggerDebug)
block.invoke(this)
}
And then:
logger.commit {
log("Logging without $myVar waste of resources"+ "My fancy concat")
}
Since we are using an inline function, there are no extra object allocation and no extra virtual method calls.
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");
? No additional libraries needed, no proguard rules which tend to screw up the project and java compiler will just leave out bytecode for for this call when you make release build.
my Way:
1) enable Column Selection Mode (alt+shift+insert)
2) select on one Log.d(TAG, "text"); the part 'Log.'
3) then do shift + ctrl + alt + j
4) click left arrow
5) do shift+end
6) hit delete.
this removes all LOG calls at once in a java file.
Easy with kotlin, just declare a few top level functions
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)
}
I have used below approach in my project
Created custom logger class:
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);
}
}
}
Then whenever required logs in code use like this way
LoggerData.showLog("Refreshed token: ", token);
before building release APK, disable logs only one place in LoggerData class
example
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);
}
}
}
Hope it will help you as well.
Here's a simple Kotlin solution that isn't Android or logging API-specific:
Set up some helper object 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()
}
}
then wrap lines in that method:
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!")
}
}
Since the debugLog method is marked as inline and the variable DEBUG_LOGGING_ENABLED is a constant, the log line is simply included or optimized away at compile time. No lambdas are allocated, no method calls.
It's a little cleaner and easier to refactor than wrapping each log line with if() {} statements individually, and the tempting option of making wrappers for your loggers can have significant downsides in terms of compiler and logging server optimizations, safeguards against logging user data inappropriately, etc.
the simplest way;
use DebugLog
All logs are disabled by DebugLog when the app is released.
https://github.com/MustafaFerhan/DebugLog
Here is my solution if you don't want to mess with additional libraries or edit your code manually. I created this Jupyter notebook to go over all java files and comment out all the Log messages. Not perfect but it got the job done for me.

Remove LibGDX logs in Android using ProGuard

I have a proguard.cfg file which contains several statements including optimization passes and logs suppression as :
-assumenosideeffects class android.util.Log { *; }
-assumenosideeffects class com.badlogic.gdx.Application {
public static void debug(...);
public static void error(...);
public static void log(...);
}
Calls to Log.* are correctly removed in the final output APK file. But gdx log calls are still in the code. For example I can still see things like that in the output :
Gdx.app.debug("debug()", "^");
Gdx.app.error("error()", "^");
Gdx.app.log("log()", "^");
I also tried to put this part of my config in a proguard-optimize.txt file as I have seen on similar questions and then setting the proper value in project.properties files like this : proguard.config=proguard-optimize.txt:proguard.txt but it doesn't work !
These calls get removed only if I put a general wildcard :
-assumenosideeffects class com.badlogic.gdx.Application {
*;
}
But I don't want to remove calls to other Application's static methods, like add* and get*() ones.
Optimization step is enabled (6 passes).
Gdx.app.debug is not static its an instance method (app is a static field of the Gdx class).
Try:
-assumenosideeffects class com.badlogic.gdx.Application {
public void debug(...);
public void error(...);
public void log(...);
}
Try something like this in your application's code:
Gdx.app.setLogLevel(Application.LOG_NONE);
That will prevent messages from being logged.
Cheers!

Android: run application in dev/prod environment?

I want to make development easier by implementing a configuration parameter that determines whether the app should be run in 'DEV' mode or 'PROD' mode.
I want this parameter to be accessible from any file (based on this parameter different chunks of code will be executed).
What's the most practical way to store this parameter (which isn't accessible or changeable by the user)?
How can I access it from within the application?
Starting with ADT 17 (IIRC), you have this automatically as part of the auto generated BuildConfig class.
The DEBUG field is always true when developing, but when you export a signed or unsigned apk, it is set to false. You can use it as:
if(BuildConfig.DEBUG) {
//Debug mode
}
Or the other way around:
if(!BuildConfig.DEBUG) {
//Release mode
}
You can use an enum:
public enum BuildType {
Release, Pilot, Debug;
}
And assign it to a global variable:
public static final BuildType BUILD_TYPE = BuildType.Debug;
You can even create some methods in the enum that allow you
switch over very specific parts of your application.
Now you can do stuff like this:
if (MyApplication.BUILD_TYPE != BuildType.Release) {
// some code that does not go in the release
}
A static field in one of your Activity ? Or I am missing something ?
public static boolean isDev = true;
You can set it in the onCreate of your main activity.
You can create a new class and add your variable there.
Also you can add some methods which will display some details about your app in dev mode.
public class Console{
public final static boolean isDev = true;
public static error(String tag, String msg){
if(isDev){
Log.e(TAG, msg);
}
}
}

What is the recommended way of creating switchable a verbose/logging mode in an Android app

How can we create a verbose/logging mode in the app which when switched on will print logging statements from the app and on switching it off no log statements will be printed on the console? One way is to create a preferences option and do a ton of if and else, which does not sound very good. Is there a standard way to do it in Android?
I've never done this myself but check here : http://developer.android.com/reference/android/util/Log.html
Under the isLoggable function it mentions how to enable/disable logging for different types (ERROR, INFO, VERBOSE, etc).
That is, if you're okay having this setting in one file and changing that when you need to.
I created a simple Class to do my logs, so I can easily switch it off. I'm sure there's plenty of rooms for improvements, but it works :)
So use this Log Class instead of the android one:
public class Log {
private static String tag = "YOUR_LOG_TAG";
public static void d(String... params){
for(String m : params){
android.util.Log.d(tag, m);
}
}
public static void d(int m){
android.util.Log.d(tag, String.valueOf(m));
}
public static void d(String iTag, String m){
android.util.Log.d(iTag, m);
}
public static void e(String iTag, String m, Throwable t){
android.util.Log.e(iTag, m, t);
}
public static void e(String m, Throwable t){
android.util.Log.e(tag, m, t);
}
public static void e(String iTag, String m){
android.util.Log.e(iTag, m);
}
}
I agree with #nmjohn that using the android logger is the easiest way to do logging. Together with the Eclipse-adt-plugin-view "LogCat" you can decide at runtime, what you want to see from the logging when your device is connected to development-pc via usb.
If you want to write portable busineslogic you can use the Simple Logging Facade for Java(SLF4J). There is already a "do nothig" implementatin and a implementation that uses the android Log mechanism.
If you need a special kind of logging you can easily create your own SLF4J-implementation that can write to a disk file or do something else.
As far as i know the java standard logger log4j does not work for android because of missing dependencies and a memory footprint that is to big for android.

Should I comment my log calls when creating my final package?

I have an application that uses a lot of Log.d() or Log.e() calls for debugging. Now I want to create my final package for release. The Android Export feature from Eclipse mentions to remove the "Debuggable" flag in the manifest, which I have done. Should I also comment all the Log calls to improve the performance of my application or these calls will do nothing in the non debuggable final version package ?
I have subclassed the Log class to a class called Trace, which mirrors methods on Log. So I do Trace.d(TAG,"blah") and then within the Trace.d method the code only executes based on a static final class variable called LOGGING_LEVEL, which has levels 1-5 (none, errors only, errors & warnings, errors & warnings & info, and everything including debug) . When producing a production APK, Proguard removes all the code that isn't used in the application, so it does it for me.
For me, logging is far too important to remove from the source, but it must be removed from the production application, for performance, secure and intellectual property reasons.
This structure allows me to add a lot MORE logging to the application, which makes debugging problems much easier, but with no impact whatsoever on the production APK
public class Trace
{
public static final int NONE = 0;
public static final int ERRORS_ONLY = 1;
public static final int ERRORS_WARNINGS = 2;
public static final int ERRORS_WARNINGS_INFO = 3;
public static final int ERRORS_WARNINGS_INFO_DEBUG = 4;
private static final int LOGGING_LEVEL = ERRORS_ONLY; // Errors + warnings + info + debug (default)
public static void e(String tag, String msg)
{
if ( LOGGING_LEVEL >=1) Log.e(tag,msg);
}
public static void e(String tag, String msg, Exception e)
{
if ( LOGGING_LEVEL >=1) Log.e(tag,msg,e);
}
public static void w(String tag, String msg)
{
if ( LOGGING_LEVEL >=2) Log.w(tag, msg);
}
public static void i(String tag, String msg)
{
if ( LOGGING_LEVEL >=3) Log.i(tag,msg);
}
public static void d(String tag, String msg)
{
if ( LOGGING_LEVEL >=4) Log.d(tag, msg);
}
}
This made me check my assumption that the log.d lines in the code would somehow not appear on a signed release apk without the debuggable flag set in the manifest, I was wrong, they still appear.
A quick search on SO led me to the accepted answer to this question:
Remove all debug logging calls before publishing: are there tools to do this?
It works very well and you don't have to change any code.
From developer.android.com:
Turn off logging and debugging and clean up data/files For release, you
should make sure that debug facilities
are turned off and that debug and
other unnecessary data/files are
removed from your application project.
Remove the android:debuggable="true"
attribute from the
element of the manifest. Remove log
files, backup files, and other
unnecessary files from the application
project. Check for private or
proprietary data and remove it as
necessary. Deactivate any calls to Log
methods in the source code.
Source
I would remove the logging code as below:
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
public static java.lang.String getStackTraceString(java.lang.Throwable);
}
-assumenosideeffects class java.lang.Exception {
public void printStackTrace();
}
-assumenosideeffects class * implements org.slf4j.Logger {
public void trace(...);
public void debug(...);
public void info(...);
public void warn(...);
public void error(...);
public boolean isTraceEnabled(...);
public boolean isDebugEnabled(...);
public boolean isInfoEnabled(...);
public boolean isWarnEnabled(...);
public boolean isErrorEnabled(...);
}
If required, the error and warn categories may be retained. But be sure that optimization and shrinking is enabled for the build only then the code removal is effective

Categories

Resources