是啥让某些 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 相关的内容,那么不,-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;内部字节码仍在优化中。

以上是关于是啥让某些 android 类“必须保留”?的主要内容,如果未能解决你的问题,请参考以下文章

是啥让某些蓝牙设备在 iOS“我的设备”中列出?

是啥让某些东西成为 ASP.NET Core 中的请求功能?

弄清楚是啥让 VS2008 中的 C++ 类抽象

是啥让这两个功能分别为“公共”和“私有”,这是啥意思?

是啥让一些 EXIF 标签不可写?

是啥让 API 变得“丰富”? [关闭]