3

当我在手机上安装我的应用程序时出现异常。它可以在没有 proguard 的情况下工作。我的配置有什么问题?非常感谢你!该配置是我在某处找到的默认 android 配置。不知道怎么回事

D/AndroidRuntime(15388): Shutting down VM
W/dalvikvm(15388): threadid=1: thread exiting with uncaught exception (group=0x40c3a1f8)
E/AndroidRuntime(15388): FATAL EXCEPTION: main
E/AndroidRuntime(15388): java.lang.NullPointerException
E/AndroidRuntime(15388): at aV.setViewValue(SourceFile:163)
E/AndroidRuntime(15388): at android.widget.SimpleAdapter.bindView(SimpleAdapter.java:168)
E/AndroidRuntime(15388): at android.widget.SimpleAdapter.createViewFromResource(SimpleAdapter.java:126)
E/AndroidRuntime(15388): at android.widget.SimpleAdapter.getView(SimpleAdapter.java:114)
E/AndroidRuntime(15388): at android.widget.AbsListView.obtainView(AbsListView.java:2214)
E/AndroidRuntime(15388): at android.widget.ListView.makeAndAddView(ListView.java:1774)
E/AndroidRuntime(15388): at android.widget.ListView.fillDown(ListView.java:672)
E/AndroidRuntime(15388): at android.widget.ListView.fillFromTop(ListView.java:732)
E/AndroidRuntime(15388): at android.widget.ListView.layoutChildren(ListView.java:1625)
E/AndroidRuntime(15388): at android.widget.AbsListView.onLayout(AbsListView.java:2044)
E/AndroidRuntime(15388): at android.view.View.layout(View.java:11418)
E/AndroidRuntime(15388): at android.view.ViewGroup.layout(ViewGroup.java:4224)
E/AndroidRuntime(15388): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
E/AndroidRuntime(15388): at android.view.View.layout(View.java:11418)
E/AndroidRuntime(15388): at android.view.ViewGroup.layout(ViewGroup.java:4224)
E/AndroidRuntime(15388): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
E/AndroidRuntime(15388): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
E/AndroidRuntime(15388): at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
E/AndroidRuntime(15388): at android.view.View.layout(View.java:11418)
E/AndroidRuntime(15388): at android.view.ViewGroup.layout(ViewGroup.java:4224)
E/AndroidRuntime(15388): at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
E/AndroidRuntime(15388): at android.view.View.layout(View.java:11418)
E/AndroidRuntime(15388): at android.view.ViewGroup.layout(ViewGroup.java:4224)
E/AndroidRuntime(15388): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1628)
E/AndroidRuntime(15388): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2585)
E/AndroidRuntime(15388): at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(15388): at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(15388): at android.app.ActivityThread.main(ActivityThread.java:4507)
E/AndroidRuntime(15388): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(15388): at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(15388): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
E/AndroidRuntime(15388): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
E/AndroidRuntime(15388): at dalvik.system.NativeStart.main(Native Method)

这是我的 proguard 配置

-injars      bin/classes
-injars      libs
-outjars     bin/classes-processed.jar

-libraryjars /libs/android-support-v13.jar



#
# This ProGuard configuration file illustrates how to process Android
# applications.
# Usage:
#     java -jar proguard.jar @android.pro
#
# If you're using the Android SDK (version 2.3 or higher), the android tool
# already creates a file like this in your project, called proguard.cfg.
# It should contain the settings of this file, minus the input and output paths
# (-injars, -outjars, -libraryjars, -printmapping, and -printseeds).
# The generated Ant build file automatically sets these paths.

