2011-08-17 38 views
20

thể trùng lặp:
Removing unused strings during ProGuard optimisationLoại bỏ khai thác gỗ với ProGuard không loại bỏ các dây đang được đăng nhập

Tôi có một ứng dụng Android với hàng chục báo cáo khai thác gỗ. Tôi muốn họ sẽ không xuất hiện trong phiên bản phát hành, vì vậy tôi sử dụng Proguard với một cái gì đó như thế này trong proguard.cfg file:

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

Nhưng vấn đề là có rất nhiều Log.d("something is " + something), và mặc dù Log.d() tuyên bố đang được xóa khỏi bytecode, các chuỗi vẫn còn ở đó.

Vì vậy, sau this câu trả lời, tôi đã tạo ra một lớp wrapper đơn giản, một cái gì đó dọc theo dòng:

public class MyLogger { 
    public static void d(Object... msgs) { 
     StringBuilder log = new StringBuilder(); 
     for(Object msg : msgs) { 
      log.append(msg.toString()); 
     } 
     Log.d(TAG, log.toString()); 
    } 
} 

Sau đó, tôi thay đổi nội dung của tôi proguard.cfg:

-assumenosideeffects class my.package.MyLogger { 
    public static *** d(...); 
} 

Nhưng chuỗi vẫn tìm thấy trong bytecode được tạo ra!

Khác với điều này, tôi đang sử dụng tiêu chuẩn proguard.cfg do Android SDK cung cấp. Tôi có làm điều gì sai?


Sửa: sau khi kiểm tra các bytecode tạo ra, tôi thấy rằng các dây ở đó, nhưng họ không được nối với nhau như tôi nghĩ. Họ đã được được lưu trữ trong một mảng. Tại sao? Để chuyển chúng thành các tham số biến cho phương thức của tôi. Dường như ProGuard không thích điều đó, vì vậy tôi sửa đổi lớp logger của tôi như thế này:

public static void d(Object a) { 
    log(a); 
} 

public static void d(Object a, Object b) { 
    log(a, b); 
} 

(... I had to put like seven d() methods ...) 

private static void log(Object... msgs) { 
    (same as before) 
} 

Nó xấu xí, nhưng bây giờ các dây là đâu trong bytecode.

Đây có phải là một số lỗi/giới hạn của ProGuard không? Hay chỉ là tôi không hiểu nó hoạt động như thế nào?

+0

Bạn có thể muốn tránh hacks proguard và chỉ cần sử dụng một hằng số: http://stackoverflow.com/questions/4199563/android-util-log-when-publishing-what-can-i-do-not-do Nếu sau đó bạn sử dụng một proguard liên tục sẽ loại bỏ các dòng mã khi nó == false. – Blundell

+2

Đúng là đây là một hack, và một cái xấu xí, nhưng tôi nghĩ nó tốt hơn là đặt 'if (DEBUG)' ở khắp mọi nơi. Mã kết quả là sạch hơn và kết quả là như nhau trong ứng dụng đã xuất. Ngoài ra, vì một số lý do, Eclipse đang rên rỉ về mã chết nếu hằng số gỡ lỗi là sai, và tôi không thích điều đó. Cảm ơn ý tưởng, mặc dù :) –

+0

Lưu ý rằng vẫn có thể có một số mã chết nếu bạn chuyển các loại dữ liệu cơ bản. Proguard không loại bỏ kiểu dữ liệu cơ bản để chuyển đổi 'Object' tương ứng. Ví dụ. nếu bạn vượt qua một 'int', Proguard sẽ để lại trong dòng' Integer.valueOf (someVar); ' – crazymaik

Trả lời

11

Giải pháp của bạn với các phương pháp khác nhau cho các số đối số khác nhau có lẽ là cách thuận tiện nhất. Một phương thức duy nhất có số lượng đối số thay đổi sẽ đẹp hơn, nhưng phiên bản hiện tại của ProGuard không đủ thông minh để loại bỏ tất cả mã không sử dụng.

Trình biên dịch java biên dịch một số biến đối số dưới dạng đối số mảng đơn. Về phía yêu cầu, điều này có nghĩa là tạo ra một mảng có kích thước phù hợp, điền vào các phần tử và chuyển nó tới phương thức. ProGuard thấy rằng mảng đang được tạo và sau đó được sử dụng để lưu trữ các phần tử trong đó. Nó không nhận ra (chưa) rằng nó sau đó không được sử dụng cho các hoạt động hữu ích thực tế, với lời gọi phương thức được đi. Kết quả là việc tạo và khởi tạo mảng được bảo toàn.

Thực tiễn tốt là kiểm tra mã được xử lý nếu bạn đang mong đợi một số tối ưu hóa cụ thể.

+1

Tôi vừa bắt đầu sử dụng bảo vệ chuyên nghiệp để loại bỏ các bản ghi và đang đối mặt với cùng một vấn đề mã chết. Tôi tự hỏi tại sao pro guard không thể loại bỏ các mảng này trong các lần truy cập tiếp theo. Tôi đã thấy các IDE chỉ ra rằng một biến cục bộ không bao giờ được sử dụng. Vì vậy, nó chắc chắn có vẻ như có thể. –

4

Proguard không làm việc với tôi cũng vậy, và tôi không muốn tạo ra một wrapper xung quanh Log, vì vậy tôi đã thử nghiệm các giải pháp sau: Giải pháp

LÀM VIỆC

final static boolean IsDebugging = false; 

và trong mã của bạn:

if(IsDebugging) 
    Log.i(TAG, "Debugging"); 

xem xét mà bạn phải sử dụng thức từ khóa để IsDe bugging trở thành true hoặc false tại thời gian biên dịch và các chuỗi log không xuất hiện trong bytecode cuối cùng.

KHÔNG LÀM VIỆC (IsDebugMode)

public static boolean IsDebugMode(Context context) { 
    PackageManager pm = context.getPackageManager(); 
    PackageInfo pi; 
    try { 
     pi = pm.getPackageInfo(context.getPackageName(),0); 
    } catch (NameNotFoundException e) { 
     return false; 
    } 
    return (pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; 
} 

và trong mã của tôi:

boolean IsDebugging = Utils.IsDebugMode(this); 

    if(IsDebugging) 
     Log.i(TAG, "Debugging"); 

Các giải pháp trên không in bất kỳ Đăng nhập Logcat nhưng chuỗi log được biên dịch và tồn tại trong bytecode cuối cùng là xấu.

Các giải pháp khác là:

KHÔNG LÀM VIỆC (BuildConfid.DEBUG)

if(BuildConfig.DEBUG) 
     Log.i(TAG, "Debugging"); 

Đây là giống như giải pháp IsDebugMode. Nó không in bất cứ điều gì nhưng các chuỗi trong bytecode cuối cùng. Xấu lần nữa!

+0

Vui lòng xem nhận xét thứ hai về câu hỏi của tôi. –

Các vấn đề liên quan