【问题标题】:What makes certain android classes "must -keep"?是什么让某些 android 类“必须保留”?
【发布时间】:2012-02-10 02:48:40
【问题描述】:

我注意到“模板”proguard.cfg 始终包含以下内容:

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService

为什么是这些特定的类而不是其他类?

这是不能被 ProGuard“优化”的类的完整列表吗?

【问题讨论】:

    标签: android proguard


    【解决方案1】:

    简而言之,这些类在 proguard.cfg 模板中,因为这些类可以在 AndrodiManifest.xml 中声明。

    考虑这个最小的应用程序:

    CustomTextView.java:

    package com.example.android;
    
    import android.content.Context;
    import android.widget.TextView;
    
    public class CustomTextView extends TextView {
        public CustomTextView(Context context) {
            super(context);
            setText("The class name of this class is not important");
        }
    }
    

    ExampleActivity.java:

    package com.example.android;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    
    public class ExampleActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(new CustomTextView(this));
            Log.i("ExampleActivity", "The class name of this class is important");
        }
    }
    

    AndroidManifest.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.android"
          android:versionCode="1"
          android:versionName="1.0">
        <application>
            <activity android:name=".ExampleActivity">
                <intent-filter>
                     <action android:name="android.intent.action.MAIN" />
                </intent-filter>
            </activity>
        </application>
    </manifest>
    

    现在,没有线

    -keep public class * extends android.app.Activity
    

    在 proguard.cfg 文件中,proguard 可能会尝试将 ExampleActivity 重命名为 A虽然它对 AndroidManifest.xml 一无所知,所以它不会触及清单。由于 Android 操作系统使用应用程序清单中声明的​​类名来启动应用程序,因此 Android 操作系统将尝试实例化 ExampleActivity,但该类将不存在,因为 proguard 重命名了它!

    对于CustomTextView,proguard 可以将其重命名为B,因为类的名称并不重要,因为它没有在清单中声明,仅由 proguard 将更新的代码引用当它改变CustomTextView的类名时。

    以某种方式,从模板 proguard.cfg 文件引用的所有类都可以在清单中声明,因此 proguard 不得触及它们。

    【讨论】:

    • 感谢您理解我的问题并提供如此出色的答案。已经+1,除非出现令人惊讶的事情,否则我计划接受+50您的回答。现在是后续问题:#1. 我是否从您的回答中正确理解-keep 也会影响映射,而不仅仅是“优化”? #2. 如果未来版本的 Proguard 支持 AndroidManifest.xml,那么上述类将不再需要 -keep
    • #1.:我不完全确定您所说的“映射”是什么意思。如果您的意思是“重命名类”,那么是的,-keep 不仅阻止 proguard 删除类,而且阻止重命名类。如果您所说的“映射”是指与 AndroidManifest.xml 相关的内容,那么不,-keepAndroidManifest.xml 根本没有任何关系,这正是首先需要 -keep 的原因(请参阅对 # 的回答2)。 #2. 是的,如果proguard 知道AndroidManifest.xml 的语义(以及如何修改它),那么-keep 就没有必要了。
    【解决方案2】:

    查看ProGuard Manual。它指出-keep

    指定类和类成员(字段和方法) 保留为您的代码的入口点。例如,为了保持 一个应用程序,您可以指定主类及其主类 方法。为了处理图书馆,您应该公开指定所有 可访问的元素。

     

    这是不能被混淆的类的完整列表吗? ProGuard?

    如果您指定-keep 这并不意味着缺少混淆。这意味着它将这些类保留在您的代码中。因为 ProGuard 在尝试优化和缩小您的应用程序时,如果某些类似乎没有被使用,它可能会删除它们。不要 100% 相信我的话,但这就是我曾在其他一些 SO 帖子上读到的内容。

    为什么是这些特定的类而不是其他类?

    我会假设是因为这些课程非常重要。正如您所看到的,它们中的大多数都是extend 您列出的类。如果您指定 ActivityService 或您列出的任何其他内容,您肯定不希望在优化期间将其删除。

    【讨论】:

    • 谢谢,但我正在寻找特定于我列出的特定 Android 类的答案。例如,什么使得BroadcastReceiver 必须-keep?说“非常重要”并不能告诉我任何事情......
    • 好吧,我想说BroadcastReceiver 的原因可能是BroadcastReceiver 类通常不会被使用(通过其他Java 代码),但它在您的清单中被引用.意思是它被使用了,但Proguard 不承认,所以你必须-keep 它所以Proguard 不会删除它。事实上,我对此一无所知,这只是我阅读Proguard Manual的理解。
    • 谢谢。我确实阅读了手册,但我仍然不明白为什么 ADT 选择这些类出现在模板 proguard.cfg 中。 -keep 的描述为:“指定要保留为代码的入口点的类和类成员(字段和方法)。”顺便说一句,从上面列出的类派生的类不仅被保留,而且也没有混淆
    • 我在我的应用程序上使用了 progaurd,当我反编译应用程序并在 classes.dex 上使用 dex2jar 然后查看结构时,我的类被混淆了,包括用指定的活动和广播接收器-keep。您是说根据个人经验或根据您阅读的内容,它们没有被混淆?我相信它们被保留为入口点意味着类的名称不会被混淆,但方法的内容会被混淆。虽然我可能有误解。
    • Jakar 的答案和细节是正确的。默认情况下,ProGuard 删除(或至少重命名)类的实现,如 BroadcastReceiver,因为它们似乎没有在应用程序的代码中使用(ProGuard 不了解 Android 约定)。这会破坏应用程序,因此您必须指定保留此类类。 ProGuard 实际上只保留其相关的公共 API;内部字节码仍在优化中。
    猜你喜欢
    • 1970-01-01
    • 2014-03-07
    • 2011-12-30
    • 2017-07-29
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多