保留从AndroidJNI调用的java方法

保留从AndroidJNI调用的java方法,java,android,android-ndk,java-native-interface,proguard,Java,Android,Android Ndk,Java Native Interface,Proguard,我试图通过Proguard混淆Android应用程序代码。在使用proguard进行处理后,应用程序可以自行运行,但是从c到java的本机调用在java.lang.NoSuchMethodError中失败 此代码来自本机部分,其中调用了名为EngineStarted的java类实例: void callEngineStarted( JNIEnv* env, bool isStreamOne ) { jclass cls; if(isStreamOne == true) {

我试图通过Proguard混淆Android应用程序代码。在使用proguard进行处理后,应用程序可以自行运行,但是从c到java的本机调用在
java.lang.NoSuchMethodError
中失败

此代码来自本机部分,其中调用了名为EngineStarted的java类实例:

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[]);
}
-keepclassmembers类**.PDecoderNative{
本地人;
无效初始化层(int);
无效引擎启动(int);
无效位置更改(int);
无效设置持续时间(int);
已完成作废();
void CompletedWithFade();
空洞谱(浮点数[]);
}

编辑:问题不在于proguard,而在于proguard无法不时读取project.txt文件。将整个项目移动到磁盘上的新位置并重新创建文件。它工作正常。

您的分析是正确的,您的配置看起来也是正确的。您应该仔细检查类的完全限定名(com.emrahgunduz.AppBase.Services.PlayService.players.pDecoders.PDecoderNative)。请注意,如果适用,必须使用“$”而不是“.”来分隔内部类

如果指定了正确的名称,您将在proguard在Android构建过程中写出的proguard/seeds.txt文件中看到它们


一旦这起作用,您可以将
-keep
替换为
-keepclassmembers
。然后,ProGuard仍将保留方法名,但会混淆类名,这在本例中没有问题。

这可能是因为ProGuard更改了方法名。对于1个或多个方法,有一个选项可以忽略该优化,请参阅手册中“使用>保留”下的选项。您可以将更改的名称记录到mapping.txt,这是默认行为。有类似的项目,如
PDecoderNative getPrevious()->e
,但是我提到的方法没有出现在日志中。感谢您的回复。我查了一下班名,没问题。使用转储回调方法的usage.txt中也会出现相同的名称。我不知道为什么,但是完全使用类名会导致keep方法的转储。但是,将名称更改为**.PDecoderNative解决了这个问题。我会接受你的正确答案,因为我通过你的名字/软件包建议解决了这个问题。我无法想象为什么ProGuard会在没有通配符的情况下错误地解析类名。要进行双重检查,可以尝试将其从proguard/seeds.txt复制/粘贴到dexguard-project.txt。您还应该在proguard/seeds.txt中看到保留的方法名。猜猜看,在使用通配符进行更改后,我开始出现同样的问题。已从零开始移动项目文件夹并重新创建project.txt文件。现在它在没有通配符的情况下工作。可能是文件被锁定或损坏,或者某些安全问题不允许proguard不时读取文件。我想sdk或macosx的上一次更新把我搞砸了。