# Specify the input jars, output jars, and library jars.
# Note that ProGuard works with Java bytecode (.class),
# before the dex compiler converts it into Dalvik code (.dex).



    # Save the obfuscation mapping to a file, so you can de-obfuscate any stack
    # traces later on.

    -printmapping bin/classes-processed.map

    # You can print out the seeds that are matching the keep options below.

    #-printseeds bin/classes-processed.seeds

    # Preverification is irrelevant for the dex compiler and the Dalvik VM.

    -dontpreverify

    # Reduce the size of the output some more.

    -repackageclasses ''
    -allowaccessmodification

    # Switch off some optimizations that trip older versions of the Dalvik VM.

    -optimizations !code/simplification/arithmetic

    # Keep a fixed source file attribute and all line number tables to get line
    # numbers in the stack traces.
    # You can comment this out if you're not interested in stack traces.

    -renamesourcefileattribute SourceFile
    -keepattributes SourceFile,LineNumberTable

    # RemoteViews might need annotations.

    -keepattributes *Annotation*

    # Preserve all fundamental application classes.

    -keep public class * extends android.app.Activity
    -keep public class * extends android.app.Application
    -keep public class * extends android.app.Service
    -keep public class * extends android.content.BroadcastReceiver
    -keep public class * extends android.content.ContentProvider

    # Preserve all View implementations, their special context constructors, and
    # their setters.

    -keep public class * extends android.view.View {
        public <init>(android.content.Context);
        public <init>(android.content.Context, android.util.AttributeSet);
        public <init>(android.content.Context, android.util.AttributeSet, int);
        public void set*(...);
    }

    # Preserve all classes that have special context constructors, and the
    # constructors themselves.

    -keepclasseswithmembers class * {
        public <init>(android.content.Context, android.util.AttributeSet);
    }

    # Preserve all classes that have special context constructors, and the
    # constructors themselves.

    -keepclasseswithmembers class * {
        public <init>(android.content.Context, android.util.AttributeSet, int);
    }

    # Preserve the special fields of all Parcelable implementations.

    -keepclassmembers class * implements android.os.Parcelable {
        static android.os.Parcelable$Creator CREATOR;
    }

    # Preserve static fields of inner classes of R classes that might be accessed
    # through introspection.

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

    # Preserve the required interface from the License Verification Library
    # (but don't nag the developer if the library is not used at all).

    #-keep public interface com.android.vending.licensing.ILicensingService

    #-dontnote com.android.vending.licensing.ILicensingService

    # The Android Compatibility library references some classes that may not be
    # present in all versions of the API, but we know that's ok.

    -dontwarn android.support.**

    # Preserve all native method names and the names of their classes.

    -keepclasseswithmembernames class * {
        native <methods>;
    }

    # Preserve the special static methods that are required in all enumeration
    # classes.

    -keepclassmembers class * extends java.lang.Enum {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }

    # Explicitly preserve all serialization members. The Serializable interface
    # is only a marker interface, so it wouldn't save them.
    # You can comment this out if your application doesn't use serialization.
    # If your code contains serializable classes that have to be backward 
    # compatible, please refer to the manual.

    #-keepclassmembers class * implements java.io.Serializable {
    #    static final long serialVersionUID;
    #    static final java.io.ObjectStreamField[] serialPersistentFields;
    #    private void writeObject(java.io.ObjectOutputStream);
    #    private void readObject(java.io.ObjectInputStream);
    #    java.lang.Object writeReplace();
    #    java.lang.Object readResolve();
    #}

    # Your application may contain more items that need to be preserved; 
    # typically classes that are dynamically created using Class.forName:

    # -keep public class mypackage.MyClass
    # -keep public interface mypackage.MyInterface
    # -keep public class * implements mypackage.MyInterface

    # Needed by google-api-client to keep generic types and @Key annotations accessed via reflection
    -keepclassmembers class * {
      @com.google.api.client.util.Key <fields>;
    }

    -keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault,*Annotation*

    -dontwarn sun.misc.Unsafe





    -keepattributes 
    -dontoptimize


    #-dontshrink 
4

2 回答 2

3

设置场景

我目前有完全相同的问题。parent我使用带有和false作为第二个和第三个参数的格式,使用带有布局充气器的自定义适配器完美地工作代码。

