我的应用程序在模拟和真实1.6设备上都能完美运行。但是,索尼Xperia X10系列(运行1.6)与java.lang.VerifyError崩溃。 This thread让我相信ProGuard优化可能是罪魁祸首,但如果是这样的话,那么每个运行1.6的设备上都存在问题,而不仅仅是X10?
这是堆栈跟踪:
java.lang.VerifyError: com.twocell.walkabout.Animator
at com.twocell.walkabout.Main.void onCreate(android.os.Bundle)(SourceFile:197)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2390)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2443)
at android.app.ActivityThread.access$2100(ActivityThread.java:117)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1815)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4263)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:799)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)
以下是触发错误的代码(在名为“Animator”的类中):
static void setLayoutAnimation_textFadeIn(ViewGroup vg, Context context)
{
Animation text_fadeIn = AnimationUtils.loadAnimation(context, R.anim.text_fade_in);
LayoutAnimationController controller = new LayoutAnimationController(text_fadeIn, 0.25f);
vg.setLayoutAnimation(controller);
}
来自:
LinearLayout HeaderBar_Text = (LinearLayout) findViewById(R.id.HeaderBar_Text);
Animator.setLayoutAnimation_textFadeIn(HeaderBar_Text, this); // this is line 197
这里是text_fade_in.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="1000"
/>
</set>
我无法访问X10,因此我依赖于通过ACRA提供的堆栈跟踪。
好的,我能够找到运行1.6的X10的旧仿真器图像并重新创建问题。事实证明,它/只是在发布(ProGuard)版本上崩溃。关闭ProGuard,它完美无缺。为什么它只影响X10而不是每一个1.6设备都是问题。以下是我收集模拟器后收集到的一些新信息......
在我的一些活动中,我使用overridePendingTransition
更改为淡入淡出效果,但1.6不支持此功能,因此我使用名为VersionHelper的辅助类:
class VersionHelper
{
static void overrideTransition(Context context)
{
((Activity)context).overridePendingTransition(R.anim.activity_fade_in, R.anim.activity_fade_out);
}
}
从Animator调用它:
static void overrideTransition(Context context)
{
if (Build.VERSION.SDK_INT > 4)
{
VersionHelper.overrideTransition(context);
}
}
这允许1.6设备运行其余代码而不会从不受支持的方法崩溃(感谢Mark Murphy提供此技术)。
现在,堆栈跟踪带有额外的日志数据:
07-19 23:42:29.150: ERROR/dalvikvm(705): Could not find method android.app.Activity.overridePendingTransition, referenced from method com.twocell.walkabout.Animator.overrideTransition
07-19 23:42:29.150: WARN/dalvikvm(705): VFY: unable to resolve virtual method 14: Landroid/app/Activity;.overridePendingTransition (II)V
07-19 23:42:29.150: WARN/dalvikvm(705): VFY: rejecting opcode 0x6e at 0x0012
07-19 23:42:29.150: WARN/dalvikvm(705): VFY: rejected Lcom/twocell/walkabout/Animator;.overrideTransition (Landroid/content/Context;)V
07-19 23:42:29.150: WARN/dalvikvm(705): Verifier rejected class Lcom/twocell/walkabout/Animator;
07-19 23:42:29.160: DEBUG/AndroidRuntime(705): Shutting down VM
07-19 23:42:29.160: WARN/dalvikvm(705): threadid=3: thread exiting with uncaught exception (group=0x4001aa28)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): Uncaught handler: thread main exiting due to uncaught exception
07-19 23:42:29.160: ERROR/AndroidRuntime(705): java.lang.VerifyError: com.twocell.walkabout.Animator
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at com.twocell.walkabout.Main.onCreate(SourceFile:199)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at android.app.ActivityThread.access$2100(ActivityThread.java:116)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at android.os.Handler.dispatchMessage(Handler.java:99)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at android.os.Looper.loop(Looper.java:123)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at android.app.ActivityThread.main(ActivityThread.java:4203)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at java.lang.reflect.Method.invokeNative(Native Method)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at java.lang.reflect.Method.invoke(Method.java:521)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
07-19 23:42:29.160: ERROR/AndroidRuntime(705): at dalvik.system.NativeStart.main(Native Method)
所以它就是 - 当我使用ProGuard时,只有在X10上,它仍然会看到overridePendingTransition
并且崩溃。 (我确认X10 /是/报告“4”作为其API版本。)
最后,我的proguard.cfg:
-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
-keep class com.android.vending.billing.**
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#ACRA specifics
# we need line numbers in our stack traces otherwise they are pretty useless
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
# ACRA needs "annotations" so add this...
-keepattributes *Annotation*
# keep this class so that logging will show 'ACRA' and not a obfuscated name like 'a'.
# Note: if you are removing log messages elsewhere in this file then this isn't necessary
-keep class org.acra.ACRA {
*;
}
# keep this around for some enums that ACRA needs
-keep class org.acra.ReportingInteractionMode {
*;
}
# keep this otherwise it is removed by ProGuard
-keep public class org.acra.ErrorReporter
{
public void addCustomData(java.lang.String,java.lang.String);
}
# keep this otherwise it is removed by ProGuard
-keep public class org.acra.ErrorReporter
{
public org.acra.ErrorReporter$ReportsSenderWorker handleSilentException(java.lang.Throwable);
}
-keep class org.acra.ReportField {*;}
有什么想法吗?
在ProGuard中使用-dontoptimize
可让应用在X10上运行。我正在偷偷摸摸解决方案。
答案 0 :(得分:3)
ProGuard的优化步骤将内联诸如VersionHelper#overrideTransition()之类的方法,这不是你想要的,因为该方法旨在隔离对1.6的依赖(尽管ProGuard不知道这一点)。
暴力解决方案:关闭所有优化:
-dontoptimize
更细粒度:关闭所有方法内联(如您所知):
-optimizations !method/inlining/*
理想的解决方案:避免内联这种特殊方法及其兄弟姐妹:
-keepclassmembers,allowobfuscation,allowshrinking somepackage.VersionHelper {
<methods>;
}
没有细节,我不能多说其他问题。您可以在ProGuard的帮助论坛上提问。
答案 1 :(得分:1)
您的com.twocell.walkabout.Animator
类实现指的是Xperia X10上不存在的某些类或方法。 不必须限制在静态setLayoutAnimation_textFadeIn()
方法中的某些内容 - 它可以是该类中的任何内容。很遗憾,VerifyError
并未说无法找到。
您必须使用细齿梳子完成您的应用程序,并确定Xperia X10上可能缺少的其他地方。
但是如果是这样的话,那么每个运行1.6的设备上都不存在问题,而不仅仅是X10吗?
是
答案 2 :(得分:1)
解决方法是将-optimizations !method/inlining/unique
添加到proguard.cfg,根据ProGuard的文档通常“内联只调用一次的方法”。我希望我可以说我没有排除每一个优化,然后在构建签名版本时逐个删除它们......但这正是我所做的。
修改(新信息)
当我继续工作时,我发现我的应用程序的其他部分在X10上崩溃,并且需要其他特定的优化排除才能正常工作。我也开始看到一个模式,其中包含来自其他特定设备的崩溃报告不应该发生,实际上不会发生在我自己的测试设备和模拟器上。
我不得不得出结论,我现在不能相信ProGuard的优化。由于问题只发生在特定设备上,我更可能将责任归咎于制造商定制,而不是ProGuard。找到两者之间的实际联系超出了我的能力。
所以我的最终解决方案是使用-dontoptimize
或因为无法解决的问题而冒险获得一星评价。整齐。到目前为止,我从未有人抱怨过平台碎片。这个特别的发现令人非常失望。
编辑2(跟进)
由于我推送更新直接删除了优化,因此所有崩溃都已停止。现在我终于可以回到功能开发了。