-
Notifications
You must be signed in to change notification settings - Fork 395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for maven-shade-plugin #487
Comments
I did some further research and it seems that integration between maven-shade-plugin may actually have become at lot harder then it was with the 2011-era version of android-maven-plugin. With the current version the creation of a jar file happens in the |
Why don't you change the phase in which the shade plugin executes? On Thu, Oct 23, 2014 at 9:57 PM, Matthias Stevens [email protected]
|
I tried attaching it to
In other words, the shade plugin seems to require a jar file to work its magic on. I haven't found a way to make it perform the class relocation on unpackaged class files. |
You could always shade your libraries in a separate project and produce a On Thu, Oct 23, 2014 at 10:54 PM, Matthias Stevens <[email protected]
|
True, but the consequence of that is that an important benefit of the shading plugin would be lost. Namely the fact that it transparently relocates classes without the programmer having to change imports accordingly. For example, it allows one to package a jar in which But if, as you suggest, I use a separate project to perform the shading then the source code of my primary apk project will have to modified (i.e. change imports to point to The beauty of not having to modify source code is that it means a dependency clash would be solved entirely through build-time maven trickery, without bothering the (java) programmer. The shade plugin makes this possible for jar packaging and I was hoping this "magic" could be carried through to apk packaging. |
In an environment like Android that sounds really dangerous. If you want to use a different version of a library then you should be On Thu, Oct 23, 2014 at 11:13 PM, Matthias Stevens <[email protected]
|
You are right about it being dangerous if other Android-specific dependencies also depend on the renamed dependency. In my situation this is not the case however. |
To clarify, this double inclusion happens in the following situation: |
This double inclusion is very weird because in fact the shade plugin actually installs a "dependency-reduced" version of the library project pom file to the local m2 repo. This means the commons-codec dependency is in fact removed from the installed pom (which makes sense because the jar which is installed actually contains the shaded commons-codec classes). |
I may need to mention that my apk and library project share the same parent. |
Another side note, the dangerous situation you describe is not very plausible in the particular case of commons-codec because it is an internal Android library, i.e. not exposed in the Android SDK (unlike Apache HttpClient, which is exposed). So any Android app or library which needs commons-codec has to explicitly depend on/contain its own version of it in order to compile against the Android SDK.
So even though it is absent at compile-time at runtime Android's internal commons-codec version annoyingly takes preference over the one included in the apk (and of course this is the reason I need some kind of shading to begin with). |
If you are getting commons-codec as well as your shaded commons-codec On Thu, Oct 23, 2014 at 11:50 PM, Matthias Stevens <[email protected]
|
I still think it is somehow related to android-maven-plugin. Here is a minimal working example: Parent pom.xml:
Library project pom:
Apk project, this is just the helloflashlight project taken from android-maven-plugin samples, only modifications are in the pom (added parent and the
When running "mvn install" on the parent pom (which in turn installs both modules) I and up with an apk which contains both the original and the shaded commons-codec. |
So as my example shows, when the apk and library project share a parent android-maven-plugin somehow becomes aware of the fact that the library originally did depend on commons-codec, even though the library jar and pom which are installed in the local repository do not. |
Its supposed to do that. But in your dependency declaration to the shaded jar you just add an exclusion to the original. Or you use provided scope in the project where you are shading it.. |
Why exactly is it supposed to do that? This means android-maven-plugin effectively "invents" a dependency which shouldn't be there (given that the library, as-installed to the repo, includes rather then depends on commons-codec) and which is not even listed when I run Also note that android-maven-plugin doesn't do this if the apk and library project do not share their parent. So at the very least the behaviour is inconsistent. |
The pom for the shaded jar declares a dependency to commons-codec... and as such it is a transitive dependency.. which needs to be pulled in. Just add the exclusion like I mentioned and it will work. |
The suggested exclusion does indeed work (thanks!), but I'm trying to convince you guys there is an actual bug (or at least an inconsistency) here. Perhaps you didn't read the entire thread.
So really, the behaviour is inconsistent: when the apk and library projects do not share a parent then the installed library pom is used (this is the "dependency-reduced" one, which does not depend on commons-codec, not even transitively, as per the shading), but when the projects do share a parent then original library pom is somehow found and used, causing android-maven-plugin to think the library still depends on commons-codec, resulting in the double inclusion. |
To clarify, this is the "depenency-reduced" library pom, as installed to the local repo:
As you can see it does not depend on commons-codec, due to the work of the shading plugin. |
By the way, while your first suggestion (adding an exclusion to the original to the dependency declaration to the shaded jar) works the second one (using provided scope in the project where the original is shaded) does not. In the second case the shade plugin failed to do its work and I get a jar which only contains META-INF. |
Hm ... I made a wrong assumption about the shade plugin working with provided scope. Sorry about that. In terms of the pom... if you have it in a multi module project the pom within the project is used and not what the shade plugin cooks up and pushes into the local repo. If you pull it apart into a separate project that publishes to your repo .. then it should work without exclusion.. |
Ok thanks for explaining. |
Problem is that we just use the dependency resolving from Maven and dont to much custom stuff. Also how would we know what is shaded and what not. Frankly I have no clear idea how this could be resolved without a lot of effort and considering that there is an easy solution I just dont see the need. |
I found out that using "runtime" scope on the commons-codec dependency in my library project does not prevent the shade plugin from doing its work (unlike with the "provided" scope), but (like the provided scope) also works as a way to prevent the inclusion of the original commons-codec in the final apk. So for other people face this problem, here is my final solution:
|
Isn't the correct solution to this to set createDependencyReducedPom=true On Fri, Oct 24, 2014 at 11:12 PM, Matthias Stevens <[email protected]
|
Sort of.. problem is that the dependency reduced pom is created as part of the build. And the pom creating that has the dependency in it and in a multi module build it participates in the reactor. We talked about this in the last Maven dev hangout and Igor mentioned that using the scope optional might work... worth a try @mstevens83 |
mosabua: you mean optional scope instead of provided (or runtime, as I did above?). |
The last pom.xml posted above turned out not to be the final solution after all.
What happsn here is basically: fetch the commons-codec sources, compile, package classes and source, shade both, unpack both, repack with bundle manifest. Quite a fun maven learning experience this was :-). |
Awesome hack... how about a pull request with this in an asciidoc formatted file in src/site/asciidoc as an example doc ;-) |
asciidoc formatted description of the hack discussed here: simpligility#487 (comment)
Because Android includes stale (or rather ancient) versions of a few popular open source libraries (e.g. Apache HttpClient & Apache Commons Codec) app developers may run into problems when they want to make use of more recent versions of these libraries (e.g. #479).
Thankfully there is a Maven plugin, called maven-shade-plugin, which makes dealing with this sort of situation easy (e.g. http://stackoverflow.com/a/16916552/1084488).
But sadly android-maven-plugin and maven-shade-plugin do not seem to be compatible.
By default the maven-shade-plugin attaches itself to the
package
phase, meaning it performs the "class relocation" at the wrong moment in the apk build cycle, namely after, instead of before, dexing. Consequently only the jar is affected, not the apk (meaning the app code will still try to reference the library with the clashing package name).I was therefore hoping it would be possible to make future versions of android-maven-plugin aware of maven-shade-plugin such that the shading can be triggered at the correct moment.
This possibility has been discussed before in 2011 (see https://code.google.com/p/maven-android-plugin/issues/detail?id=170) and a preliminary patch was produced, but as far as I've been able to find out the effort was abandoned.
In my opinion the most elegant solution would be to introduce some kind of
<executeShadePlugin>true</executeShadePlugin>
parameter in the<configuration>
which would make android-maven-plugin aware of maven-shade-plugin.Or, if the 2 plugins are inherently incompatible (which may be the case, see comment below) than perhaps it would be best if android-maven-plugin was extended with built-in support for this kind of "class relocation", without actually using the shade plugin as such.
The text was updated successfully, but these errors were encountered: