5

I am trying to use proguard with my android app and am using the samsung accesory sdk which keeps giving be trouble.

No matter what I try in the proguard configuration I can't seem to get past this runtime exception:

07-21 13:44:12.851: E/SAAgent(3563): <init> []

07-21 13:44:12.851: E/SAAgent(3563): java.lang.NoSuchMethodException: <init> []

...

07-21 13:44:12.851: E/AndroidRuntime(3563): Caused by: java.lang.RuntimeException: Invalid implemetation of SASocket. Provider a public default constructor.

...

Does anyone have any idea on what to try?

4

3 回答 3

5

问题是,开启一些优化后,Proguard 将更改顶级类中的每个内部类。

这意味着内部类的默认构造函数将与一个接受外部类实例的单参数构造函数进行交换,因为在 java 中,内部类保持对外部类的引用。

Samsung Accesory SDK 需要 SASocket 内部类实现的默认构造函数,因为我猜他们使用反射来实例化该对象。

在这里http://sourceforge.net/p/proguard/bugs/387/您可以阅读:“Outer$Inner 不会更改为顶级类,除非您还将 -repackageclasses 和 -allowaccessmodification 添加到配置中”。

不幸的是,这些标志通常是从 proguard-android-optimize.txt 继承的,如果你想继续优化,解决方案是添加到你的 proguard 配置中:

-keepattributes InnerClasses

请注意,为了能够使用 Samsung Accesory SDK 的全部功能,您还应该包括以下规则:

# Based on http://proguard.sourceforge.net/manual/examples.html#library 

-keep public class com.samsung.** { 
    public protected *; 
}   

-keepclassmembernames class com.samsung.** {    
    java.lang.Class class$(java.lang.String);   
    java.lang.Class class$(java.lang.String, boolean);  
}   

-keepclasseswithmembernames class com.samsung.** {  
    native <methods>;   
}   

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

-keepclassmembers class com.samsung.** implements java.io.Serializable {    
    static final long serialVersionUID; 
    private 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(); 
}
于 2014-07-26T10:01:10.020 回答
3

只需将此答案添加为替代方案更新到现有答案即可。

最近将三星的 Accessory SDK 集成到 Android 的“配套”应用程序中以支持 Galaxy Gear S2 上的 Tizen 应用程序,我在编译配套应用程序的(缩小的)发布版本时遇到了同样的问题。

@while 的回答已经解释了NoSuchMethodException抛出的原因和补救措施。但是,我发现概述的 Proguard 规则相当宽松且数量众多。这对于旧版本的 Accessory SDK 可能是必需的,但现在您可以使用更少的排除项来实现。

假设您使用的是较新的 Accessory SDK 版本之一(我测试了 2.2.2 和 2.3.0),您仍然需要从以下内容开始:

-keepattributes InnerClasses 

您无法解决这个问题,因为SAAgent使用反射来实例化SASocket您在自己代码中某处实现的实例。此规则确保内部和外部类之间的关系(和命名)不会改变。

现在,您可能会想SASocket通过添加排除来编写规则以保留实现的默认构造函数<init>()。不幸的是,这不起作用,因为作为代码优化的一部分,Proguard 实际上会在内部类中创建一个参数化构造函数,该构造函数接受外部类的实例。结果,该构造函数没有被保留和剥离,因为 Proguard 认为没有人在调用它。

因此,长话短说,要同时保留您的SASocket实现及其构造函数,请添加一条规则:

-keep class * extends com.samsung.android.sdk.accessory.SASocket { <init>(...); }

到目前为止,如果没有上述规则,您的应用程序可能会在运行时崩溃。添加它们后,情况将不再如此。但是,您会注意到 Accessory SDK 仍会记录各种错误,并且您的应用程序尚未按预期运行。检查 Logcat,您应该会看到错误,表明 SDK 无法绑定到您的服务。

造成这种情况的原因可能并不明显,但是如果您深入研究 Accessory SDK,您会注意到一些IInterfaceBinder扩展(即在IDeathCallbackand ISAFrameworkManager(2.2.2) 或ISAFrameworkManagerV2(2.3.0) 中)。由于 Proguard 找不到对它们的任何显式调用,并且不知道这些实际上是由 Android 框架在运行时调用的,因此它会将它们剥离。所以,让我们添加一个规则来阻止 Proguard 这样做:

-keep class com.samsung.accessory.api.* extends android.os.Binder { *; }

在此之后,是时候恭喜了:您的服务现在应该可以再次绑定了。根据您的实现,您可能需要进一步的例外,但对于基本设置,上面应该可以解决问题。

加起来,你的配置中应该有以下规则:

# 
# Samsung Accessory SDK Proguard Rules
# 

# Keep relationship between inner and outer classes
-keepattributes InnerClasses

# Keep any SASocket implementation and its constructors
-keep class * extends com.samsung.android.sdk.accessory.SASocket { <init>(...); }

# Keep the Accessory SDK's IInterface and Binder classes
-keep class com.samsung.accessory.api.* extends android.os.Binder { *; }

YMMV。

于 2015-11-26T20:18:51.693 回答
0

尝试了上面的建议,但仍然有崩溃归因于SAPeerAccessory (可能还有其他一些)实现的Parcelable接口,以及其他实现IInterface的类:

public class SAPeerAccessory implements Parcelable

我自己的通过GSON可序列化的类也有问题(下面示例中的最后一行)。这就是我对 proguard-rules.pro 所做的更改的样子

-keepattributes SourceFile,LineNumberTable,InnerClasses,EnclosingMethod,Signature 

-keep class * extends com.samsung.android.sdk.accessory.SASocket { <init>(...); }

# Keep the Accessory SDK's IInterface, Binder, and Prcelable classes
-keep class com.samsung.** extends android.os.Binder { *; }
-keep class com.samsung.** extends android.os.IInterface { *; }
-keep class com.samsung.** extends android.os.Parcelable { *; }
# This is for my own class implementing a model serializable by GSON
-keep class my.gson.Model { <fields>; }

到目前为止没有崩溃,而 APK 的大小减少了 20%

我项目中三星的 lib 版本

accessory-v2.5.3.jar
sdk-v1.0.0.0.jar
于 2018-06-21T04:45:37.257 回答