2014-07-23 23 views
5

我想通過Proguard混淆Android應用程序代碼。使用proguard進行處理後,該應用程序自行運行,但從c到java的本機調用失敗,出現java.lang.NoSuchMethodError保持從Android調用的Java方法JNI

這段代碼是從本地部分,其中調用Java類實例所做的,名爲EngineStarted:

void callEngineStarted(JNIEnv* env, bool isStreamOne) 
{ 
    jclass cls; 
    if(isStreamOne == true) { 
     cls = (*env)->GetObjectClass(env, currentObjectOne); 
    } else { 
     cls = (*env)->GetObjectClass(env, currentObjectTwo); 
    } 

    jmethodID midCallBack = (*env)->GetMethodID(env, cls, "EngineStarted", "(I)V"); 
    if (0 == midCallBack) { 
     LOGW("Could not find EngineStarted method in class"); 
     return; 
    } 

    if(isStreamOne == true) { 
     (*env)->CallVoidMethod(env, currentObjectOne, midCallBack, 1); 
    } else { 
     (*env)->CallVoidMethod(env, currentObjectTwo, midCallBack, 0); 
    } 
} 

Java有此方法。它只從本地部分調用,而不是其他任何地方。因此,proguard正在刪除該方法。

public void EngineStarted (int isStreamOne) 
    { 
    Log.v("decoderService", "PDecoder - Engine started, using stream " + (isStreamOne == 1 ? "one" : "two")); 
    this.isStreamOne = isStreamOne == 1; 

    // Initialize the player 
    InitializePlayer(isStreamOne); 
    } 

我試過把它添加到proguard-project.txt中,但沒有解決問題。

-keep class com.emrahgunduz.AppBase.Services.PlayService.players.pDecoders.PDecoderNative { 
    void EngineStarted(int); 
    void PositionChanged(int); 
    void SetDuration(int); 
    void Completed(); 
    void CompletedWithFade(); 
    void Spectrum (***); 
} 

編譯後,mapping.txt不包括方法,我懷疑proguard刪除它們。 如何讓這些方法被刪除和/或重命名?

編輯/解決方案:

我能夠通過改變全位置使用通配符來解決這個問題。這節省了一些方法,但還不夠。不知道爲什麼,但被傾銷者調用的另一種方法(void InitializePlayer(int))也被拋棄,這種方法以某種方式產生了連鎖反應。添加此方法解決了剩餘的缺失方法。最終的解決方案成爲

-keepclassmembers class **.PDecoderNative { 
    native <methods>; 
    void InitializePlayer(int); 
    void EngineStarted(int); 
    void PositionChanged(int); 
    void SetDuration(int); 
    void Completed(); 
    void CompletedWithFade(); 
    void Spectrum(float[]); 
} 

編輯:問題是不與ProGuard的,但使用ProGuard不能夠從時間project.txt文件讀取時間。將整個項目移至磁盤上的新位置並重新創建文件。它工作完美。

+0

這可能是由於proguard更改方法名稱。有一個選項可以省略1個或多個方法的優化,請參見使用手冊> keep下的[Keep](http://proguard.sourceforge.net/index.html#manual/usage.html)選項。 –

+0

您可以將更改的名稱記錄到mapping.txt,這是一種默認行爲。有類似的項目,如'PDecoderNative getPrevious() - > e',但我提到的方法不會出現在日誌中。 – emrahgunduz

回答

3

你的分析是正確的,你的配置看起來也是正確的。你應該仔細檢查你的類的完全限定名(com.emrahgunduz.AppBase.Services.PlayService.players.pDecoders.PDecoderNative)。請注意,您必須使用'$'而不是'。'。如果適用,分開內部類。

如果您指定了正確的名稱,您將在ProGuard在Android構建過程中寫出的proguard/seeds.txt文件中看到它們。

一旦這項工作,您可以用-keepclassmembers替換-keep。然後,ProGuard將保留方法名稱,但會混淆類名,在這種情況下罰款。

+0

感謝您的回覆。我查了這個班的名字,沒事。使用轉儲回調方法的usage.txt中也會顯示相同的名稱。我不知道爲什麼,但完全使用類名會導致keep方法的轉儲。然而,改名爲**。PDecoderNative解決了這個問題。當我設法通過您的名字/包裹建議解決問題時,我會接受您的答案爲正確答案。 – emrahgunduz

+0

我無法想象爲什麼ProGuard會錯誤地解析沒有通配符的類名。要仔細檢查,你可以嘗試從proguard/seeds.txt複製/粘貼到dexguard-project.txt中。您還應該在proguard/seeds.txt中看到保存的方法名稱。 –

+0

猜猜看,我在使用通配符後發生了同樣的問題。移動項目文件夾並從零重新創建project.txt文件。現在它沒有通配符。可能文件被鎖定或損壞,或者某些安全問題不會讓proguard不時讀取文件。我認爲sdk或macosx上的最新更新與我混淆了。 – emrahgunduz