كيفية إزالة جميع مكالمات تسجيل التصحيح قبل بناء إصدار الإصدار من تطبيق Android؟

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

سؤال

وفقا ل Google، يجب علي "إلغاء تنشيط أي مكالمات إلى أساليب السجل في التعليمات البرمجية المصدر"قبل نشر تطبيق Android الخاص بي إلى Google Play. استخراج من القسم 3 من قائمة التحقق من النشر:

تأكد من إلغاء تنشيط التسجيل وتعطيل خيار التصحيح قبل إنشاء طلبك للإصدار. يمكنك إلغاء تنشيط التسجيل عن طريق إزالة المكالمات إلى أساليب السجل في ملفاتك المصدر.

مشروعي مفتوح المصدر كبير وهو ألم يجب القيام به يدويا في كل مرة أفرج عنه. بالإضافة إلى ذلك، فإن إزالة خط السجل أمر صعب للغاية، على سبيل المثال:

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

إذا قمت بتعليق خط السجل، فهناك الحالة تنطبق الشرط على السطر التالي، ولا يتم تحميل الفرص (). هي مثل هذه الحالات نادرة بما فيه الكفاية أستطيع أن أقرر أنه لا ينبغي أن يكون موجودا؟

لذلك، هل هناك طريقة أفضل من التعليمات البرمجية في المصدر للقيام بذلك؟ أو ربما بعض بناء جملة proguard ذكي بكفاءة ولكن بأمان إزالة جميع خطوط السجل؟

هل كانت مفيدة؟

المحلول

أجد حلا أسهل بكثير هو أن ننسى كل if يتحقق في كل مكان واستخدام فقط بروغوارد لتجريد أي Log.d() أو Log.v() طريقة المكالمات عندما نسمي النملة release هدف.

بهذه الطريقة، لدينا دائما معلومات التصحيح التي تكون إخراجها للبناء المنتظم وليس من الضروري إجراء أي تغييرات تعليمية للإصدار. يمكن أن تقوم Proguard أيضا بتمرير متعددة عبر ByTecode لإزالة العبارات الأخرى غير المرغوبة وكتل فارغة ويمكنها إتصل الأساليب القصيرة تلقائيا عند الاقتضاء.

على سبيل المثال، إليك تكوين Proguard أساسي للغاية لالروبوت:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

لذلك ستحفظ ذلك إلى ملف، ثم اتصل ببرنامج Proguard من النملة، ويمر في جرة مجمعة فقط و JAR منصة Android التي تستخدمها.

أنظر أيضا الأمثلة في دليل البروجارد.


تحديث (بعد 4.5 سنوات): في الوقت الحاضر اعتدت الأخشاب لتسجيل أندرويد.

ليس فقط هو أجمل بعض الشيء من الافتراضي Log التنفيذ - يتم تعيين علامة السجل تلقائيا، ومن السهل تسجيل السلاسل والاستثناءات المنسقة - ولكن يمكنك أيضا تحديد سلوكيات تسجيل مختلفة في وقت التشغيل.

في هذا المثال، سيتم كتابة بيانات التسجيل فقط إلى LOGCAT في Bredug Builds من تطبيقي:

تم إعداد الأخشاب في بلدي Application onCreate() طريقة:

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

ثم في أي مكان آخر في الرمز الخاص بي يمكنني تسجيل الدخول بسهولة:

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

انظر تطبيق عينة الأخشاب للحصول على مثال أكثر تقدما، حيث يتم إرسال جميع عبارات السجل إلى Logcat أثناء التطوير، وفي الإنتاج، يتم تسجيل أي بيانات تصحيح، ولكن يتم إبلاغ الأخطاء بصمت إلى Crasslytics.

نصائح أخرى

جميع الإجابات الجيدة، ولكن عندما انتهيت من تطويري، لم أرغب في استخدام أي بيانات حول جميع مكالمات السجل، كما أنني لا أريد استخدام أدوات خارجية.

لذلك الحل الذي أستخدمه هو استبدال فئة Android.util.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);
    }
}

الشيء الوحيد الذي كان علي فعله في جميع الملفات المصدر كان ليحل محل استيراد Android.util.log مع صفي الخاص.

أقترح وجود منطقي ثابت في مكان ما يشير إلى ما إذا كان السجل:

فئة MYDEBUG {ثابت السجل المنطقي النهائي = صحيح؛ }

ثم أينما كنت ترغب في تسجيل الدخول في التعليمات البرمجية الخاصة بك، فقط قم بذلك:

إذا كان (mydebug.log) {إذا (شرط) log.i (...)؛ }

