Bir Android uygulamasının yayın sürümünü oluşturmadan önce tüm hata ayıklama günlüğü aramalarını nasıl kaldırırım?


397

Google'a göre, Android uygulamamı Google Play'de yayınlamadan önce " Kaynak koddaki Günlük yöntemlerine yapılan tüm aramaları devre dışı bırakmalıyım ". Yayın kontrol listesinin 3. bölümünden alıntı :

Uygulamanızı yayınlanmak üzere oluşturmadan önce günlüğe kaydetmeyi devre dışı bıraktığınızdan ve hata ayıklama seçeneğini devre dışı bıraktığınızdan emin olun. Kaynak dosyalarınızdaki Günlük yöntemlerine yapılan çağrıları kaldırarak günlüğü devre dışı bırakabilirsiniz.

Açık kaynaklı projem büyük ve her bıraktığımda bunu manuel olarak yapmak acı verici. Ayrıca, bir Günlük satırını kaldırmak potansiyel olarak zordur, örneğin:

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

Günlük satırına yorum yaparsam, koşul bir sonraki satıra uygulanır ve olasılıklar load () olarak adlandırılmaz. Böyle durumlar var olmamasına karar verebilecek kadar nadir midir?

Peki, bunu yapmanın daha iyi bir kaynak kodu düzeyinde yolu var mı? Ya da tüm Log satırlarını verimli ama güvenli bir şekilde kaldırmak için bazı akıllı ProGuard sözdizimi?


2
+1 çünkü bunun yayın kontrol listesinde olduğunu hatırlamadım.
rds

51
Engellenmeyen bir satırı yorumlamak için "//" yerine "; //" kullanıyorum.
12'de

Bunu geri alabilmeniz gerekiyorsa, sed 's_^\(\s*Log\.\)_;//'`date|tr -s \ -`'\1_g'bunun yerine kullanmak isteyeceksinizdir .
12'de

2
Dimitar'ın eklediği bağlantı artık çalışmıyor. Bunun yerine source.android.com/source/code-style.html#log-sparingly buldum .
JosephL

1
@mboy: Muhtemelen bugünlerde performans için, ancak eski Android sürümlerinde de güvenlik faydaları var.
Nicolas Raoul

Yanıtlar:


488

Her ifyerde tüm kontrolleri unutmak ve Ant hedefimizi aradığımızda herhangi bir veya yöntem çağrısını çıkarmak için ProGuard'ı kullanmak çok daha kolay bir çözüm buluyorum .Log.d()Log.v()release

Bu şekilde, normal derlemeler için her zaman hata ayıklama bilgilerinin çıktısını alırız ve sürüm derlemeleri için herhangi bir kod değişikliği yapmamız gerekmez. ProGuard, diğer istenmeyen ifadeleri, boş blokları kaldırmak için bayt kodu üzerinden birden fazla geçiş yapabilir ve uygun olduğunda kısa yöntemleri otomatik olarak satır içine alabilir.

Örneğin, Android için çok temel bir ProGuard yapılandırması:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Böylece bunu bir dosyaya kaydeder ve daha sonra derlenmiş JAR'ınızı ve kullandığınız Android platformunu JAR'dan geçirerek Ant'den ProGuard'ı ararsınız.

Ayrıca ProGuard kılavuzundaki örneklere bakın .


Güncelleme (4,5 yıl sonra): Bugünlerde kullandım Android günlüğü için Kereste .

Sadece varsayılandan biraz daha hoş değil Log uygulamadan - günlük etiketi otomatik olarak ayarlanır ve biçimlendirilmiş dizeleri ve istisnaları günlüğe kaydetmek kolaydır - aynı zamanda çalışma zamanında farklı günlükleme davranışları da belirtebilirsiniz.

Bu örnekte, günlük ifadeleri yalnızca uygulamamın hata ayıklama yapılarında logcat'e yazılır:

