【问题标题】:Proguard issue with SAAgent(Samsung Accessory) java.lang.NoSuchMethodException: <init> []SAAgent(Samsung Accessory) java.lang.NoSuchMethodException 的 Proguard 问题:<init> []
【发布时间】:2018-06-21 12:45:37
【问题描述】:

我正在尝试将 proguard 与我的 android 应用程序一起使用,并且正在使用 samsung 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.

...

有人知道要尝试什么吗?

【问题讨论】:

    标签: java android proguard samsung-mobile samsung-mobile-sdk


    【解决方案1】:

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

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

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

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

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

    -keepattributes InnerClasses
    

    请注意,为了能够使用三星配件 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(); 
    }
    

    【讨论】:

    • 即使在今天我尝试在 xamarin.android 应用程序中使用时,它仍然有效。
    【解决方案2】:

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

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

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

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

    -keepattributes InnerClasses 
    

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

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

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

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

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

    造成这种情况的原因可能并不明显,但如果您深入了解 Accessory SDK,您会注意到一些 IInterfaceBinder 扩展(即在 IDeathCallbackISAFrameworkManager (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.

    【讨论】:

    • 这个答案解决了我所有关于 proguard 和 Tizen 框架的问题!非常感谢。
    • 这也解决了我的问题,但现在我收到大量错误,例如“错误:警告:忽略匿名内部类的 InnerClasses 属性”
    • 添加“-keepattributes EnclosureMethod”删除了所有警告:-)
    【解决方案3】:

    尝试了上述建议,但仍将崩溃归因于 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
    

    【讨论】:

      猜你喜欢
      • 2015-02-25
      • 2013-08-04
      • 2017-03-26
      • 1970-01-01
      • 2017-01-22
      • 1970-01-01
      • 2017-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多