how to specify injars for proguard within android

2019-04-08 05:45发布

is there a way to pass libraries pulled from maven central as injars for proguard? I want them to be obfuscated. Context: remove unused classes with proguard for Android

2条回答
老娘就宠你
2楼-- · 2019-04-08 06:15

I never used Maven and I'm using Gradle, but either build syste, the same thing applies I believe. And I don't think that what you want is possible...

The -injars keyword is specific to the ProGuard configuration file, which is a text file read by the build tools.

The only way I see is that if you build some kind of script that will that for you. That is, read all Maven dependencies, create the appropriate ProGuard configuration file specifying all the required -injars and pass it to the build process. Not sure how feasible is this with Maven.

It shouldn't be too difficult with Gradle. With Gradle you can easily pass multiple ProGuard configuration files and you could just create a method in the build.gradle file to get all the .jar file locations from the dependencies and create a temporary text file that you would then pass into the ProGuard configuration.

I would assume the same process would work with Maven, but again, I never used it.

查看更多
你好瞎i
3楼-- · 2019-04-08 06:16

EDIT: I see now the question asked Gradle specifically. My answer is for Ant, but it might give you ideas.

A complete solution involves these steps:

  1. Create a custom build.xml
  2. Copy and modify the "obfuscate" target to use injars
  3. Use the injars from a directory where Maven puts them
  4. Automate Maven to put jars in a directory. And this is where I'm lost. Not enough experience with gradle/maven.

Steps in detail:

1. Custom build.xml

In build.xml, put in "custom", as such:

<!-- version-tag: custom -->
<import file="${sdk.dir}/tools/ant/build.xml" />

Before this bit, insert the code below, or put it in a separate file (general-build.xml) and import that into build.xml.

2. Target

Insert the following:

<!-- Obfuscate target
    This is only active in release builds when proguard.config is defined
    in default.properties.

    To replace Proguard with a different obfuscation engine:
    Override the following targets in your build.xml, before the call to <setup>
        -release-obfuscation-check
            Check whether obfuscation should happen, and put the result in a property.
        -debug-obfuscation-check
            Obfuscation should not happen. Set the same property to false.
        -obfuscate
            check if the property set in -debug/release-obfuscation-check is set to true.
            If true:
                Perform obfuscation
                Set property out.dex.input.absolute.dir to be the output of the obfuscation
-->
<target name="-obfuscate">
    <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.
                 Each path must be quoted if it contains spaces.
            -->
            <pathconvert property="project.target.classpath.value" refid="project.target.class.path">
                <firstmatchmapper>
                    <regexpmapper from='^([^ ]*)( .*)$$' to='"\1\2"'/>
                    <identitymapper/>
                </firstmatchmapper>
            </pathconvert>

            <!-- 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.all.classes.path">
                <pathelement location="${preobfuscate.jar.file}" />
                <path refid="project.all.jars.path" />
            </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.
                 Each path must be quoted if it contains spaces.
            -->
            <pathconvert property="project.all.classes.value" refid="project.all.classes.path">
                <firstmatchmapper>
                    <regexpmapper from='^([^ ]*)( .*)$$' to='"\1\2"'/>
                    <identitymapper/>
                </firstmatchmapper>
            </pathconvert>

            <!-- Turn the path property ${proguard.config} from an A:B:C property
                 into a series of includes: -include A -include B -include C
                 suitable for processing by the ProGuard task. Note - this does
                 not include the leading '-include "' or the closing '"'; those
                 are added under the <proguard> call below.
            -->
            <path id="proguard.configpath">
                <pathelement path="${proguard.config}"/>
            </path>
            <pathconvert pathsep='" -include "' property="proguard.configcmd" refid="proguard.configpath"/>


            <!--  INSERT SOME MAVEN STORAGE DIR BELOW -->
            <echo level="info">PROJECT.ALL.CLASSES.VALUE === ${project.all.classes.value}</echo>
            <echo level="info">PROJECT.TARGET.CLASSPATH.VALUE === ${project.target.classpath.value}</echo>
            <property name="project.all.classes.value2" value="${project.all.classes.value}:/some-maven-dir"/>
            <echo level="info">PROJECT.ALL.CLASSES.VALUE2 === ${project.all.classes.value2}</echo>

            <mkdir   dir="${obfuscate.absolute.dir}" />
            <delete file="${preobfuscate.jar.file}"/>
            <delete file="${obfuscated.jar.file}"/>
            <jar basedir="${out.classes.absolute.dir}"
                destfile="${preobfuscate.jar.file}" />
            <proguard>
                -include      "${proguard.configcmd}"
                -include      "${out.absolute.dir}/proguard.txt"
                -injars       ${project.all.classes.value2}
                -outjars      "${obfuscated.jar.file}"
                -libraryjars  ${project.target.classpath.value}(!META-INF/MANIFEST.MF,!META-INF/NOTICE.txt,!META-INF/LICENSE.txt)
                -dump         "${obfuscate.absolute.dir}/dump.txt"
                -printseeds   "${obfuscate.absolute.dir}/seeds.txt"
                -printusage   "${obfuscate.absolute.dir}/usage.txt"
                -printmapping "${obfuscate.absolute.dir}/mapping.txt"
                -printconfiguration "${obfuscate.absolute.dir}/used_config.txt"
            </proguard>
        </then>
    </if>
</target> 

Another way to do it is to copy in jars only temporary (the same technique is used for regular Java project dependencies that are not Android library projects):

<property name="lib.javalib1.project.dir" location="${basedir}/../../some-maven-dir" />

<target name="-pre-build">
  <subant buildpath="${lib.javalib1.project.dir}" target="package" failonerror="true" />
  <copy todir="${basedir}/libs" failonerror="true" verbose="true">
      <fileset dir="${lib.javalib1.project.dir}/bin">
          <filename name="general-api.jar"/>
      </fileset>
  </copy>
</target>
<target name="-post-package">
    <delete verbose="true">
        <fileset dir="${basedir}/libs" includes="general-api.jar" />
    </delete>
</target>

But it compiles jars one by one and copies them, so for Maven, where jars are already available, this is a disadvantage.

3. Maven dir

"/some-maven-dir" is a directory where jars are stored.

4. Maven automation

I can't help here, but I put up a suggestion for the first part. Perhaps someone can continue with this.

查看更多
登录 后发表回答