Problem
The Android builder.py script in the 2.1 SDK fails when it calls the zipalign tool in the Android SDK, with the error "Unable to open
as zip archive."
From the customer:
The error seems to be caused by a change to builder.py in 2.1. When it calls out to the Android jarsigner tool, the 2.1 script uses two additional parameters, "-sigalg MD5withRSA" and "-digestalg SHA1". The 2.0.X builder.py script does not have these two extra arguments. The script calls zipalign right after that, which fails. When the two arguments from the 2.1 builder.py are removed it runs successfully, and if those are added to the 2.0 builder.py, it fails with the same error.
A regression caused by https://github.com/appcelerator/titanium_mobile/commit/618602ab92306727105efa304d58bde1b73138d9 with regard to TIMOB-8800
Desktop OS? Version of Android SDK? Java version?
And the complete build log
Unable to duplicate by building in studio. Manually invoking the build command line in a manner where: * Project name does not match directory name * AVD ID (arg 10) is left out Does not even run. The build command in the log does not work without the AVD ID, although this argument is not strictly necessary. The fix for this issue will deprecate the AVD ID, but this issue is NOT reproducible.
We need the following information as part of the bug report: * Output of
ls -lah /Users/chris/Development/titanium/MB-Next-Gen-Phone/build/Android/com.mfoundry.mbanking.nextgen.phone.apk
AFTER the build fails * Output ofls -lah /Users/chris/Development/titanium/MB-Next-Gen-Phone/build/android/bin/app-unsigned.apk
AFTER the build fails * Output ofls -lah /Users/chris/Development/titanium/MB-Next-Gen-Phone/build
AFTER the build fails * Output ofls -lah /Users/chris/Development/titanium/MB-Next-Gen-Phone/build/android
AFTER the build fails * Output ofumask
This will indicate if there is a permissions issue.One more question: * After the build fails, does running the command
And then attempting a rebuild (WITHOUT any kind of clean) fix this issue? Note that this may actually be a python bug in the version that ships with 10.6.8: Python 2.6.1 apparently has numerous permissions issues which we may not be able to easily resolve. The recommended action is to upgrade to 10.7 Lion (or bump the python version to 2.7.x - please install [homebrew](http://mxcl.github.com/homebrew/) and then
brew install python
) where this build script does NOT fail.Fixed the AVD issue but nobody can reproduce the dexing problem. That will not be resolved and is likely a local configuration issue for the reporter.
Cannot reproduce; however PR [2435](https://github.com/appcelerator/titanium_mobile/pull/2435) was submitted to solve the AVD requirement problem.
For reference, http://developer.android.com/tools/publishing/app-signing.html
Complete build log: https://gist.github.com/e316d1fc28302b9eb863
After looking at this some more, I think the error is specifically caused by the -sigalg parameter when calling jarsigner. MD5withRSA is not compatible with the keystore we are using because it contains a SHA1withDSA key. jarsigner can use two signature algorithms, MD5withRSA and SHA1withDSA. The signature algorithm has to match the private key in the keystore. If the -sigalg parameter is omitted, jarsigner will automatically detect which algorithm to use by looking at the private key. source: http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/jarsigner.html If I run jarsigner manually after the build fails, I can see this error: "jarsigner error: java.security.SignatureException: private key algorithm is not compatible with signature algorithm". I didn't see this message before because builder.py suppresses it. I tried building with builder.py again, but using the keystore that Titanium Studio uses to sign builds (the one with alias "tidev" and password "tirocks"). That was successful because that keystore has an MD5withRSA key. If I edit builder.py and change "MD5withRSA" to "SHA1withDSA", it succeeds with mFoundry's keystore and fails with the Titanium Studio keystore. I think the fix for this issue is just to omit the -sigalg parameter when calling jarsigner. jarsigner can detect which algorithm it should use.
Chris - Thank you for looking into this. I'll make sure a patch is submitted today.
I tested again with the CI build 2.2.0.v20120710234110 and still get the jarsigner error. Looking at builder.py, it appears this fix has not been applied yet: https://github.com/appcelerator/titanium_mobile/blob/master/support/android/builder.py
This was fixed, but for some reason the fix was never committed.
We can't really do the suggested fix, as it will break builder.py when JDK 7 instead of 6 is being used. We really need to support JDK 7 (in addition to 6) going forward. In JDK 7, the default became DSA. Our tidev alias, which is used for everything except when you build with your own certificate for packaging for a store, uses RSA. Many of you out there probably have RSA, since it was the default prior to JDK 7. If you build an app using the proposed changes, and your key is using RSA like ours is, and you're using JDK *7*, then the resulting APK will not be able to be installed on emulator/device.
adb install
will say INSTALL_PARSE_FAILED_NO_CERTIFICATES. It's my inclination to "force" you to use RSA, but I'm open to suggestions (comments here in this ticket.) Here are my arguments in favor of forcing you to use RSA: a) Android's [Signing your Applications](http://developer.android.com/tools/publishing/app-signing.html) document explicitly says "Use the value MD5withRSA" in the "3. Sign your application with your private key" section. b) They also explicitly say, "Caution: As of JDK 7, the default signing algorithim has changed, *requiring you to specify the signature and digest algorithims* (-sigalg and -digestalg) when you sign an APK." Of course, it wouldn't be required if you were using DSA, since that's the JDK 7 default. The fact that they say it's required means they're assuming you want to use RSA. The point here is that, thanks to this switch from JDK6 to JDK7, we really do need to specify those arguments. And we want to specify them as RSA. c) (Countering myself here.) Unfortunately they muddy the waters a bit in that document by stating "Both DSA and RSA are supported" for the-keyalg
argument forkeytool
. However that is the only mention of DSA in the whole document, whereas RSA receives more attention. d) The only alternative would be yet another setting somewhere in your Titanium project, and yet another argument passed to builder.py to specify RSA or DSA. We sure would like to avoid that.Went ahead and got JDK 7u5 for OS X to test with. I'm not sure if it can cohabitate with the existing JDK 6 install or not, so there may need to be some more extensive testing here.
It can cohabitate with JDK 6. I have them both and I can switch between them using the Applications -> Utilities -> Java Preferences application. (We already had a ticket for Java 7 support, which is where these two arguments (-sigalg and -digestalg), and I tested extensively on all three desktop platforms.) So I have a new and happier idea to solve this ticket. The verbose output option for
keytool -list
will show the signature algorithm name (DSA v RSA). Since builder.py is given the password for the store, we can actually call out to keytool and get that info. Example from the command line:Note the last line there. If we parse that we can then pass the result to the -sigalg argument to jarsigner. My change of heart comes from learning that you can successfully sign and use Android applications using DSA signatures using Android's eclipse and command-line tools, so we should support it too. :) @Stephen, do you want to do this? Or you can reassign to me, whichever you prefer. If I were doing it I'd try to use
run.run
(our little wrapper function for Python Popen) because I think it can pass back stdout to the caller. Else I would just use Popen stuff directly in case our wrapper doesn't pass stdout back.Thanks Bill, glad to hear that you have a fix in progress. This is an important issue for mFoundry; we cannot switch to another key, so we would need either this fix or another parameter to builder.py to specify the signing algorithm.
@Bill I can take this. It'll be something for me to finish this afternoon and I need more experience working with the Java toolchain anyway.
Merged to master (2.2.0). 2.1.1 coming up shortly.