الآن عند تعيين MyDebug.log إلى False، سيقوم المحول البرمجي بإيقاعات جميع التعليمات البرمجية داخل هذه الشيكات (نظرا لأنها نهائية ثابتة، فإنه يعرف وقت ترجمة الوقت غير المستخدم.)

للمشاريع الكبيرة، قد ترغب في البدء في تناول المنطمنون في الملفات الفردية لتتمكن من تمكين أو تعطيل التسجيل بسهولة حسب الحاجة. على سبيل المثال، هذه هي ثوابت الأشجار المختلفة لدينا في إدارة النافذة:

static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG_LAYERS = false;
static final boolean DEBUG_INPUT = false;
static final boolean DEBUG_INPUT_METHOD = false;
static final boolean DEBUG_VISIBILITY = false;
static final boolean DEBUG_WINDOW_MOVEMENT = false;
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;

مع رمز المقابلة مثل:

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

حل كريستوفر بروغوخار هو الأفضل، ولكن إذا لم يكن لديك أي سبب لا تحب بروغوارد، فإليك محلول منخفض التكنولوجيا للغاية:

سجلات التعليق:

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

سجلات uncomment:

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

القيد هو أن إرشادات التسجيل الخاصة بك يجب أن لا تمتد على خطوط متعددة.

(تنفيذ هذه الأسطر في قذيفة UNIX في جذر مشروعك. إذا كنت تستخدم Windows، احصل على طبقة UNIX أو استخدام أوامر Windows المكافئة)

أرغب في إضافة بعض الدعايات حول استخدام Proguard with Android Studio والمتقاطعة، حيث كان لدي الكثير من المشكلات لإزالة خطوط السجل من الثنائي النهائي.

من أجل صنع assumenosideeffects في أعمال Proguard، هناك شرط أساسي.

في ملف MARDLE الخاص بك، يجب عليك تحديد استخدام proguard-android-optimize.txt كملف افتراضي.

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

        // With the file below, it does not work!
        //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

في الواقع، في الافتراضي proguard-android.txt ملف، تم تعطيل التحسين مع العلمين:

-dontoptimize
-dontpreverify

ال proguard-android-optimize.txt الملف لا يضيف تلك الأسطر، لذلك الآن assumenosideeffects يمكن أن تعمل.

ثم، شخصيا، أنا استخدم SLF4J., كلما زاد عرض بعض المكتبات التي يتم توزيعها على الآخرين. الميزة هي أنه بشكل افتراضي لا يوجد إخراج. وإذا كان Integrator يريد بعض مخرجات السجلات، فيمكنه استخدام Logback لنظام Android وتفعيل السجلات، لذا يمكن إعادة توجيه السجلات إلى ملف أو Logcat.

إذا كنت بحاجة فعلا إلى تجريد سجلات المكتبة النهائية، فأنا أضيف بعد ذلك إلى ملف Proguard الخاص بي (بعد تمكين proguard-android-optimize.txt ملف بالطبع):

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

أقترح بشدة باستخدام الأخشاب من جيك وارتن

https://github.com/jakewharton/timber.

يحل مشكلتك مع تمكين / تعطيل PLUS يضيف فئة العلامات تلقائيا

مجرد

public class MyApp extends Application {

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

سيتم استخدام سجلات فقط في إصدار Debug الخاص بك، ثم استخدمها

Timber.d("lol");

أو

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

لطباعة

"صفك / MSG" دون Specyfing العلامة

لقد استخدمت أ Logutils. مثل فئة في تطبيق مثال Google IO. قمت بتعديل هذا لاستخدام تطبيق ثابت تصحيح التطبيق بدلا من buildconfig.debug buildconfig.debug غير موثوق بها. وبعد ثم في فصاتي لدي ما يلي.

import static my.app.util.LogUtils.makeLogTag;
import static my.app.util.LogUtils.LOGV;

public class MyActivity extends FragmentActivity {
  private static final String TAG = makeLogTag(MyActivity.class);

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LOGV(TAG, "my message");
  }
}

أنا أعتبر استخدام Roboguice منشأة تسجيل بدلا من المدمج في Android.util.log

تقوم منشأتهم تلقائيا بتعطيل عمليات تصحيح الأخطاء والسفلات للإصدار. بالإضافة إلى ذلك، تحصل على بعض ميزات Nifty مجانا (مثل سلوك التسجيل القابل للتخصيص، بيانات إضافية لكل سجل وأكثر)

