2016-10-04 68 views
1

我有Thrift客戶端庫,並且很少在我的應用項目中生成thrift java類。需要幫助瞭解爲什麼未使用的Thrift客戶端庫和生成的類未被Proguard剝離。找到某些類未被Proguard刪除的原因

我已確認代碼縮水啓用

minifyEnabled true 
proguardFiles file('proguard-android.txt') 

我完全我的應用程序裏面註釋掉節儉使用。[早些時候在我的代碼,我只使用一個與互助儲蓄TDeserializer和TSerializer類生成的類和期待Proguard不保留TServer等類,因爲它們沒有被使用。但我注意到它仍然存在。爲了確保它不是間接保留Thrift客戶端類的生成類,我沒有評論這一切]

即使沒有人實際上在我的應用代碼中調用com.test.thrift.Task,seeds.txt仍然顯示出來e com.test.thrift.Task裏面。

我試圖調試爲什麼類沒有被刪除:

使用

它顯示
-verbose 
-whyareyoukeeping class com.offerup.android.thrift.Task { public * ; } 

唯一的事情就是com.offerup.android.thrift.Task 通過在一個指令保持組態。

我試圖刪除一些候選人,如下圖。似乎沒有任何區別。除了蠻力的方式去除所有東西並且弄清楚配置條款,還有更好的方法來知道爲什麼這些類被保存了嗎?

#-keep public class * extends java.lang.Exception 
#-keep class * implements android.os.Parcelable { 
# public static final android.os.Parcelable$Creator *; 
#} 
#-keepclassmembers enum * { 
# public static **[] values(); 
# public static ** valueOf(java.lang.String); 
#} 
#-keep class org.apache.** { *; } 

Proguard的配置是這樣的:

# This is a configuration file for ProGuard. 
# http://proguard.sourceforge.net/index.html#manual/usage.html 

-dontusemixedcaseclassnames 
-dontskipnonpubliclibraryclasses 
-verbose 

# For Fabric (Crashlytics) 
-keep class com.crashlytics.** { *; } 
-keep class com.crashlytics.android.** 
-keepattributes SourceFile,LineNumberTable, *Annotation* 
-keep public class * extends java.lang.Exception 

# Optimization is turned off by default. Dex does not like code run 
# through the ProGuard optimize and preverify steps (and performs some 
# of these optimizations on its own). 

#-dontoptimize 
#-dontpreverify 

# Note that if you want to enable optimization, you cannot just 
# include optimization flags in your own project configuration file; 
# instead you will need to point to the 
# "proguard-android-optimize.txt" file instead of this one from your 
# project.properties file. 

-keepattributes *Annotation* 
-keepclasseswithmembers class * { 
    @retrofit.http.* <methods>; 
} 
#-keep public class com.google.vending.licensing.ILicensingService 
#-keep public class com.android.vending.licensing.ILicensingService 

-keep class com.android.vending.billing.** 

# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native 

#-keepclasseswithmembernames class * { 
# native <methods>; 
#} 

# keep setters in Views so that animations can still work. 
# see http://proguard.sourceforge.net/manual/examples.html#beans 

#-keepclassmembers public class * extends android.view.View { 
# void set*(***); 
# *** get*(); 
#} 

# We want to keep methods in Activity that could be used in the XML attribute onClick 

#-keepclassmembers class * extends android.app.Activity { 
# public void *(android.view.View); 
#} 

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations 

#-keepclassmembers enum * { 
# public static **[] values(); 
# public static ** valueOf(java.lang.String); 
#} 

#-keep class * implements android.os.Parcelable { 
# public static final android.os.Parcelable$Creator *; 
#} 

#-keepclassmembers class **.R$* { 
# public static <fields>; 
#} 

# The support library contains references to newer platform versions. 
# Don't warn about those in case this app is linking against an older 
# platform version. We know about them, and they are safe. 
-dontwarn android.support.** 
-dontwarn com.google.android.** 
-dontwarn retrofit.** 
-dontwarn com.square.** 
-dontwarn com.squareup.** 
-dontwarn org.apache.** 
-dontwarn org.joda.** 
-dontwarn rx.** 

