使用 proguard 的 Android 混淆应用程序会不断混淆库 jar - 是吗?

Posted

技术标签:

【中文标题】使用 proguard 的 Android 混淆应用程序会不断混淆库 jar - 是吗?【英文标题】:Android obfuscate app using proguard keeps obfuscating library jars - or is it? 【发布时间】:2011-09-26 10:10:26 【问题描述】:

我是使用 Proguard 的新手,所以我可能犯了一个新手错误。我有一个应用程序,在我运行发布版本(它使用 Proguard 进行混淆)后,它很快就崩溃了。我相信我已经将其范围缩小到它似乎混淆了我的参考库的事实。在我的例子中,我的参考库用于定义我用来与使用 Google Protobuffers 的另一台设备通信的消息类。我正在使用 ant 版本进行构建。 我的 proguard 配置是:

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-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

-keepclasseswithmembernames class * 
 
    native <methods>;
 

-keepclasseswithmembernames class * 
 
    public <init>(android.content.Context, android.util.AttributeSet);
 

-keepclasseswithmembernames class * 
 
    public <init>(android.content.Context, android.util.AttributeSet, int);
 

-keepclassmembers enum * 
 
    public static **[] values();
    public static ** valueOf(java.lang.String);
 

-keep class * implements android.os.Parcelable 
 
    public static final android.os.Parcelable$Creator *;
 

在我的 ant build.xml 文件中,我定义了以下内容:

<target name="-obfuscate" unless="do.not.compile">
    <if condition="$proguard.enabled">
        <then>
            <property name="obfuscate.absolute.dir" location="$out.absolute.dir/proguard" />
            <property name="preobfuscate.jar.file"  value="$obfuscate.absolute.dir/original.jar" />
            <property name="obfuscated.jar.file"    value="$obfuscate.absolute.dir/obfuscated.jar" />

             <!-- input for dex will be proguard's output -->
            <property name="out.dex.input.absolute.dir" value="$obfuscated.jar.file" />

            <!-- Add Proguard Tasks -->
            <property name="proguard.jar" location="$android.tools.dir/proguard/lib/proguard.jar" />
            <taskdef name="proguard" classname="proguard.ant.ProGuardTask" classpath="$proguard.jar" />

            <!-- Set the android classpath Path object into a single property. It'll be
                 all the jar files separated by a platform path-separator.
            -->
            <property name="android.libraryjars" refid="android.target.classpath"/>

            <!-- Build a path object with all the jar files that must be obfuscated.
                 This include the project compiled source code and any 3rd party jar
                 files. 
            -->
            <path id="project.jars.ref">
                <pathelement location="$preobfuscate.jar.file" />
                <path refid="jar.libs.ref" />
            </path>

            <!-- Set the project jar files Path object into a single property. It'll be
                 all the jar files separated by a platform path-separator.
            -->
            <property name="project.jars" refid="project.jars.ref" />

            <mkdir  dir="$obfuscate.absolute.dir" />
            <delete file="$preobfuscate.jar.file" />
            <delete file="$obfuscated.jar.file"   />
            <jar basedir="$out.classes.dir" destfile="$preobfuscate.jar.file" />
            <proguard>
                @$proguard.config
                -injars $project.jars
                -outjars $obfuscated.jar.file
                -libraryjars $android.libraryjars
                -dump $obfuscate.absolute.dir/dump.txt
                -printseeds $obfuscate.absolute.dir/seeds.txt
                -printusage $obfuscate.absolute.dir/usage.txt
                -printmapping $obfuscate.absolute.dir/mapping.txt
            </proguard>
        </then>
    </if>
</target>

<!-- Converts this project's .class files into .dex files -->
<target name="-dex" depends="compile, -post-compile, -obfuscate"
        unless="do.not.compile">
    <if condition="$manifest.hasCode">
        <then>
            <dex-helper />
        </then>
        <else>
            <echo>hasCode = false. Skipping...</echo>
        </else>
    </if>
</target>

<!-- Puts the project's resources into the output package file
     This actually can create multiple resource package in case
     Some custom apk with specific configuration have been
     declared in default.properties.
     -->
<target name="-package-resources">
    <echo>Packaging resources</echo>
    <aapt executable="$aapt"
            command="package"
            versioncode="$version.code"
            debug="$build.packaging.debug"
            manifest="AndroidManifest.xml"
            assets="$asset.absolute.dir"
            androidjar="$android.jar"
            apkfolder="$out.absolute.dir"
            resourcefilename="$resource.package.file.name"
            resourcefilter="$aapt.resource.filter">
        <res path="$resource.absolute.dir" />
        <!-- <nocompress /> forces no compression on any files in assets or res/raw -->
        <!-- <nocompress extension="xml" /> forces no compression on specific file extensions in assets and res/raw -->
    </aapt>
</target>

<!-- Packages the application and sign it with a debug key. -->
<target name="-package-debug-sign" depends="-dex, -package-resources">
    <package-helper
            output.filepath="$out.debug.unaligned.file" />
</target>

<!-- Packages the application without signing it. -->
<target name="-package-release" depends="-dex, -package-resources">
    <package-helper
            output.filepath="$out.unsigned.file"/>
