Proguard - Error: A JNI error has occured

Proguard - Error: A JNI error has occured

我一直在尝试使用 ProGuard 来混淆我的应用程序。我已经禁用了混淆的每个选项异常。 Loader是我的主要class.

下面的屏幕截图是我尝试 运行 我的混淆 jar 时的结果。 混淆时均未报错

我的配置

-injars 'C:\Users\Corsair\Desktop\obfuscate\Example.jar'
-outjars 'C:\Users\Corsair\Desktop\obfuscate\ExampleOut.jar'

-libraryjars 'C:\Program Files\Java\jre1.8.0_91\lib\rt.jar'

-dontskipnonpubliclibraryclassmembers
-dontshrink
-dontoptimize
-dontusemixedcaseclassnames
-dontpreverify
-dontnote
-dontwarn

-verbose

-keep class Loader

如果这是您使用的唯一配置,本机方法也会被混淆。因此,它们的名称将不再与本机库中的名称匹配,因此当您尝试使用 System.loadLibrary.

加载库时,您会看到这样的错误

您至少需要添加如下规则:

-keepclasseswithmembernames,includedescriptorclasses class * {
    native <methods>;
}

这将指示 ProGuard 在它处理的任何 class 中保留所有本机方法。

编辑:

使其正常工作所需的其他规则:

  • 移除 -dontpreverify,Java 7+
  • 需要预验证
  • 保留主要方法

这将保留主要方法:

-keep class Loader {
    public static void main(...);
}

您必须排除某些 classes 像 bean classes、回调 classes 和原生 classes 一样进行混淆。在官方例子中提到了以下内容:

处理本机方法

如果您的应用程序、applet、servlet、库等包含本机方法,您将希望保留它们的名称及其 classes 的名称,以便它们仍然可以链接到本机图书馆。

-keepclasseswithmembernames,includedescriptorclasses class * {
    native <methods>;
}

注意:我们不想保留所有 classes 或所有本机方法;我们只是想让相关名称不被混淆。

处理回调方法

如果您的应用程序、applet、servlet、库等包含从外部代码(本机代码、脚本等)调用的回调方法,您将希望保留它们,可能还有它们的class也是。它们只是您代码的入口点,很像应用程序的主要方法。

-keep class mypackage.MyCallbackClass {
    void myCallbackMethod(java.lang.String);
}

正在处理bean classes

如果您的应用程序、applet、servlet、库等广泛使用 bean classes 的内省来查找 bean 编辑器 classes,或 getter 和 setter 方法,那么配置可能会变得很痛苦。除了确保 bean class 名称或 getter 和 setter 名称不变外,您无能为力

有用:在 class 名称和方法签名中使用通配符

-keep class mybeans.** {
    void set*(***);
    void set*(int, ***);

    boolean is*(); 
    boolean is*(int);

    *** get*();
    *** get*(int);
}

还有一些其他情况(资源、序列化 classes)也可能导致问题。这些请参考整个指南

ProGuard Official: Examples