# Jars that we need to keep 
-keep class org.apache.** { *; } 
-keep class org.joda.** { *; } 
-keep class com.google.** { *; } 
-keep class com.mobileapptracker.** { *; } 
-keep class com.urbanairship.** { *; } 
-keep class com.appsflyer.** { *; } 

# Libaries that we need to keep 
# Jumio 
-keep class com.jumio.** { *; } 
-keep class jumiomobile.** { *; } 
-keep class net.sf.scuba.smartcards.IsoDepCardService {*;} 
-keep class org.jmrtd.** { *; } 
-keep class net.sf.scuba.** {*;} 
-keep class org.spongycastle.** {*;} 
-keep class org.ejbca.** {*;} 
-dontwarn org.ejbca.** 
-dontwarn org.spongycastle.** 

# Apptentive 
-dontwarn com.apptentive.android.sdk.** 
-keepattributes SourceFile,LineNumberTable 
-keep class com.apptentive.android.sdk.** { *; } 

-keep class com.facebook.** { *; } 
-keep class com.android.** { *; } 
-keep class uk.co.senab.** { *; } 

# Gradle libraries that we need to keep 
-keep class retrofit.** { *; } 
-keep class com.square.** { *; } 
-keep class com.squareup.** { *; } 
-keep class com.crashlytics.** { *; } 
-keep class com.stripe.** { *; } 

# Android libraries that we need to keep 
#-keep class android.support.** { *; } 
-keep class com.google.android.** { *; } 
#-keep interface android.support.** { *; } 

## 
# Allow obfuscation of android.support.v7.internal.view.menu.** 
# to avoid problem on Samsung 4.2.2 devices with appcompat v21 
# see https://code.google.com/p/android/issues/detail?id=78377 
#-keep class !android.support.v7.internal.view.menu.**,android.support.** {*;} 

# https://code.google.com/p/android/issues/detail?id=78377#c224 
# MenuBuilder not found issue on AppCompat 23.1+. Keep all classes except the ones indicated by the patterns preceded by an exclamation mark 
#http://cudou.com/pages/ddbffhcj-once-again-getting-java-lang-noclassdeffounderror-android-support-v7-internal-v.html 
-keep class !android.support.v7.view.menu.**,!android.support.design.internal.NavigationMenu,!android.support.design.internal.NavigationMenuPresenter,!android.support.design.internal.NavigationSubMenu,** {*;} 

# For otto subscribers/producers 
-keepclassmembers class ** { 
    @com.squareup.otto.Subscribe public *; 
    @com.squareup.otto.Produce public *; 
} 

# More retrofit fixes 
-keep class javax.inject.* { *; } 
-keepattributes Signature 
-keep class sun.misc.Unsafe { *; } 

# okhttp 2.2 fixes 
-dontwarn java.nio.file.* 
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 

# Local files that are needed 
-keep class com.byarger.exchangeit.** { *; } 
-keep class com.test.R { *; } 
-keep class com.test.R$* { *; } 
-keep class com.test.BuildConfig { *; } 
-keep class com.test.Manifest { *; } 
-keep class com.test.Manifest$* { *; } 

# Trying other things to get search to load 

# keep setters in Views so that animations can still work. 
# see http://proguard.sourceforge.net/manual/examples.html#beans 
-keepclassmembers public class * extends android.view.View { 
    void set*(***); 
    *** get*(); 
} 

# Ensure the unreferenced Creator isn't removed by proguard 
-keepclassmembers class * implements android.os.Parcelable { 
    public static final android.os.Parcelable$Creator *; 
} 

# We want to keep methods in Activity that could be used in the XML attribute onClick 
#-keepclassmembers class * extends android.app.Activity { 
# public void *(android.view.View); 
#} 

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations 
-keepclassmembers enum * { 
    public static **[] values(); 
    public static ** valueOf(java.lang.String); 
} 

