SAAgent(三星配件)java.lang.NoSuchMethodException的Proguard问题:<;初始化>;[]

SAAgent(三星配件)java.lang.NoSuchMethodException的Proguard问题:<;初始化>;[],java,android,proguard,samsung-mobile,samsung-mobile-sdk,Java,Android,Proguard,Samsung Mobile,Samsung Mobile Sdk,我正在尝试将proguard与我的android应用程序一起使用,并且正在使用三星accesory sdk,这会给我带来麻烦 无论我在proguard配置中尝试什么,我似乎都无法通过此运行时异常: 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

我正在尝试将proguard与我的android应用程序一起使用,并且正在使用三星accesory sdk,这会给我带来麻烦

无论我在proguard配置中尝试什么,我似乎都无法通过此运行时异常:

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.
07-21 13:44:12.851:E/SAAgent(3563):[]
07-21 13:44:12.851:E/SAAgent(3563):java.lang.NoSuchMethodException:[]
...
07-21 13:44:12.851:E/AndroidRuntime(3563):由以下原因引起:java.lang.RuntimeException:SASocket的实现无效。提供程序是公共默认构造函数。


有人知道该尝试什么吗?

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

这意味着内部类的默认构造函数将与获取外部类实例的单参数构造函数交换,因为在java中,内部类保留对外部类的引用

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

在这里您可以看到:“Outer$internal不会更改为顶级类,除非您还向配置中添加了-repackageclasses和-allowaccessmodification”

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

-keepattributes InnerClasses
请注意,为了能够使用三星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(); 
}
基于http://proguard.sourceforge.net/manual/examples.html#library -保持公共类com.samsung.*{ 受公众保护*; } -keepclassmembernames类com.samsung.*{ java.lang.Class类$(java.lang.String); java.lang.Class类$(java.lang.String,布尔值); } -KeepClassSwithMemberNames类com.samsung.*{ 本地人; } -keepclassmembers enum com.samsung.*{ 公共静态**[]值(); 公共静态**valueOf(java.lang.String); } -keepclassmembers类com.samsung.**实现java.io.Serializable{ 静态最终长SerialVersionId; 私有静态final java.io.ObjectStreamField[]serialPersistentFields; 私有void writeObject(java.io.ObjectOutputStream); 私有void readObject(java.io.ObjectInputStream); java.lang.Object WriterReplace(); java.lang.Object readResolve(); }
只需添加此答案作为备选答案,并对现有答案进行更新即可

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

@while的回答已经解释了引发
NoSuchMethodException
的原因和补救方法。然而,我发现概述的Proguard规则相当宽松,而且数量众多。对于旧版本的附件SDK,这可能是必需的,但现在您可能需要更少的排除

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

-keepattributes InnerClasses 
您无法回避这个问题,因为
SAAgent
使用反射来实例化您在自己的代码中实现的
SASocket
的实例。此规则确保内部类和外部类之间的关系(以及命名)不会更改

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

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

-keep class * extends com.samsung.android.sdk.accessory.SASocket { <init>(...); }
在此之后,是时候祝贺您了:您的服务现在应该可以再次绑定了。根据您的实现,您可能需要更多的例外情况,但对于基本设置,上述方法应该可以实现

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

# 
# 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 { *; }
#
#三星附件SDK Proguard规则
# 
#保持内部类和外部类之间的关系
-keepattributes内部类
#保留任何SASocket实现及其构造函数
-keep class*扩展com.samsung.android.sdk.accessory.SASocket{(…);}
#保留附件SDK的界面和活页夹类
-keep class com.samsung.association.api.*扩展了android.os.Binder{*;}

YMMV.

尝试了上述建议,但仍然由于SAPeerAccessory实现的Parcelable接口(可能由其他人实现)以及其他实现IInterface的类而导致崩溃:

public class SAPeerAccessory implements Parcelable
accessory-v2.5.3.jar
sdk-v1.0.0.0.jar
我自己的类也有问题,可以通过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>; }

这个答案用proguard和Tizen框架解决了我所有的问题!非常感谢。这也解决了我的问题,但现在我遇到了大量错误,如“错误:警告:忽略匿名内部类的内部类属性”添加“-keepattributes EnclosingMethod”删除了所有警告:-)即使在今天我尝试在xamarin.android应用程序中使用时,这仍然有效。
accessory-v2.5.3.jar
sdk-v1.0.0.0.jar