5

Androidアプリでproguardを使用しようとしていますが、問題を引き起こし続けるsamsungアクセサリSDKを使用しています。

プロガード構成で何を試しても、このランタイム例外を乗り越えることができないようです:

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.

...

誰が何を試すべきかについて何か考えがありますか?

4

3 に答える 3

5

問題は、一部の最適化をオンにすると、Proguard が最上位クラスのすべての内部クラスを変更することです。

これは、Java では内部クラスが外部クラスへの参照を保持するため、内部クラスのデフォルトのコンストラクターが、外部クラスのインスタンスを取る 1 つのパラメーターのコンストラクターと交換されることを意味します。

Samsung Accesory SDK では、SASocket 内部クラスの実装にデフォルトのコンストラクターが必要です。これは、リフレクションを使用してそのオブジェクトをインスタンス化していると思われるためです。

ここでhttp://sourceforge.net/p/proguard/bugs/387/を読むことができます: 「構成に -repackageclasses と -allowaccessmodification も追加しない限り、Outer$Inner は最上位クラスに変更されません」。

残念ながら、これらのフラグは通常 proguard-android-optimize.txt から継承されます。最適化を維持したい場合は、ソリューションを proguard 構成に追加します。

-keepattributes InnerClasses

Samsung アクセサリ 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

この回答を代替として追加し、既存の回答を更新するだけです。

最近、Samsung のアクセサリ SDK を Android の「コンパニオン」アプリに統合して、Galaxy Gear S2 で Tizen アプリをサポートしましたが、コンパニオン アプリの (縮小された) リリース ビルドをコンパイルするときに同じ問題に遭遇しました。

@while の回答では、NoSuchMethodExceptionスローされた原因と解決策が既に説明されています。しかし、概説された Proguard ルールはかなり緩和されていて数が多いことがわかりました。これは、以前のバージョンのアクセサリ SDK では必要だったかもしれませんが、最近では、おそらくはるかに少ない除外で実行できます。

最近のアクセサリ 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>(...); }

これまでは、上記のルールを適用しないと、実行時にアプリがクラッシュしていた可能性があります。それらを追加すると、これはもはや当てはまりません。ただし、アクセサリ SDK は依然としてさまざまなエラーをログに記録し、アプリがまだ意図したとおりに動作していないことに気付くでしょう。Logcat を調べると、SDK がサービスへのバインドに失敗したことを示すエラーが表示されるはずです。

この原因は明らかではないかもしれませんが、Accessory SDK を調べてみると、いくつかのIInterfaceandBinder拡張機能 (つまり、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 に答える