clojure-android / lein-droid

A Leiningen plugin for building Clojure/Android projects
Eclipse Public License 1.0
645 stars 56 forks source link

Improved manifest manipulation #95

Closed AdamClements closed 9 years ago

AdamClements commented 10 years ago

Much more flexible manifest system. Define a :manifest-template xml file which has placeholders in the clostache format, for example {{version-code}}, then specify an :android :manifest map with the appropriate substitutions. This can be used to insert debug permissions, version codes, change app names in different profiles, etc.

Bundled with this I have made the default map insert the {{version-name}} and {{version-code}} substitutions from the semantic leiningen version string. This will work if you stick to standard semantic versioning (which the new leiningen releases feature does).

This feature is back-compatible. :manifest-file remains as an option, and is the output of the template substitution, so I would recommend by default this is set to target/AndroidManifest.xml if you're using the new :manifest-template option.

There is a lot of other code which could be simplified in lein-droid using this approach without breaking back-compatibility I think, and even bigger improvements which could be made if this was the default way to do manifest manipulation. This has the nice property that it can be overridden in different profiles and arbitrarily extended without needing to hardcode every situation ahead of time.

I've also included the option to change the apk package namespace (different to the namespace which R references etc), this lets you install multiple versions of your app without them conflicting, which I need to have a release version installed at the same time as actively developing.

Here's a gist with a skeleton manifest and project.clj making use of the new features. Note that when this runs, the versionCode and versionName will be automatically set in the manifest map as per the "1.3.1-SNAPSHOT" set in the project.clj

AdamClements commented 10 years ago

Oh, the other advantage of this approach is that it doesn't modify the AndroidManifest.xml in place, with the current method of adding the internet permission, if the build is aborted part way through, it's quite possible to corrupt and blow away your AndroidManifest.xml

alexander-yakushev commented 10 years ago

This seems very useful. I need some time to give it a thorough look.

I noticed there is quite a bit of code related to semantic versions. Without delving much into it, couldn't org.sonatype/aether library contain something similar? I use class org.sonatype.aether.util.version.GenericVersionScheme to parse and compare semantic versions.

AdamClements commented 10 years ago

Nothing I can find in sonatype/aether, but I've just found https://github.com/technomancy/leiningen/blob/da00e756859c6d104d5de4786a578c2d9d3fa85f/src/leiningen/release.clj#L9 which it would make sense to use and adhere to. It doesn't allow for build numbers though... but I'm not sure we care that much, the version codes are only really important when you're uploading to the market and that should be a point release anyway.

AdamClements commented 10 years ago

I've pushed a new version using leiningen's version parsing. This doesn't incorporate a build number in the version code, but google play releases should have semantically incrementing version numbers anyway, so that's not really an issue.

alexander-yakushev commented 10 years ago

It will be also very helpful if you added an example to sample/ project, and possibly even in new project template instead of current usage of original AndroidManifest.

AdamClements commented 10 years ago

Acted on all the comments.

AdamClements commented 10 years ago

Oh, apart from the extra documentation, examples etc. Quite busy at work at the moment, trying to get this + a lot of other things done before I go on holiday next week. Will try and change the sample at some point today/this weekend.

alexander-yakushev commented 10 years ago

Will try and change the sample at some point today/this weekend.

This will be great, thank you.

alexander-yakushev commented 10 years ago

Looks good now. Could you now please squash the review commits with the original ones, and then force-push?

AdamClements commented 10 years ago

Done.

If it's alright with you, I might make the sample project changes separately, because there are other things I would like to propose for that - a basic project setup which plays nicely with profiles without any of the hideous unmerging that goes on currently, and replacing the metatasks doall and release with simple aliases, making the underlying build, apk, deploy more apparent if people want to only do the build, apk steps for example (it took me ages to work out that to just build the apk on my ci build machine and not deploy I could do lein with-profile android-release do droid build, droid apk).

alexander-yakushev commented 10 years ago

Yes, it's all right. I postponed the rework on profiles for now because I'm currently working on my GSoC project. But I remember about it and I will get to it after this summer.

it took me ages to work out that...

Strange, I thought I laid it out clearly in the Tutorial.

alexander-yakushev commented 10 years ago

Thank you! I pushed the commit as 71884d8. I will keep the PR/issue open as a reminder for myself to include the changes into sample at some point.

alexander-yakushev commented 10 years ago

With the new changes lein-droid isn't working anymore. I updated Leiningen to 2.4.2, and running lein droid doall yields this stacktrace: http://pastebin.com/zLLYuZjN. Any ideas?

alexander-yakushev commented 10 years ago

OK, sorry, it is Leiningen and not the new changes.

wiseman commented 9 years ago

Does it make sense to make minSdkVersion a parameter in the manifest template that takes its value from :target-version from project.clj? It took me a while to figure out that the reason I was getting INSTALL_FAILED_OLDER_SDK errors even though I had changed my project.clj was that the manifest template already had a hardcoded version from when I ran lein droid new.

alexander-yakushev commented 9 years ago

No, it doesn't. I overlooked that part, sorry. Fixed now.

wiseman commented 9 years ago

When I commented above, I actually was thinking that minSdkVersion should come at build-time from :target-version in project.clj, but since then I read some of your comments on other issues that talk about the distinction, so I think I understand the difference.

That said, maybe instead of hardcoding minSdkVersion it should be overrideable via something like lein droid new ... --min-sdk-version 17?

alexander-yakushev commented 9 years ago

It doesn't make much sense to put minSdkVersion in project.clj because lein-droid doesn't consume it in any way. 15 being default is perfectly fine, and at the point you need it higher you should have edited AndroidManifest couple of times already. Specifying it from the command line is possible, but again I don't see how it is better than changing it once in the manifest.

alexander-yakushev commented 9 years ago

Also good thing you reminded me to close this.