قد يكون استخدام Proguard متاعبا تماما ولن أذهب إلى مشكلة تكوين وجعله الشغل مع طلبك ما لم يكن لديك سبب وجيه لذلك (سجلات تعطيل ليست جيدة)

أنا نشر هذا الحل الذي ينطبق خصيصا لمستخدمي استوديو Android. كما اكتشفت مؤخرا الأخشاب وأستوردها بنجاح في تطبيقي عن طريق القيام بما يلي:

ضع أحدث إصدار من المكتبة في Build.Gradle:

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

ثم في استوديوهات Android، انتقل إلى تحرير -> Find -> استبدال في المسار ...

اكتب في Log.e(TAG, أو ومع ذلك كنت تعرف رسائل السجل الخاصة بك في "Text to find" مربع الكتابة. ثم تحل محلها Timber.e(

enter image description here

انقر فوق بحث ثم استبدال الكل.

ستذهب الآن خدمة Android Studios الآن من خلال جميع ملفاتك في مشروعك واستبدال جميع سجلات الأخشاب.

المشكلة الوحيدة التي تلقيتها مع هذه الطريقة هي أن الخرج يتصدر إلى مليون رسالة خطأ بعد ذلك لأنه لا يمكن العثور على "الأخشاب" في الواردات لكل ملفات Java الخاصة بك. فقط انقر على الأخطاء وسوف تقوم شركة Android Studios باستيراد "الأخشاب" تلقائيا في Java. بمجرد أن تفعل ذلك لجميع ملفات الأخطاء الخاصة بك، سوف يترجم المتدرج مرة أخرى.

تحتاج أيضا إلى وضع هذه القطعة من التعليمات البرمجية الخاصة بك onCreate طريقة الخاص بك Application صف دراسي:

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

سيؤدي ذلك إلى تسجيل التطبيق فقط عندما تكون في وضع التطوير وليس في الإنتاج. يمكنك أيضا BuildConfig.RELEASE لتسجيل الدخول في وضع الإصدار.

لكل android.util.log طريقة لتمكين / تعطيل السجل:

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

افتراضي طريقة isloggable (...) إرجاع FALSE، فقط بعد SetProp في الجهاز يحب هذا:

adb shell setprop log.tag.MyAppTag DEBUG

وهذا يعني أنه يمكن طباعة أي سجل أعلى مستوى التصحيح. مرجع Android Doc:

يتحقق لمعرفة ما إذا كان تسجيل الدخول للعلامة المحددة أو لا يوجد مستغرق في المستوى المحدد. يتم تعيين المستوى الافتراضي لأي علامة على المعلومات. هذا يعني أنه سيتم تسجيل أي مستوى أعلاه وتشمل المعلومات. قبل إجراء أي مكالمات إلى طريقة تسجيل، يجب عليك التحقق لمعرفة ما إذا كان يجب تسجيل علاماتك. يمكنك تغيير المستوى الافتراضي عن طريق تعيين خاصية النظام: 'SetProp log.tag. "حيث المستوى إما حرفيا أو تصحيح أو معلومات أو تحذير أو خطأ أو تأكيدا أو قمع. سيقوم بإيقاف تشغيل جميع تسجيل الدخول لعلمك. يمكنك أيضا إنشاء ملف محلي. باستخدام ملف محلي مع ما يلي فيه: "log.tag. =" ووضع ذلك في /data/local.prop.

لذلك يمكننا استخدام سجل مخصص 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);
    }
}

إذا كنت تستطيع تشغيل استبدال عالمي (مرة واحدة)، وبعد ذلك يحتفظ ببعض اتفاقية الترميز، يمكنك اتباع النمط المستخدم في Android إطار العمل.

بدلا من الكتابة

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

اطلب

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

يمكن الآن Proguard إزالة StringBuilder وجميع السلاسل والأساليب التي يستخدمها في الطريق، من DEX "الأمثل DEX". يستخدم proguard-android-optimize.txt ولا داعي للقلق android.util.log. في الخاص بك proguard-rules.pro:

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

مع برنامج Android Studio Madle Plugin، BuildConfig.تصحيح موثوقة تماما، لذلك لا تحتاج إلى ثوابت إضافية للتحكم في التعرية.

لدي حل بسيط للغاية. يمكنني استخدام Intellij for Development، لذلك تختلف التفاصيل ولكن الفكرة يجب أن تنطبق عبر جميع IDE.

اخترت إلى جذر شجرة المصدر الخاصة بي، انقر بزر الماوس الأيمن وحدد "استبدال". ثم اخترت استبدال كل "السجل". مع "// سجل". هذا يزيل جميع بيانات السجل. لوضعها في وقت لاحق فأركر نفس الاستبدال ولكن هذه المرة مثل استبدال الكل "// السجل". مع "السجل".

