如何保留类具有本机函数

Mic*_*Tin 0 android proguard android-proguard

如果类中有本机函数,是否可以告诉 ProGuard 完全跳过该类?

-keepclasseswithmembernames class * { native <methods>; }
Run Code Online (Sandbox Code Playgroud)

上面对我不起作用,因为它保留了类名称和本机函数名称,但混淆了其他成员

我想知道是否可以将所有内容保留在此类中,而无需显式指定每个类

谢谢

use*_*723 7

\n

如果类中有本机函数,是否可以告诉 ProGuard 完全跳过该类

\n
\n\n

使用这些规则:

\n\n
\n-keepclasseswithmembers class com.your.packages.** {\n 本机 <方法>;\n}\n-keepclassmembers class com.your.packages.** {\n 本机 <方法>;\n}\n
\n\n

请注意,使用 Proguard“完全跳过”类总是一个坏主意,因为它也可能间接保留一些类,这些类是从您保留的类的代码中使用的。相反,我推荐以下模式:

\n\n
\n-keepclasseswithmembers,允许收缩,允许优化class com.your.packages.** {\n native <methods>;\n}\n-keepclassmembers class com.your.packages.** {\n native <methods>;\ n}\n
\n\n

它将允许缩小和优化同一类中存在的非本机方法的代码。

\n\n

您可以做得更好:如果您的本机方法是通过名称解析的(例如,它们被称为类似的东西Java_com_your_packages_methodName),并且您不使用RegisterNatives显式注册它们,则可以通过删除第二条规则来允许缩小未使用的本机方法,该规则只会离开

\n\n
\n-keepclasseswithmembers、允许收缩、允许优化类 com.your.packages.** {\n 本机 <methods>;\n}\n
\n\n

如果您希望某些类成员可以从 JNI 访问(例如,您有一些要从本机代码调用的静态回调方法),则应该显式保留它们使用专门的注释来注释每个此类成员,并使用基于注释的规则来保留它们他们:

\n\n
\n-keepclassmembers,允许优化,includedescriptorclasses class com.your.packages.** {\n @android.support.annotation.Keep *;\n}\n
\n\n

您可以使用自己的注释来代替 Android 支持库 \xe2\x80\x94 中的注释,事实上,最好使用自己的注释,以避免来自 Android Gradle 插件或其他库的现有消费者规则的干扰。

\n\n
\n\n

一般来说,我建议您尽可能减少 JNI 和 Java 代码之间的摩擦。如果您有多个从 JNI 调用的相关 Java 方法,请尝试将它们放在同一个方法中:

\n\n
@Keep\npublic static void callback(int action, String arg) {\n    switch (action) {\n        ...\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

从 Java 代码中抛出异常(无论如何,您都会反射性地调用它们的构造函数,因此也可以调用静态帮助器方法):

\n\n
@Keep\npublic static void throwException(int type, String message) {\n    switch (type) {\n        case 0:\n            throw new BadThingsHappenedException(message);\n        case 1:\n            throw new AllHopeIsLostError();\n        ...\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您有一个类,必须将其传递给 JNI,请尝试传递单个字段而不是该类:

\n\n
public final class DataClass {\n    int intField;\n    String stringField;\n\n    public void doSomeNativeOperation() {\n        JNI.doSomeNativeOperation(this);\n    }\n}\n\npublic final class JNI {\n    public static void doSomeNativeOperation(DataClass arg) {\n        doSomeNativeOperation0(arg.intField, arg.stringField);\n    }\n\n    private static native void doSomeNativeOperation0(int intField, String stringField);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您有一个本机对等类(与本机内存中的某些结构紧密连接的类),您可以在long字段中保留指向该类中本机结构的指针,并将该字段传递给本机方法。然后在本机方法中将其转换long为指针:

\n\n
public final class Peer {\n    long pointer;\n\n    // constructor is invoked from JNI\n    @Keep\n    protected Peer(long pointer) {\n        this.pointer = pointer;\n    }\n\n    public void doSomeNativeOperation() {\n        JNI.doSomeNativeOperation(this);\n    }\n}\n\npublic final class JNI {\n    public static void doSomeNativeOperation(Peer peer) {\n        doSomeNativeOperation0(peer.pointer);\n    }\n\n    private static native void doSomeNativeOperation0(long pointer);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在本机代码中:

\n\n
void JNIEXPORT Java_com_your_packages_methodName(JNIEnv* env, jobject type, jlong ptr) {\n    struct my_struct peer = (struct my_struc*) (intptr_t) ptr;\n    ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这些简单的规则将允许您使用 JNI 完全混淆任何大型应用程序,但包含所有方法的单个小类除外native

\n\n

我建议您更进一步,推动重新打包由本机回调引用的类。

\n\n

代替

\n\n
@Keep\npublic static void callback(YourCustomType arg) {\n    ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以通过将其替换为来省略某种类型的参数Object

\n\n
@Keep\npublic static void callback(Object arg) {\n    // this cast won\'t make much difference in performance, but it makes huge\n    // difference for Proguard!\n    YourCustomType instance = (YourCustomType) arg;\n\n    ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这将允许您混淆和重新打包甚至类型的回调参数。

\n