Kereste benim Application onCreate()yöntemimle kuruldu :

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

Sonra benim kodu başka bir yerde kolayca giriş yapabilirsiniz:

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

Tüm günlük deyimlerinin geliştirme sırasında logcat'e gönderildiği ve üretimde hata ayıklama deyimlerinin kaydedilmediği, ancak hataların sessizce Crashlytics'e bildirildiği daha gelişmiş bir örnek için Kereste örneği uygulamasına bakın .


59
Ve bu neden varsayılan koruma dosyasında değil?
rds

10
+ rds, üretim yığınlarını satır satırları kodunuzdakilerden farklı yapar, çünkü satırlar kaldırılır.
Guy

5
Günlük aramalarını çıkarmanın yığın izlemelerinde satır numaralarını değiştireceğini onaylayabilirim. Her zaman senkronize olmayacak (birkaç hızlı test yaptım, ancak sebebinin ne olduğunu tam olarak belirleyemem, muhtemelen Günlük çağrısında bir dizeyi birleştirirseniz), ancak bazen birkaç satır kapalı olacaktır. Günlük çağrıları kolayca kaldırmak için IMO sorun değerinde.
Tony Chan

5
@Fraggle ADT araçlarındaki proguard-android.txt dosyasından: "Optimizasyonu etkinleştirmek istiyorsanız, yalnızca kendi proje yapılandırma dosyanıza optimizasyon bayraklarını ekleyemeyeceğinizi unutmayın; bunun yerine" proguard-android-optimiz "seçeneğini işaret etmeniz gerekir. txt "yerine" # project.properties dosyanızdaki "dosyayı.
Raanan

3
Espinchi'nin dediği gibi aşağıdaki cevap. "Bu yaklaşımla ilgili tek sorun, Log.d (" tag "," Processed: "+ new ItemCounter (blabla) +" items ") yaparsanız, bu günlük mesajı yayımlanan sürümünüzde görünmese bile, bir StringBuilder oluşturmak için pahalı olabilir bir mesaj oluşturmak için kullanılır. "Bu Timber durumda da geçerli mi?
Chitrang

117

Tüm iyi cevaplar, ancak gelişimimi bitirdiğimde, tüm Log çağrılarının etrafında if ifadelerini kullanmak istemiyordum ya da harici araçlar kullanmak istemiyordum.

Bu yüzden kullandığım çözüm android.util.Log sınıfını kendi Log sınıfımla değiştirmektir:

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

Tüm kaynak dosyalarda yapmak zorunda olduğum tek şey android.util.Log'u kendi sınıfımla değiştirmekti.


143
Bu yaklaşımla ilgili tek sorun, Log.d ("tag", "Processed:" + new ItemCounter (blabla) + "items") yaparsanız, bu günlük mesajı yayımlanan sürümünüzde görünmese bile, StringBuilder, oluşturulması pahalı olabilecek bir mesaj oluşturmak için kullanılır.
espinchi

9
Bu çözümün büyük bir sorunu var. espinchi buzdağının sadece ucundan bahsetti. Sorun şu ki, bazı Log.d("tag", someValue.toString());değerleri boş olup olmadıklarını kontrol etmeyi unutmak çok kolay NullPointerException. Güvenli bir çözüm önerir, ancak sizi kandırır. Biz bir private static boolean DEBUGve daha sonraif(DEBUG)Log.d(TAG, msg);
philipp '

2
@espinchi Endişeniz bu yanıtta tartışılan gibi tüm günlük kitaplıkları için geçerli gibi görünüyor stackoverflow.com/a/15452492/433718 (Slf4j, biriktirme listesi, ...). Bunları kullanmanız önerilmez mi?
OneWorld

1
@Espinchi tarafından yapılan 1. açıklamada bahsedilen genel giderleri en aza indirmenin tek yolu, varargs yerine varargs kabul etmek için günlük yöntemlerini değiştirmektir String. Komple çözüm burada açıklanmıştır . Görünüşe göre başka bir dezavantajı var: her çağrı düzenlenmelidir (sadece bir içe aktarma hattı değil).
Stan