#-keep class * implements retrofit.Callback { *; } 

-keepclassmembers class com.test.android.activities.BaseActivity { 
    protected android.location.LocationManager mLocationManager; 
} 

-keepclass class com.test.android.bus.BusProvider { *; } 

-keep class com.test.android.gson.** { *; } 

-keep class com.test.android.dto.** { *; } 

-keep class android.support.v7.widget.** {*;} 

-keepclassmembers class * { 
    @com.leanplum.annotations.* <fields>; 
} 

-keep class com.leanplum.** { *; } 
-dontwarn com.leanplum.** 

#RXJava work arounds 
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { 
    long producerIndex; 
    long consumerIndex; 
} 
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { 
    long producerNode; 
    long consumerNode; 
} 

節儉產生的未使用的類是什麼樣子:

/** 
* Autogenerated by Thrift Compiler (0.9.3) 
* 
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 
* @generated 
*/ 
package com.test.thrift; 

import org.apache.thrift.scheme.IScheme; 
import org.apache.thrift.scheme.SchemeFactory; 
import org.apache.thrift.scheme.StandardScheme; 

import org.apache.thrift.scheme.TupleScheme; 
import org.apache.thrift.protocol.TTupleProtocol; 
import org.apache.thrift.EncodingUtils; 

import java.util.List; 
import java.util.ArrayList; 
import java.util.Map; 
import java.util.HashMap; 
import java.util.EnumMap; 
import java.util.EnumSet; 
import java.util.Collections; 
import java.util.BitSet; 

import javax.annotation.Generated; 

@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"}) 
@Generated(value = "Autogenerated by Thrift Compiler (0.9.3)", date = "2016-09-30") 
public class Task implements org.apache.thrift.TBase<Task, Task._Fields>, java.io.Serializable, Cloneable, Comparable<Task> { 
    private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Task"); 

    private static final org.apache.thrift.protocol.TField IDENTIFIER_FIELD_DESC = new org.apache.thrift.protocol.TField("Identifier", org.apache.thrift.protocol.TType.I64, (short)1); 
    private static final org.apache.thrift.protocol.TField DESCRIPTION_FIELD_DESC = new org.apache.thrift.protocol.TField("Description", org.apache.thrift.protocol.TType.STRING, (short)2); 

    private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>(); 
    static { 
    schemes.put(StandardScheme.class, new TaskStandardSchemeFactory()); 
    schemes.put(TupleScheme.class, new TaskTupleSchemeFactory()); 
    } 

    /** 
    * A unique identifier for this task. 
    */ 
    public long Identifier; // required 
    /** 
    * A description of the task. 
    */ 
    public String Description; // required 

    /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ 
    public enum _Fields implements org.apache.thrift.TFieldIdEnum { 
    /** 
    * A unique identifier for this task. 
    */ 
    IDENTIFIER((short)1, "Identifier"), 
    /** 
    * A description of the task. 
    */ 
    DESCRIPTION((short)2, "Description"); 

    private static final Map<String, _Fields> byName = new HashMap<String, _Fields>(); 

    static { 
     for (_Fields field : EnumSet.allOf(_Fields.class)) { 
     byName.put(field.getFieldName(), field); 
     } 
    } 

    /** 
    * Find the _Fields constant that matches fieldId, or null if its not found. 
    */ 
    public static _Fields findByThriftId(int fieldId) { 
     switch(fieldId) { 
     case 1: // IDENTIFIER 
      return IDENTIFIER; 
     case 2: // DESCRIPTION 
      return DESCRIPTION; 
     default: 
      return null; 
     } 
    } 

    /** 
    * Find the _Fields constant that matches fieldId, throwing an exception 
    * if it is not found. 
    */ 
    public static _Fields findByThriftIdOrThrow(int fieldId) { 
     _Fields fields = findByThriftId(fieldId); 
     if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); 
     return fields; 
    } 

    /** 
    * Find the _Fields constant that matches name, or null if its not found. 
    */ 
    public static _Fields findByName(String name) { 
     return byName.get(name); 
    } 

