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
问题:
回答1:
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.
回答2:
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:
- Create a custom build.xml
- Copy and modify the "obfuscate" target to use injars
- Use the injars from a directory where Maven puts them
- 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.