21
Sadece bir FYI, Android Studio ve gradle derleme sistemi kullanıyorsanız, static final boolean LOG = BuildConfig.DEBUGbu dosyayı hiç kullanmanıza gerek yoktur.
ashishduh

61

Günlük bir yerde olup olmadığını belirtmek için statik bir boole sahip öneririz:

sınıf MyDebug {
  statik son boolean LOG = doğru;
}

Ardından, kodunuzu girmek istediğiniz her yerde şunları yapın:

if (MyDebug.LOG) {
  eğer (koşul) Log.i (...);
}

Şimdi MyDebug.LOG öğesini false olarak ayarladığınızda, derleyici bu tür denetimlerin içindeki tüm kodu çıkarır (statik bir final olduğu için derleme zamanında kodun kullanılmadığını bilir.)

Daha büyük projeler için, gerektiğinde günlük kaydını kolayca etkinleştirmek veya devre dışı bırakmak için tek tek dosyalarda booleans kullanmaya başlamak isteyebilirsiniz. Örneğin, bunlar pencere yöneticisinde bulunan çeşitli günlük sabitleridir:

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;

Gibi karşılık gelen kod ile:

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

1
Ben de böyle bir yaklaşıma oy verirdim. Ayrıca resmi Google'ın uygulama içi faturalandırma örneğinde de kullanılmıştır.
LA_

4
Koşulu ilk parametre olarak geçirmek daha az ayrıntılı olmaz mı?
Snicolas

1
Her günlük deyiminde ek kod gerektirmesine rağmen bu en iyi çözüm gibi görünmektedir: Satır numaraları korunur (ProGuard yaklaşımının zayıflığı), Günlük mesajı oluşturmak için kod yürütülmez ( sarıcı sınıfı yaklaşımının zayıflığı ve görünüşte kayıt kütüphanesi yaklaşımı da) . @LA_'ya göre uygulama faturalandırma örneğinde Google'da bu yaklaşımın kullanılması düşüncelerimi de destekler.
OneWorld

2
@Snicolas Bir sarmalayıcı uygulamadan durumu ilk parametre olarak nasıl iletebilirsiniz? Ayrıca, parametre olarak eklerseniz, yönteme girmeden önce, tüm parametrelerin, yani mesaj dizesinin de değerlendirilmesi gerekir. Parametreleri oluşturmadan önce durumun test edilmesi gerekir. Önerilen çözüm, harici bir araç göz önüne alınmadan muhtemelen en iyisidir.
type-a1pha

2
İkili kod akıllıca, bu en iyisidir. Ancak bu şekilde kodlama, basit bir hata ayıklama günlüğü çıktısı için çok fazla çaba gerektirir. Kod okunabilirliği önemli ölçüde düşer. Biraz kazan, biraz kaybet, sanırım ...
Richard Le Mesurier

30

Christopher'ın Proguard çözümü en iyisidir, ancak herhangi bir nedenle Proguard'ı sevmiyorsanız, işte çok düşük teknolojili bir çözüm var:

Yorum günlükleri:

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

Uncomment günlükleri:

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

Bir kısıtlama, günlük kaydı talimatlarınızın birden çok satıra yayılmaması gerektiğidir.

(Bu satırları projenizin kökündeki UNIX kabuğunda yürütün. Windows kullanıyorsanız, UNIX katmanı edinin veya eşdeğer Windows komutlarını kullanın)


1
Mac üzerinde çalışıyorsa Sed'de -i sonra bir "" gerekir ( buna göre ) Teşekkürler.
Vishal

Bunun üzerinde çalıştığım bir şey için kullandığım şey olabileceğini hissediyorum çünkü Proguard ile bunu yapmakta pek şansım yoktu
Joe Plante