    private final short _thriftId; 
    private final String _fieldName; 

    _Fields(short thriftId, String fieldName) { 
     _thriftId = thriftId; 
     _fieldName = fieldName; 
    } 

    public short getThriftFieldId() { 
     return _thriftId; 
    } 

    public String getFieldName() { 
     return _fieldName; 
    } 
    } 

    // isset id assignments 
    private static final int __IDENTIFIER_ISSET_ID = 0; 
    private byte __isset_bitfield = 0; 
    public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; 
    static { 
    Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); 
    tmpMap.put(_Fields.IDENTIFIER, new org.apache.thrift.meta_data.FieldMetaData("Identifier", org.apache.thrift.TFieldRequirementType.DEFAULT, 
     new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64  , "id"))); 
    tmpMap.put(_Fields.DESCRIPTION, new org.apache.thrift.meta_data.FieldMetaData("Description", org.apache.thrift.TFieldRequirementType.DEFAULT, 
     new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); 
    metaDataMap = Collections.unmodifiableMap(tmpMap); 
    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Task.class, metaDataMap); 
    } 

    public Task() { 
    this.Identifier = -1L; 

    } 

    public Task(
    long Identifier, 
    String Description) 
    { 
    this(); 
    this.Identifier = Identifier; 
    setIdentifierIsSet(true); 
    this.Description = Description; 
    } 

    /** 
    * Performs a deep copy on <i>other</i>. 
    */ 
    public Task(Task other) { 
    __isset_bitfield = other.__isset_bitfield; 
    this.Identifier = other.Identifier; 
    if (other.isSetDescription()) { 
     this.Description = other.Description; 
    } 
    } 

    public Task deepCopy() { 
    return new Task(this); 
    } 

    @Override 
    public void clear() { 
    this.Identifier = -1L; 

    this.Description = null; 
    } 

    /** 
    * A unique identifier for this task. 
    */ 
    public long getIdentifier() { 
    return this.Identifier; 
    } 

    /** 
    * A unique identifier for this task. 
    */ 
    public Task setIdentifier(long Identifier) { 
    this.Identifier = Identifier; 
    setIdentifierIsSet(true); 
    return this; 
    } 

    public void unsetIdentifier() { 
    __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __IDENTIFIER_ISSET_ID); 
    } 

    /** Returns true if field Identifier is set (has been assigned a value) and false otherwise */ 
    public boolean isSetIdentifier() { 
    return EncodingUtils.testBit(__isset_bitfield, __IDENTIFIER_ISSET_ID); 
    } 

    public void setIdentifierIsSet(boolean value) { 
    __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __IDENTIFIER_ISSET_ID, value); 
    } 

    /** 
    * A description of the task. 
    */ 
    public String getDescription() { 
    return this.Description; 
    } 

    /** 
    * A description of the task. 
    */ 
    public Task setDescription(String Description) { 
    this.Description = Description; 
    return this; 
    } 

    public void unsetDescription() { 
    this.Description = null; 
    } 

    /** Returns true if field Description is set (has been assigned a value) and false otherwise */ 
    public boolean isSetDescription() { 
    return this.Description != null; 
    } 

    public void setDescriptionIsSet(boolean value) { 
    if (!value) { 
     this.Description = null; 
    } 
    } 

    public void setFieldValue(_Fields field, Object value) { 
    switch (field) { 
    case IDENTIFIER: 
     if (value == null) { 
     unsetIdentifier(); 
     } else { 
     setIdentifier((Long)value); 
     } 
     break; 

    case DESCRIPTION: 
     if (value == null) { 
     unsetDescription(); 
     } else { 
     setDescription((String)value); 
     } 
     break; 

    } 
    } 

    public Object getFieldValue(_Fields field) { 
    switch (field) { 
    case IDENTIFIER: 
     return getIdentifier(); 

    case DESCRIPTION: 
     return getDescription(); 

    } 
    throw new IllegalStateException(); 
    } 

    /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ 
    public boolean isSet(_Fields field) { 
    if (field == null) { 
     throw new IllegalArgumentException(); 
    } 

    switch (field) { 
    case IDENTIFIER: 
     return isSetIdentifier(); 
    case DESCRIPTION: 
     return isSetDescription(); 
    } 
    throw new IllegalStateException(); 
    } 

    @Override 
    public boolean equals(Object that) { 
    if (that == null) 
     return false; 
    if (that instanceof Task) 
     return this.equals((Task)that); 
    return false; 
    } 

    public boolean equals(Task that) { 
    if (that == null) 
     return false; 

    boolean this_present_Identifier = true; 
    boolean that_present_Identifier = true; 
    if (this_present_Identifier || that_present_Identifier) { 
     if (!(this_present_Identifier && that_present_Identifier)) 
     return false; 
     if (this.Identifier != that.Identifier) 
     return false; 
    } 

    boolean this_present_Description = true && this.isSetDescription(); 
    boolean that_present_Description = true && that.isSetDescription(); 
    if (this_present_Description || that_present_Description) { 
     if (!(this_present_Description && that_present_Description)) 
     return false; 
     if (!this.Description.equals(that.Description)) 
     return false; 
    } 

    return true; 
    } 

    @Override 
    public int hashCode() { 
    List<Object> list = new ArrayList<Object>(); 

    boolean present_Identifier = true; 
    list.add(present_Identifier); 
    if (present_Identifier) 
     list.add(Identifier); 

    boolean present_Description = true && (isSetDescription()); 
    list.add(present_Description); 
    if (present_Description) 
     list.add(Description); 

    return list.hashCode(); 
    } 

    @Override 
    public int compareTo(Task other) { 
    if (!getClass().equals(other.getClass())) { 
     return getClass().getName().compareTo(other.getClass().getName()); 
    } 

    int lastComparison = 0; 

    lastComparison = Boolean.valueOf(isSetIdentifier()).compareTo(other.isSetIdentifier()); 
    if (lastComparison != 0) { 
     return lastComparison; 
    } 
    if (isSetIdentifier()) { 
     lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.Identifier, other.Identifier); 
     if (lastComparison != 0) { 
     return lastComparison; 
     } 
    } 
    lastComparison = Boolean.valueOf(isSetDescription()).compareTo(other.isSetDescription()); 
    if (lastComparison != 0) { 
     return lastComparison; 
    } 
    if (isSetDescription()) { 
     lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.Description, other.Description); 
     if (lastComparison != 0) { 
     return lastComparison; 
     } 
    } 
    return 0; 
    } 

    public _Fields fieldForId(int fieldId) { 
    return _Fields.findByThriftId(fieldId); 
    } 

    public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { 
    schemes.get(iprot.getScheme()).getScheme().read(iprot, this); 
    } 

    public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { 
    schemes.get(oprot.getScheme()).getScheme().write(oprot, this); 
    } 

    @Override 
    public String toString() { 
    StringBuilder sb = new StringBuilder("Task("); 
    boolean first = true; 

    sb.append("Identifier:"); 
    sb.append(this.Identifier); 
    first = false; 
    if (!first) sb.append(", "); 
    sb.append("Description:"); 
    if (this.Description == null) { 
     sb.append("null"); 
    } else { 
     sb.append(this.Description); 
    } 
    first = false; 
    sb.append(")"); 
    return sb.toString(); 
    } 

    public void validate() throws org.apache.thrift.TException { 
    // check for required fields 
    // check for sub-struct validity 
    } 

    private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 
    try { 
     write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); 
    } catch (org.apache.thrift.TException te) { 
     throw new java.io.IOException(te); 
    } 
    } 

    private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { 
    try { 
     // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. 
     __isset_bitfield = 0; 
     read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); 
    } catch (org.apache.thrift.TException te) { 
     throw new java.io.IOException(te); 
    } 
    } 

    private static class TaskStandardSchemeFactory implements SchemeFactory { 
    public TaskStandardScheme getScheme() { 
     return new TaskStandardScheme(); 
    } 
    } 

    private static class TaskStandardScheme extends StandardScheme<Task> { 

    public void read(org.apache.thrift.protocol.TProtocol iprot, Task struct) throws org.apache.thrift.TException { 
     org.apache.thrift.protocol.TField schemeField; 
     iprot.readStructBegin(); 
     while (true) 
     { 
     schemeField = iprot.readFieldBegin(); 
     if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
      break; 
     } 
     switch (schemeField.id) { 
      case 1: // IDENTIFIER 
      if (schemeField.type == org.apache.thrift.protocol.TType.I64) { 
       struct.Identifier = iprot.readI64(); 
       struct.setIdentifierIsSet(true); 
      } else { 
       org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 
      } 
      break; 
      case 2: // DESCRIPTION 
      if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { 
       struct.Description = iprot.readString(); 
       struct.setDescriptionIsSet(true); 
      } else { 
       org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 
      } 
      break; 
      default: 
      org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); 
     } 
     iprot.readFieldEnd(); 
     } 
     iprot.readStructEnd(); 

     // check for required fields of primitive type, which can't be checked in the validate method 
     struct.validate(); 
    } 

    public void write(org.apache.thrift.protocol.TProtocol oprot, Task struct) throws org.apache.thrift.TException { 
     struct.validate(); 

     oprot.writeStructBegin(STRUCT_DESC); 
     oprot.writeFieldBegin(IDENTIFIER_FIELD_DESC); 
     oprot.writeI64(struct.Identifier); 
     oprot.writeFieldEnd(); 
     if (struct.Description != null) { 
     oprot.writeFieldBegin(DESCRIPTION_FIELD_DESC); 
     oprot.writeString(struct.Description); 
     oprot.writeFieldEnd(); 
     } 
     oprot.writeFieldStop(); 
     oprot.writeStructEnd(); 
    } 

    } 

    private static class TaskTupleSchemeFactory implements SchemeFactory { 
    public TaskTupleScheme getScheme() { 
     return new TaskTupleScheme(); 
    } 
    } 

    private static class TaskTupleScheme extends TupleScheme<Task> { 

    @Override 
    public void write(org.apache.thrift.protocol.TProtocol prot, Task struct) throws org.apache.thrift.TException { 
     TTupleProtocol oprot = (TTupleProtocol) prot; 
     BitSet optionals = new BitSet(); 
     if (struct.isSetIdentifier()) { 
     optionals.set(0); 
     } 
     if (struct.isSetDescription()) { 
     optionals.set(1); 
     } 
     oprot.writeBitSet(optionals, 2); 
     if (struct.isSetIdentifier()) { 
     oprot.writeI64(struct.Identifier); 
     } 
     if (struct.isSetDescription()) { 
     oprot.writeString(struct.Description); 
     } 
    } 

    @Override 
    public void read(org.apache.thrift.protocol.TProtocol prot, Task struct) throws org.apache.thrift.TException { 
     TTupleProtocol iprot = (TTupleProtocol) prot; 
     BitSet incoming = iprot.readBitSet(2); 
     if (incoming.get(0)) { 
     struct.Identifier = iprot.readI64(); 
     struct.setIdentifierIsSet(true); 
     } 
     if (incoming.get(1)) { 
     struct.Description = iprot.readString(); 
     struct.setDescriptionIsSet(true); 
     } 
    } 
    } 

} 

回答

3

我也有類似的問題,但ProGuard的不告訴你哪個指令迫使上課要保留。然而,通過看你的配置,我懷疑這條線可能是罪魁禍首:

-keep class !android.support.v7.view.menu.**,!android.support.design.internal.NavigationMenu,!android.support.design.internal.NavigationMenuPresenter,!android.support.design.internal.NavigationSubMenu,** {*;} 

我懷疑最後**可能會迫使所有的類被保留,包括你。

此外,您可以使用ClassyShark來分析您的APK中的類和方法,而無需安裝APK,因此您可以做的一件事是通過您的規則進行二進制搜索,以查看哪些方法可以保留該類。