</target>
    <target name="-set-release-mode">
        <!-- release mode is only valid if the manifest does not explicitly
             set debuggable to true. default is false.
             We actually store build.packaging.debug, not build.release -->
        <xpath input="AndroidManifest.xml" expression="/manifest/application/@android:debuggable"
               output="build.packaging.debug" default="false"/>

        <!-- Enable proguard -->
        <property name="proguard.enabled" value="true"/>
        <property name="proguard.config" value="proguard.cfg"/>

        <!-- signing mode: release -->
        <property name="build.signing.debug" value="false" />

        <if condition="$build.packaging.debug">
            <then>
                <echo>*************************************************</echo>
                <echo>****  Android Manifest has debuggable=true   ****</echo>
                <echo>**** Doing DEBUG packaging with RELEASE keys ****</echo>
                <echo>*************************************************</echo>
            </then>
            <else>
                <!-- property only set in release mode.
                     Useful for if/unless attributes in target node
                     when using Ant before 1.8 -->
                <property name="build.mode.release" value="true"/>
            </else>
        </if>
    </target>

    <target name="release"
            depends="-set-release-mode, -release-obfuscation-check, -package-release, -release-prompt-for-password, -release-nosign"
                if="has.keystore"
                description="Builds the application. The generated apk file must be signed before
                            it is published.">
        <!-- Signs the APK -->
        <echo>Signing final apk...</echo>
        <signjar
                jar="$out.unsigned.file"
                signedjar="$out.unaligned.file"
                keystore="$key.store"
                storepass="$key.store.password"
                alias="$key.alias"
                keypass="$key.alias.password"
                verbose="$verbose" />

        <!-- Zip aligns the APK -->
        <zipalign-helper in.package="$out.unaligned.file"
                                   out.package="$out.release.file" />
        <echo>Release Package: $out.release.file</echo>
    </target>

我会很感激任何想法。我从在线模板中复制了大部分构建和 proguard 配置,我怀疑我实际上是在指导 Proguard 混淆库 jar,或者我有一些 lisconfigured。 我在构建结束时的 cmd 窗口中看到以下输出:

[proguard] Writing output...
[proguard] Preparing output jar [C:\Workspace\UI\MyApp\build\proguard\obfuscated.jar]
[proguard]   Copying resources from program jar [C:\Workspace\UI\MyApp\build\proguard\original.jar]
[proguard]   Copying resources from program jar [C:\Workspace\UI\MyApp\libs\libmessaging.jar]
[proguard] Warning: can't write resource [META-INF/MANIFEST.MF] (Duplicate zip entry [libmessaging.jar:META-INF/MANIFEST.MF])
[proguard]   Copying resources from program jar [C:\Workspace\UI\MyApp\libs\protobuf-2.3.0.jar]
[proguard] Warning: can't write resource [META-INF/MANIFEST.MF] (Duplicate zip entry [protobuf-2.3.0.jar:META-INF/MANIFEST.MF])
[proguard] Printing classes to [C:\Workspace\Riptide1_1_ptr_74\WPG_HAWKSBILL\UI\MyApp\build\proguard\dump.txt]...

谢谢!

【问题讨论】:

【参考方案1】:

您已在 Proguard 配置中注释了您的库 jar 指令。 变化:

# -libraryjars /libs/protobuf-2.3.0.jar
# -libraryjars /libs/libmessaging.jar

到:

-libraryjars /libs/protobuf-2.3.0.jar
-libraryjars /libs/libmessaging.jar

(然后不要费心在 build.xml 中定义库 jar)

编辑: 我发现另一种让 Proguard 不理会库 jar 的方法是要求它保留它们的包名,例如:

-keep class javax.**  *; 
-keep class org.**  *; 
-keep class twitter4j.**  *; 

【讨论】:

我知道我已经把它们注释掉了——我得到了各种各样的输出,所以我把它们注释掉了——但我没有注意到我也在构建中引用了它们。我会试一试!所以我需要从我的构建文件中删除行 和 -libraryjars $android.libraryjars ?谢谢! 我更改了答案以添加我也做过的其他事情...见上文。 感谢您的帮助。我一定还是错过了什么。我编辑了我的 proguard.cfg 以显示我如何取消对 libraryjars 的注释并添加 -keeps。我从我的 build.xml 中从目标名称 =“-混淆”,但是当我尝试 ant 发布时,对于我的 libmessaging.jar 中的所有类,我会收到诸如“找不到引用的类 java.lang.String”和“库类的重复定义”之类的错误。 我在上面更新了我的问题。希望你有另一个想法?我尝试在 build.xml 中注释掉库声明,这似乎让事情变得更糟。我还尝试将 -keep class com.google.protobuf.** ; 和 -keep class com.my.messaging.* *; 添加到 proguard.cfg,结果与我原来有。 你的 -keep 类方法救了我!谢谢!【参考方案2】:

当 proGuard 加密 jsoup 库时,我遇到了类似的问题。我通过将以下内容添加到我的 proguard-rules.txt 来修复它:

-keep class org.jsoup** 
    *;

所以 build.gradle 会以以下部分结束:

release 
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'

【讨论】:

以上是关于使用 proguard 的 Android 混淆应用程序会不断混淆库 jar - 是吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用 proguard 的 Android 混淆应用程序会不断混淆库 jar - 是吗?

Android:proguard 不会混淆源代码

Android 中的 ProGuard 不起作用。(不混淆)

Proguard 使用 DNSJava 库混淆 Android 代码

Android 项目的代码混淆,Android proguard 使用说明

如何使用 proguard 混淆 android 库(.aar)?