是啥让某些 android 类“必须保留”?
Posted
技术标签:
【中文标题】是啥让某些 android 类“必须保留”?【英文标题】: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“优化”的类的完整列表吗?
【问题讨论】:
【参考方案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 相关的内容,那么不,-keep
与 AndroidManifest.xml
根本没有任何关系,这正是首先需要 -keep
的原因(请参阅对 # 的回答2)。 #2.
是的,如果proguard 知道AndroidManifest.xml 的语义(以及如何修改它),那么-keep
就没有必要了。【参考方案2】:
查看ProGuard Manual
。它指出-keep
:
指定类和类成员(字段和方法) 保留为您的代码的入口点。例如,为了保持 一个应用程序,您可以指定主类及其主类 方法。为了处理图书馆,您应该公开指定所有 可访问的元素。
这是不能被混淆的类的完整列表吗? ProGuard?
如果您指定-keep
这并不意味着缺少混淆。这意味着它将这些类保留在您的代码中。因为 ProGuard 在尝试优化和缩小您的应用程序时,如果某些类似乎没有被使用,它可能会删除它们。不要 100% 相信我的话,但这就是我曾在其他一些 SO 帖子上读到的内容。
为什么是这些特定的类而不是其他类?
我会假设是因为这些课程非常重要。正如您所看到的,它们中的大多数都是extend
您列出的类。如果您指定 Activity
、Service
或您列出的任何其他内容,您肯定不希望在优化期间将其删除。
【讨论】:
谢谢,但我正在寻找特定于我列出的特定 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;内部字节码仍在优化中。以上是关于是啥让某些 android 类“必须保留”?的主要内容,如果未能解决你的问题,请参考以下文章