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 来混淆我的应用程序。我已经禁用了混淆的每个选项异常。 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)也可能导致问题。这些请参考整个指南