由于代码在没有混淆的情况下运行良好,我有足够的信心忽略 stackoverflow 上关于null由于错误使用 Android API 而返回视图的所有问题和响应。

如果您也有没有混淆的问题,请忽略此答案和问题并继续前进!检查这些问题

我会尽力在这个答案中报告我的发现。这个答案可能会随着时间的推移而增长。如果您渴望了解最新消息,请跳至底部的结论。

快速而肮脏的解决方案

这里直接的解决方案是更新您的 proguard 配置以排除您的代码在混淆后失败的类。

在你的 proguard 配置文件中应该是这样的:

-keep class * extends your.company.secret.package

有关 proguard 的更多信息,请从此处开始。还要确保您至少拥有 Android 项目所需的最低限度的 proguard 配置文件。检查这个例子

映射回您的源代码

在研究这个时,您可能会对混淆之前该类的原始名称感兴趣。那应该会容易得多。您可以在项目的 bin 文件夹中的 mapping.txt 文件的 proguard 文件夹中找到此映射。

/bin/proguard/mapping.txt

固定到以下代码行

就我而言,我能够确定以下代码行中的错误。这些行仅出现在失败的适配器中,而其他代码与工作适配器相同。以下所有代码都是该getView(final int position, View convertView, final ViewGroup parent):View方法的一部分

holder.layout.removeAllViews();
TextView tView;
for (final String text : mItems.getTextList()) {
    tView = new TextView(mContext);
    tView.setTextSize(14);
    tView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
    tView.setText(text);
    holder.layout.addView(tView);
}

如果我只是删除addView()andremoveAllViews()调用,那么一切都会顺利。

安卓源代码

我的第一个想法是检查那行代码的源代码。我在堆栈跟踪中找到了以下几点。

11-20 14:19:40.709: E/AndroidRuntime(22236): FATAL EXCEPTION: main
11-20 14:19:40.709: E/AndroidRuntime(22236): Process: your.company.secret.package, PID: 22236
11-20 14:19:40.709: E/AndroidRuntime(22236): java.lang.NullPointerException
11-20 14:19:40.709: E/AndroidRuntime(22236):    at android.widget.AbsListView.obtainView(AbsListView.java:2265)

AbsListView的源代码可以在 grepcode 上找到。但是查看该代码并没有给我很大的勇气在那里找到解决方案。相反,我转向其他资源。以后可能会回到这个。

我在 Android 4.4 设备上执行了这段代码,所以行号甚至不匹配。

在 4.3 设备上测试

正确的代码行是 2177。与此行匹配:

child = mAdapter.getView(position, null, this);

示例项目

有关示例项目,请参阅https://github.com/hanscapelle/so-10822397。您需要 Android Studio (Beta) 0.8.2 和最新的构建工具。我还必须手动获取 proguard-android.txt 文件并将其放置到位。

您可以注释掉适配器中对静态 ViewHolder 类的布局字段起作用的行。一旦启用 proguard 并且应用程序在设备上运行,这些就会失败。

我接下来打算做的事情

  • (完成)我在代码中有其他适配器,即使在混淆后也能正常工作。我将检查这些与失败的差异

  • (完成)我真的必须检查 4.3 设备,这样我才能正确查看 Android 源代码。

  • (DONE) 创建示例项目

  • TODO 用样例项目完成分析

结论

似乎与getView()自定义适配器的方法中动态添加视图有关。结合代码混淆。

于 2013-11-20T14:13:38.410 回答
0

尝试关闭更多可能会破坏 Dalvik 的优化。经过进一步检查,您实际上似乎正在禁用所有优化。

-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

也试着保存这些..

-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService

编辑:这是我的 proguard 文件,想知道是否只是替换它会起作用。它是 ADT 生成的默认文件,所以这里没什么特别的。

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService

-keepclasseswithmembernames class * {
    native <methods>;
}

-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

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

-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
于 2012-05-30T19:19:26.613 回答