يعمل عظيم فقط بالنسبة لي. فقط تذكر تعيين استبدال كحسوس حالة لتجنب حوادث مثل "مربع الحوار". للحصول على ضمان إضافي، يمكنك أيضا القيام بالخطوة الأولى مع "السجل". كسلسلة للبحث.

باهِر.

مثل تعليق zserge اقترحت،

الأخشاب لطيفة جدا، ولكن إذا كان لديك بالفعل مشروع موجود - يمكنك تجربة github.com/zserge/log. إنه بديل من أجل Android.util.log ولديه معظم الميزات التي لدى الأخشاب وأكثر من ذلك.

مكتبة السجل له يوفر مفتاح طباعة تسجيل بسيط تمكين / تعطيل على النحو التالي.

بالإضافة إلى ذلك فقط يتطلب التغيير import خطوط، و لا شيئ يحتاج إلى تغيير ل Log.d(...); بيان.

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

إضافة التالي إلى Proguard-ust.txt. ملف

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

enter image description here

هذا ما اعتدت القيام به على مشاريع Android الخاصة بي ..

في Android Studio يمكننا القيام بعملية مماثلة من قبل، CTRL + SHIFT + F للعثور من المشروع بأكمله (أمر + SHIFT + F في MacOS) و Ctrl + Shift + R لاستبداله ((Command + Shift + R في MacOS))

لقد تحسنت على الحل أعلاه من خلال توفير الدعم لمستويات سجل مختلفة ومن خلال تغيير مستويات السجل تلقائيا اعتمادا على ما إذا كان الرمز يتم تشغيله على جهاز مباشر أو على المحاكي.

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


}

ستقوم بروجور بفعل ذلك من أجلك على إصدار إطلاقك والآن الأخبار الجيدة من Android.com:

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

تتقلص أداة Proguard، وتحسين الكود الخاص بك عن طريق إزالة التعليمات البرمجية غير المستخدمة وإعادة تسمية الفصول والحقول والأساليب مع أسماء غامضة دلالة. والنتيجة هي ملف صغير الحجم أصغر من الصعب عكس المهندس. نظرا لأن Proguard يجعل تطبيقك أكثر صعوبة في عكس المهندس، فمن المهم أن تستخدمه عند استخدام تطبيقك الميزات الحساسة للأمان كما لو كنت ترخيص تطبيقاتك.

تتم دمج Proguard في نظام Build Android، لذلك لا يتعين عليك استدعاءها يدويا. يعمل PROGUARD فقط عند إنشاء تطبيقك في وضع الإصدار، حتى لا تضطر إلى التعامل مع رمز Obfuscated عند إنشاء تطبيقك في وضع التصحيح. وجود Proguard Run اختياري تماما، ولكن ينصح بشدة.

توضح هذه الوثيقة كيفية تمكين وتكوين Proguard وكذلك استخدام أداة RETRACE لتعريف آثار المكدس Off

أحب استخدام log.d (العلامة، بعض السلسلة، في كثير من الأحيان string.format ()).

العلامة هي دائما اسم الفصل

تحويل LOG.D (العلامة، -> LOGD (في نص الفصل الخاص بك

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

بهذه الطريقة عندما تكون مستعدا لإصدار إصدار الإصدار، قم بتعيين MainClass.debug إلى False!

يمكن إزالة السجلات باستخدام Bash في Linux و SED:

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

يعمل على سجلات Multiline. في هذا الحل، يمكنك التأكد من أن السجلات غير موجودة في رمز الإنتاج.

أعلم أن هذا سؤال قديم، ولكن لماذا لم تحل محل كل مكالمات السجل الخاصة بك بشيء مثل logcallwashere منطقية = صحيح؛ // - - بقية سجلك هنا

لهذا السبب ستعرف متى تريد وضعها مرة أخرى، ولن تؤثر على بيانك إذا كان في بيان :)

لماذا لا تفعل فقط

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

ب لن تكون هناك حاجة إلى مكتبات إضافية، ولا توجد قواعد بروجور التي تميل إلى إبرام المشروع ومجموعة برامج التحويل البرمجي جافا فقط بمغادرة هذه المكالمة عند إنشاء إصدار الإفراج.

أبسط طريقة؛

استعمال DebugLog

يتم تعطيل جميع السجلات بواسطة Debuglog عند إصدار التطبيق.

https://github.com/mustafaferhan/debuglog.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top