Peki ya ilk yayında önerdiğiniz gibi, parantezsiz bir daldan sonra bir Günlüğünüz varsa?
type-a1pha

@ type-a1pha: Bu çözümü benimserseniz, parantez bloklarını zorunlu olarak düşünmeniz gerekir.
Nicolas Raoul

2
@NicolasRaoul Yarı kolon bu sorunu giderir ( //vs. ;//)
Alex Gittemeier

18

Proguard'ı Android Studio ve gradle ile kullanma hakkında bazı kesinlikler eklemek istiyorum, çünkü günlük satırlarını son ikili dosyadan kaldırmak için birçok sorunum vardı.

Yapabilmek için assumenosideeffectsProguard eserlerinde, bir ön koşul yoktur.

Gradle dosyanızda, proguard-android-optimize.txtvarsayılan dosyanın kullanımını belirtmeniz gerekir .

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

Aslında, varsayılan proguard-android.txtdosyada optimizasyon iki bayrakla devre dışı bırakılır:

-dontoptimize
-dontpreverify

proguard-android-optimize.txtDosya bu satırları eklemez, şimdi assumenosideeffectsçalışabilir.

Daha sonra, kişisel olarak, diğerlerine dağıtılan bazı kütüphaneler geliştirdiğimde, daha fazlasını SLF4J kullanıyorum . Avantajı, varsayılan olarak çıktı olmamasıdır. Ve tümleştirici bazı günlük çıktıları isterse, Android için Logback'i kullanabilir ve günlükleri etkinleştirebilir, böylece günlükler bir dosyaya veya LogCat'e yeniden yönlendirilebilir.

Günlükleri son kitaplıktan çıkarmam gerekirse, Proguard dosyama eklerim ( proguard-android-optimize.txttabii ki dosyayı etkinleştirdikten sonra ):

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

Bu yeni Jack derleyicisi ile çalışmaz-- stackoverflow.com/questions/37932114/…
fattire

Bu bana yardımcı oldu; hem proguard-android-optimize.txtvarsayılan Proguard dosyası olarak hem de -assumenosideeffectsözel Proguard dosyasında gerekliydi! R8 shinker (günümüzde varsayılan) ve varsayılan Android günlüğü kullanıyorum.
Jonik

10

Jake Wharton'dan Kereste kullanmanızı şiddetle tavsiye ederim

https://github.com/JakeWharton/timber

etkinleştirme / devre dışı bırakma sorununuzu çözer ve etiket sınıfını otomatik olarak ekler

sadece

public class MyApp extends Application {

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

günlükleri yalnızca hata ayıklama sürümünüzde kullanılacaktır.

Timber.d("lol");

veya

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

yazdırmak

Etiketi belirtmeden "Sınıfınız / msg"


2
Kereste çok güzel, ancak zaten mevcut bir projeniz varsa - github.com/zserge/log'u deneyebilirsiniz . Bu android.util.Log için bir açılan yedek ve Kereste'nin sahip olduğu özelliklerin çoğuna ve daha fazlasına sahiptir.
zserge

zserge, günlük çözümünüz iyi görünüyor. Birçok özellik. Kereste gibi Lint kuralları eklemeyi düşündünüz mü?
jk7

8

Google IO örnek uygulamasında olduğu gibi bir LogUtils sınıfı kullandım . BuildConfig.DEBUG güvenilir olmadığından , BuildConfig.DEBUG yerine uygulamaya özel bir DEBUG sabiti kullanmak için bunu değiştirdim . Sonra Sınıflarımda aşağıdakiler var.

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

Build.DEBUGEskiden kullandığım hata raporu için +1 . Ayrıca çeşitli "doğru" geçici çözümlerden vazgeçtim ve size benzer bir stil çözümü kullandım.
Richard Le Mesurier

7

Yerleşik android.util.Log yerine roboguice'in günlük oluşturma özelliğini kullanmayı düşünürdüm

Tesisleri, sürüm derlemeleri için hata ayıklama ve ayrıntılı günlükleri otomatik olarak devre dışı bırakır. Ayrıca, ücretsiz bazı şık özellikler elde edersiniz (örneğin, özelleştirilebilir günlük kaydı davranışı, her günlük için ek veriler ve daha fazlası)

Proguard kullanmak oldukça zor olabilir ve bunun için iyi bir nedeniniz yoksa (günlükleri devre dışı bırakmak iyi bir şey değildir) yapılandırmanız ve uygulamanızla çalışmasını zorlaştırmam.


Obfuscation'ı kullanamadığınızda çok güzel bir yaklaşım .... özellikle koruyucusu LOL nedeniyle roboguice kırılması nedeniyle
Snicolas

1
Robojuice'nin kayıt tesisi için güncellenmiş bağlantı: github.com/roboguice/roboguice/wiki/Logging-via-Ln
RenniePet

7

Özellikle Android Studio kullanıcıları için geçerli olan bu çözümü gönderiyorum. Ayrıca kısa süre önce Timber'i keşfettim ve aşağıdakileri yaparak uygulamama başarıyla aktardım:

Kütüphanenin en son sürümünü build.gradle dosyasına koyun:

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

Ardından Android Studios'ta Düzenle -> Bul -> Yolda Değiştir ... seçeneğine gidin.

Yazın Log.e(TAG,veya ancak içine Günlük iletisini tanımladınız "Text to find"metin. Sonra sadeceTimber.e(

resim açıklamasını buraya girin

Bul'u tıklayın ve ardından hepsini değiştirin.

Android Studios şimdi projenizdeki tüm dosyalarınızı gözden geçirecek ve tüm Günlükleri Kereste ile değiştirecektir.

Bu yöntem ile vardı tek sorun, gradle daha sonra milyon hata iletileri ile geliyor çünkü java dosyaları her ithalat için "Kereste" bulamıyor olmasıdır. Sadece hataları tıklayın ve Android Studios otomatik olarak "Kereste" java içine alacak. Tüm hata dosyalarınız için yaptıktan sonra, gradle tekrar derlenecektir.

Bu kod parçasını sınıfınızın onCreateyöntemine de koymanız gerekir Application:

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

Bu, uygulama günlüğüne yalnızca üretimde değil geliştirme modunda olduğunuzda neden olur. BuildConfig.RELEASESerbest bırakma modunda oturum açmak için de sahip olabilirsiniz .


3
İçe aktarma işlemleriniz için de aynı şeyi deneyin ve Düzenli İfade kutusunun işaretli olduğundan emin olun Bulmak için metin: import android\.util\.Log\;Şununla değiştir:import android\.util\.Log\;\nimport timber\.log\.Timber\;
Clark Wilson

veya kullanabilirsiniz Yapısal arama ve onun içinde Chike Mgbemena gösterileri gibi değiştirin yazı
Maksim Turaev

@MaksimTuraev Bağlantınız artık alakalı değil. Şimdi saç modelleri hakkında bir blog.
Vadim Kotov

Görünüşe göre yazı kaldırıldı = (hiçbir yerde bulamıyorum.)
Maksim Turaev

@MaksimTuraev burada Wayback makinesinin bir kopyası, ancak görüntüler bozuk - web.archive.org/web/20161004161318/http://chikemgbemena.com/…
Vadim Kotov

6

Android.util.Log başına günlüğü etkinleştirmek / devre dışı bırakmak için bir yol sağlar:

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

İsLoggable (...) yöntemi varsayılan olarak false değerini döndürür, ancak cihazda setprop bunu beğendikten sonra:

adb shell setprop log.tag.MyAppTag DEBUG

DEBUG seviyesinin üzerindeki herhangi bir günlük yazdırılabilir. Referans android doc:

Belirtilen etiket için bir günlüğün belirtilen düzeyde günlüğe kaydedilip kaydedilemeyeceğini denetler. Herhangi bir etiketin varsayılan seviyesi INFO olarak ayarlanmıştır. Bu, INFO dahil olmak üzere herhangi bir seviyenin günlüğe kaydedileceği anlamına gelir. Bir kayıt yöntemine herhangi bir arama yapmadan önce etiketinizin günlüğe kaydedilip kaydedilmeyeceğini kontrol etmelisiniz. Bir system özelliğini ayarlayarak varsayılan düzeyi değiştirebilirsiniz: 'setprop log.tag. 'Seviyenin VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT veya SUPPRESS olduğu durumlarda. SUPPRESS, etiketiniz için tüm günlük kaydını kapatır. İçinde aşağıdakileri içeren bir local.prop dosyası da oluşturabilirsiniz: 'log.tag. =' Ve /data/local.prop içine yerleştirin.

Böylece özel günlük util kullanabilirsiniz:

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

Genel bir değiştirme çalıştırabilirseniz (bir kez) ve bundan sonra bazı kodlama kurallarını koruyorsanız, Android çerçevesinde sıklıkla kullanılan deseni takip edebilirsiniz .

Yazmak yerine

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

olduğu gibi

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

Proguard, StringBuilder'ı ve yolda kullandığı tüm dizeleri ve yöntemleri optimize edilmiş DEX sürümünden kaldırabilir. Kullanım proguard-android-optimize.txtve hakkında endişe gerekmez android.util.Log Gözlerinde farklı proguard-rules.pro:

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

Android Studio gradle eklentisi ile oldukça güvenilirdir, bu nedenle sıyırma işlemini kontrol etmek için ekstra sabitlere ihtiyacınız yoktur.BuildConfig.DEBUG


4

Proguard-rules.txt dosyanıza aşağıdakileri ekleyin

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

4

resim açıklamasını buraya girin

Android projelerimde yaptığım şey budur ..

Android Studio'da, tüm projeden bulmak için Ctrl + Shift + F ve MacO'larda Command + Shift + F) ile Değiştirilecek Ctrl + Shift + R ile ((MacO'larda Command + Shift + R))


Bu tutulma projeleriyle açık bir çalışma gibi görünüyor. Arama seçeneği android stüdyolarında bile mevcut değildir.
Simon

2
Android Studio'da Ctrl + Shift + F kısayoluyla benzer aramayı yapabilirsiniz
Lins Louis

Sorudaki örnek kod, bunun neden güvenilir olmadığını açıklar.
Nicolas Raoul

Günlük'te bulunan komutların kaldırılmasında sorunlara neden olabilir. Örneğin chocolateLog.recipie ();
Andrew S

Android Studio 2.1 için bu seçenek bulunamadı. Ayrıca, normal arama / değiştirme ile bir seferde 1 dosya üzerinde bu hile kullanabilirsiniz.
VVB

3

Çok basit bir çözümüm var. Geliştirme için IntelliJ kullanıyorum, bu yüzden ayrıntılar değişiyor, ancak fikir tüm IDE'ler için geçerli olmalı.

Kaynak ağacımın kökünü seçiyorum, sağ tıklayın ve "değiştir" i seçin. Daha sonra "Günlük" ü değiştirmeyi seçtim. "// Günlük" ile. Bu, tüm günlük ifadelerini kaldırır. Onları daha sonra geri koymak için aynı "" Log "yerine bu kez tekrar ediyorum. "Log."

Benim için harika çalışıyor. Yalnızca "İletişim Kutusu" gibi kazaları önlemek için değiştirmeyi büyük / küçük harfe duyarlı olarak ayarlamayı unutmayın. Daha fazla güvence için ilk adımı "Günlük" ile de yapabilirsiniz. aranacak dize olarak.

Parlak.


2
Lütfen sorumdaki "Günlük satırına yorum yaparsam" paragrafını okuyun .
Nicolas Raoul

Tamam, evet cevaplara göz attıktan sonra daha sık tekrar okumalıyım :). Bu tür durumlarınız varsa, tüm günlüklerinizi başka bir arayüzün arkasına koymak gibi daha önce önerilen gibi farklı bir çözüm isteyebilirsiniz. Benim önerim belki de insanların ekstra günlük kütüklerinin yükünü önlemek istediği daha küçük ekipler ve projeler için daha iyi çalışır, insanları bilir ve iyi kodlar vb.
kg_sYy

1
Log.d yerine; // // // bu "If" senaryosunu da yerine getirir.
Jasper

3

As zserge 'in yorumları önerdi

Kereste çok güzel, ancak zaten mevcut bir projeniz varsa - github.com/zserge/log'u deneyebilirsiniz. Bu android.util.Log için bir açılan yedek ve Kereste'nin sahip olduğu özelliklerin çoğuna ve daha fazlasına sahiptir.

kütük kütüphanesi , aşağıdaki gibi basit etkinleştirme / devre dışı bırakma günlük yazdırma anahtarı sağlar.

Ayrıca, yalnızcaimport satırların değiştirilmesi gerekir ve hiçbir şeyinLog.d(...); ifade için değiştirilmesi gerekmez.

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

Bu kod satırını her bir Faaliyete / Parçaya mı yoksa sadece bir yere mi koymak zorundasınız?
Noah Ternullo

@NoahTernullo // türetilmiş Uygulama dosyasında. DefaultApplication.java
Youngjae

1

Farklı günlük düzeyleri için destek sağlayarak ve kodun canlı bir aygıtta veya öykünücüsünde çalıştırılmasına bağlı olarak günlük düzeylerini otomatik olarak değiştirerek yukarıdaki çözümde iyileştirmeler yaptım.

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
Önceki çözümle aynı problem. String parametresi pahalı çağrılar kullanılarak oluşturulmuşsa, yine de kaynakları boşa harcar. Çağrı kontrolü, geçirilen parametreleri oluşturmadan önce yapılmalıdır.
type-a1pha

1

ProGuard sizin için sürüm yapınızı ve şimdi android.com'dan iyi haberleri sizin için yapacak:

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

ProGuard aracı, kullanılmayan kodu kaldırarak ve sınıfları, alanları ve yöntemleri semantik olarak belirsiz adlarla yeniden adlandırarak kodunuzu küçültür, optimize eder ve gizler. Sonuç, tersine mühendislik daha zor olan daha küçük boyutlu bir .apk dosyasıdır. ProGuard uygulamanızı tersine mühendislikle zorlaştırdığından, uygulamanız Uygulamalarınızı Lisanslarken olduğu gibi güvenliğe duyarlı özellikleri kullandığında kullanmanız önemlidir.

ProGuard, Android derleme sistemine entegre edilmiştir, bu yüzden manuel olarak çağırmanız gerekmez. ProGuard yalnızca uygulamanızı serbest bırakma modunda oluşturduğunuzda çalışır, bu nedenle uygulamanızı hata ayıklama modunda oluşturduğunuzda gizli kodla uğraşmanız gerekmez. ProGuard'ın çalıştırılması tamamen isteğe bağlıdır, ancak şiddetle tavsiye edilir.

Bu belgede, gizlenmiş yığın izlerinin kodunu çözmek için ProGuard'ın nasıl etkinleştirileceği ve yapılandırılacağı ve geri çekme aracının nasıl kullanılacağı açıklanmaktadır


2
Yine de, varsayılan olarak hata ayıklama günlüğünü kaldırmıyor gibi görünüyor. Christopher'ın cevabı daha iyi geliyor.
Nicolas Raoul

0

Log.d (TAG, bazı dize, genellikle bir String.format ()) kullanmayı seviyorum.

TAG her zaman sınıf adıdır

Log.d'yi dönüştürün (TAG, -> Logd (sınıfınızın metninde)

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

Bu şekilde, bir yayın sürümü oluşturmaya hazır olduğunuzda, MainClass.debug dosyasını false olarak ayarlayın!


1
bu ve diğer çözümlerle ilgili sorun, onları korumak veya yorumlamak, kodda bırakmanız ve büyük miktarda dize oluşturmasına neden olmanızdır. ortalama bir uygulamada sorun değil, ancak optimize etmeye çalışıyorsanız sorun haline gelir.
Lassi Kinnunen

0

Günlükler linux ve sed'de bash kullanılarak kaldırılabilir:

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

Çok satırlı günlükler için çalışır. Bu çözümde, günlüklerin üretim kodunda bulunmadığından emin olabilirsiniz.


0

Bunun eski bir soru olduğunu biliyorum, ama neden tüm günlük çağrılarınızı Boolean logCallWasHere = true; // --- burada kalan günlüğünüz

Bu yüzden onları ne zaman geri koymak istediğinizi bileceksiniz ve if deyimi çağrınızı etkilemeyecek :)


İlginçtir, umarım bu tür hatlar derleyici / iyileştirici tarafından göz ardı edilir. Değişken adının benzersiz olması gerekir, çünkü bazı yöntemlerin birkaç günlük çağrısı vardır ve aynı değişkeni iki kez bildiremezsiniz.
Nicolas Raoul

Etkinlikte en üstteki değişkeni bildirebilir ve boolean bildirimini bu satırdan kaldırabilirsiniz;)
masood elsad

0

Neden sadece

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

? Ek kitaplığa gerek yok, projeyi bozma eğilimi olan hiçbir koruma kuralı yok ve java derleyici, sürüm oluştururken bu çağrı için bayt kodunu dışarıda bırakacak.


Rahatsız edici bir şey, sadece yazmaktan daha ayrıntılı olması Log.d("tag","msg");ve ayrıca if(BuildConfig.DEBUG)parçayı yazmayı unutmanın da kolay olmasıdır .
Nicolas Raoul

1
Bununla ilgili bir başka sorun da, dizelerin paketlenmiş sürümde kalmasıdır.
straya

0

Ek kütüphanelerle uğraşmak veya kodunuzu manuel olarak düzenlemek istemiyorsanız çözümüm burada. Oluşturduğum bu Jupyter dizüstü tüm java dosyalarını gidip bütün Günlüğü iletileri yorum yapmak. Mükemmel değil ama benim için işi halletti.


0

benim yolum:

1) Sütun Seçim Modunu etkinleştir (alt + üst karakter + insert)

2) bir Günlük seçin. D (TAG, "metin"); 'Günlük' bölümü.

3) sonra shift + ctrl + alt + j yapın

4) Sol oku tıklayın

5) Shift + End Yap

6) Sil tuşuna basın.

bu, tüm LOG çağrılarını bir java dosyasında bir kerede kaldırır.


0

Bu basit geleneksel yöntemi kullanmayı deneyebilirsiniz:

Ctrl+ Shift+R

değiştirmek

Log.e(

İle

// Log.e(

Bu, soruda verilen örnek kodla iyi çalışmaz.
Nicolas Raoul

0

Kotlin ile kolay, sadece birkaç üst düzey işlevi beyan edin

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

en basit yol;

kullanım DebugLog

Uygulama serbest bırakıldığında tüm günlükler DebugLog tarafından devre dışı bırakılır.

https://github.com/MustafaFerhan/DebugLog


Bu kesinlikle yanlış. Bu yalnızca günlüklerin günlüğe kaydedilmemesine neden olur, bunları koddan kaldırmaz, bu nedenle kodunuzu tersine mühendislik işlemlerine yardımcı olmak için hala oradalar ve yine de tüm bu günlüklerin dizelerini biçimlendirme maliyeti vardır.
Glenn Maynard
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.